diff options
Diffstat (limited to 'modules')
495 files changed, 10709 insertions, 6423 deletions
diff --git a/modules/SCsub b/modules/SCsub index 64da3bd0be..5ff4623743 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -10,6 +10,7 @@ env_modules = env.Clone() Export("env_modules") # Header with MODULE_*_ENABLED defines. +env.Depends("modules_enabled.gen.h", Value(env.module_list)) env.CommandNoCache( "modules_enabled.gen.h", Value(env.module_list), @@ -23,6 +24,7 @@ env.CommandNoCache( # Header to be included in `tests/test_main.cpp` to run module-specific tests. if env["tests"]: + env.Depends("modules_tests.gen.h", Value(env.module_list)) env.CommandNoCache( "modules_tests.gen.h", Value(env.module_list), diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub index 351628a0e3..1f9fde966d 100644 --- a/modules/basis_universal/SCsub +++ b/modules/basis_universal/SCsub @@ -11,40 +11,45 @@ thirdparty_obj = [] # Not unbundled so far since not widespread as shared library thirdparty_dir = "#thirdparty/basis_universal/" -tool_sources = [ +# Sync list with upstream CMakeLists.txt +encoder_sources = [ + "apg_bmp.c", "basisu_astc_decomp.cpp", "basisu_backend.cpp", "basisu_basis_file.cpp", + "basisu_bc7enc.cpp", "basisu_comp.cpp", "basisu_enc.cpp", "basisu_etc.cpp", "basisu_frontend.cpp", "basisu_global_selector_palette_helpers.cpp", "basisu_gpu_texture.cpp", + "basisu_kernels_sse.cpp", "basisu_pvrtc1_4.cpp", - "basisu_resample_filters.cpp", "basisu_resampler.cpp", + "basisu_resample_filters.cpp", "basisu_ssim.cpp", + "basisu_uastc_enc.cpp", + "jpgd.cpp", "lodepng.cpp", ] -tool_sources = [thirdparty_dir + file for file in tool_sources] +encoder_sources = [thirdparty_dir + "encoder/" + file for file in encoder_sources] transcoder_sources = [thirdparty_dir + "transcoder/basisu_transcoder.cpp"] # Treat Basis headers as system headers to avoid raising warnings. Not supported on MSVC. if not env.msvc: - env_basisu.Append( - CPPFLAGS=["-isystem", Dir(thirdparty_dir).path, "-isystem", Dir(thirdparty_dir + "transcoder").path] - ) + env_basisu.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path]) else: - env_basisu.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "transcoder"]) + env_basisu.Prepend(CPPPATH=[thirdparty_dir]) if env["target"] == "debug": - env_basisu.Append(CPPFLAGS=["-DBASISU_DEVEL_MESSAGES=1", "-DBASISD_ENABLE_DEBUG_FLAGS=1"]) + env_basisu.Append(CPPDEFINES=[("BASISU_DEVEL_MESSAGES", 1), ("BASISD_ENABLE_DEBUG_FLAGS", 1)]) env_thirdparty = env_basisu.Clone() env_thirdparty.disable_warnings() if env["tools"]: - env_thirdparty.add_source_files(thirdparty_obj, tool_sources) + env_thirdparty.Append(CPPDEFINES=["BASISU_NO_IMG_LOADERS"]) + env_thirdparty.add_source_files(thirdparty_obj, encoder_sources) env_thirdparty.add_source_files(thirdparty_obj, transcoder_sources) env.modules_sources += thirdparty_obj diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index cf5581265b..9a13406900 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -35,7 +35,7 @@ #include "texture_basisu.h" #ifdef TOOLS_ENABLED -#include <basisu_comp.h> +#include <encoder/basisu_comp.h> #endif #include <transcoder/basisu_transcoder.h> @@ -233,7 +233,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { basist::basisu_image_info info; tr.get_image_info(ptr, size, info, 0); - int block_size = basist::basis_get_bytes_per_block(format); + int block_size = basist::basis_get_bytes_per_block_or_pixel(format); Vector<uint8_t> gpudata; gpudata.resize(info.m_total_blocks * block_size); @@ -260,7 +260,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { }; }; - image.instance(); + image.instantiate(); image->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); return image; @@ -272,7 +272,7 @@ void register_basis_universal_types() { Image::basis_universal_packer = basis_universal_packer; #endif Image::basis_universal_unpacker = basis_universal_unpacker; - //ClassDB::register_class<TextureBasisU>(); + //GDREGISTER_CLASS(TextureBasisU); } void unregister_basis_universal_types() { diff --git a/modules/basis_universal/texture_basisu.cpp b/modules/basis_universal/texture_basisu.cpp index 92882a1cc8..9e917420ce 100644 --- a/modules/basis_universal/texture_basisu.cpp +++ b/modules/basis_universal/texture_basisu.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" #ifdef TOOLS_ENABLED -#include <basisu_comp.h> +#include <encoder/basisu_comp.h> #endif #include <transcoder/basisu_transcoder.h> @@ -130,7 +130,7 @@ void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) { }; Ref<Image> img; - img.instance(); + img.instantiate(); img->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); RenderingServer::get_singleton()->texture_allocate(texture, tex_size.x, tex_size.y, 0, img->get_format(), RS::TEXTURE_TYPE_2D, flags); diff --git a/modules/basis_universal/texture_basisu.h b/modules/basis_universal/texture_basisu.h index 282a0dfc8a..3316035404 100644 --- a/modules/basis_universal/texture_basisu.h +++ b/modules/basis_universal/texture_basisu.h @@ -34,7 +34,7 @@ #include "scene/resources/texture.h" #ifdef TOOLS_ENABLED -#include <basisu_comp.h> +#include <encoder/basisu_comp.h> #endif #include <transcoder/basisu_transcoder.h> diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index c7fdf56af4..171895ed24 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -130,23 +130,19 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, line_ptr += 1; } break; case 24: { - uint32_t color = *((uint32_t *)line_ptr); - - write_buffer[index + 2] = color & 0xff; - write_buffer[index + 1] = (color >> 8) & 0xff; - write_buffer[index + 0] = (color >> 16) & 0xff; + write_buffer[index + 2] = line_ptr[0]; + write_buffer[index + 1] = line_ptr[1]; + write_buffer[index + 0] = line_ptr[2]; write_buffer[index + 3] = 0xff; index += 4; line_ptr += 3; } break; case 32: { - uint32_t color = *((uint32_t *)line_ptr); - - write_buffer[index + 2] = color & 0xff; - write_buffer[index + 1] = (color >> 8) & 0xff; - write_buffer[index + 0] = (color >> 16) & 0xff; - write_buffer[index + 3] = color >> 24; + write_buffer[index + 2] = line_ptr[0]; + write_buffer[index + 1] = line_ptr[1]; + write_buffer[index + 0] = line_ptr[2]; + write_buffer[index + 3] = line_ptr[3]; index += 4; line_ptr += 4; @@ -172,11 +168,9 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, const uint8_t *cb = p_color_buffer; for (unsigned int i = 0; i < color_table_size; ++i) { - uint32_t color = *((uint32_t *)cb); - - pal[i * 4 + 0] = (color >> 16) & 0xff; - pal[i * 4 + 1] = (color >> 8) & 0xff; - pal[i * 4 + 2] = (color)&0xff; + pal[i * 4 + 0] = cb[2]; + pal[i * 4 + 1] = cb[1]; + pal[i * 4 + 2] = cb[0]; pal[i * 4 + 3] = 0xff; cb += 4; @@ -211,7 +205,7 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, // A valid bmp file should always at least have a // file header and a minimal info header - if (f->get_len() > BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_MIN_SIZE) { + if (f->get_length() > BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_MIN_SIZE) { // File Header bmp_header.bmp_file_header.bmp_signature = f->get_16(); if (bmp_header.bmp_file_header.bmp_signature == BITMAP_SIGNATURE) { @@ -304,7 +298,7 @@ static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) { Error open_memfile_error = memfile.open_custom(p_bmp, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer."); Ref<Image> img; - img.instance(); + img.instantiate(); Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image."); return img; diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 93642f2d5c..e07be14c5b 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -268,7 +268,7 @@ PhysicsServer3D::AreaSpaceOverrideMode BulletPhysicsServer3D::area_get_space_ove return area->get_spOv_mode(); } -void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) { +void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) { AreaBullet *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -288,7 +288,7 @@ void BulletPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_sh area->set_shape(p_shape_idx, shape); } -void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) { +void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) { AreaBullet *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -309,9 +309,9 @@ RID BulletPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const { return area->get_shape(p_shape_idx)->get_self(); } -Transform BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const { +Transform3D BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const { AreaBullet *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform()); + ERR_FAIL_COND_V(!area, Transform3D()); return area->get_shape_transform(p_shape_idx); } @@ -382,15 +382,15 @@ Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param) } } -void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform &p_transform) { +void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform3D &p_transform) { AreaBullet *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); area->set_transform(p_transform); } -Transform BulletPhysicsServer3D::area_get_transform(RID p_area) const { +Transform3D BulletPhysicsServer3D::area_get_transform(RID p_area) const { AreaBullet *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform()); + ERR_FAIL_COND_V(!area, Transform3D()); return area->get_transform(); } @@ -484,7 +484,7 @@ PhysicsServer3D::BodyMode BulletPhysicsServer3D::body_get_mode(RID p_body) const return body->get_mode(); } -void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) { +void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -504,7 +504,7 @@ void BulletPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_sh body->set_shape(p_shape_idx, shape); } -void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) { +void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -527,9 +527,9 @@ RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const { return shape->get_self(); } -Transform BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const { +Transform3D BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Transform()); + ERR_FAIL_COND_V(!body, Transform3D()); return body->get_shape_transform(p_shape_idx); } @@ -824,10 +824,10 @@ bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const return body->get_omit_forces_integration(); } -void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { +void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND(!body); - body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata); + body->set_force_integration_callback(p_callable, p_udata); } void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) { @@ -842,7 +842,7 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod return BulletPhysicsDirectBodyState3D::get_singleton(body); } -bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -850,7 +850,7 @@ bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform &p_from return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); } -int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { +int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, 0); ERR_FAIL_COND_V(!body->get_space(), 0); @@ -990,7 +990,7 @@ Variant BulletPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state return Variant(); } -void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform &p_transform) { +void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform3D &p_transform) { SoftBodyBullet *body = soft_body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -1205,7 +1205,7 @@ Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const { return pin_joint->getPivotInB(); } -RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) { +RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); @@ -1277,7 +1277,7 @@ bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_f return hinge_joint->get_flag(p_flag); } -RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); @@ -1313,7 +1313,7 @@ real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointPar return slider_joint->get_param(p_param); } -RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); @@ -1347,7 +1347,7 @@ real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJ return coneTwist_joint->get_param(p_param); } -RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 856ff74963..d34d619ba2 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -134,12 +134,12 @@ public: virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) override; virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const override; - virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override; + virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override; virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) override; - virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) override; + virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) override; virtual int area_get_shape_count(RID p_area) const override; virtual RID area_get_shape(RID p_area, int p_shape_idx) const override; - virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const override; + virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const override; virtual void area_remove_shape(RID p_area, int p_shape_idx) override; virtual void area_clear_shapes(RID p_area) override; virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) override; @@ -153,8 +153,8 @@ public: virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) override; virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override; - virtual void area_set_transform(RID p_area, const Transform &p_transform) override; - virtual Transform area_get_transform(RID p_area) const override; + virtual void area_set_transform(RID p_area, const Transform3D &p_transform) override; + virtual Transform3D area_get_transform(RID p_area) const override; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override; virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override; @@ -166,7 +166,7 @@ public: /* RIGID BODY API */ - virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) override; + virtual RID body_create(BodyMode p_mode = BODY_MODE_DYNAMIC, bool p_init_sleeping = false) override; virtual void body_set_space(RID p_body, RID p_space) override; virtual RID body_get_space(RID p_body) const override; @@ -174,14 +174,14 @@ public: virtual void body_set_mode(RID p_body, BodyMode p_mode) override; virtual BodyMode body_get_mode(RID p_body) const override; - virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override; + virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override; // Not supported, Please remove and add new shape virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override; - virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) override; + virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) override; virtual int body_get_shape_count(RID p_body) const override; virtual RID body_get_shape(RID p_body, int p_shape_idx) const override; - virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const override; + virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const override; virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override; @@ -246,15 +246,15 @@ public: virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override; virtual bool body_is_omitting_force_integration(RID p_body) const override; - virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override; + virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override; virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; + virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; /* SOFT BODY API */ @@ -283,7 +283,7 @@ public: virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override; /// Special function. This function has bad performance - virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override; + virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override; @@ -333,7 +333,7 @@ public: virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override; virtual Vector3 pin_joint_get_local_b(RID p_joint) const override; - virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) override; + virtual RID joint_create_hinge(RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) override; virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override; virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override; @@ -343,19 +343,19 @@ public: virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override; /// Reference frame is A - virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; + virtual RID joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override; virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override; /// Reference frame is A - virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; + virtual RID joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override; virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override; /// Reference frame is A - virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; + virtual RID joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) override; virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override; diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp index 19d4816372..01461767bd 100644 --- a/modules/bullet/bullet_types_converter.cpp +++ b/modules/bullet/bullet_types_converter.cpp @@ -59,7 +59,7 @@ void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) { INVERT_B_TO_G(inVal[2], outVal[2]); } -void B_TO_G(btTransform const &inVal, Transform &outVal) { +void B_TO_G(btTransform const &inVal, Transform3D &outVal) { B_TO_G(inVal.getBasis(), outVal.basis); B_TO_G(inVal.getOrigin(), outVal.origin); } @@ -89,7 +89,7 @@ void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) { INVERT_G_TO_B(inVal[2], outVal[2]); } -void G_TO_B(Transform const &inVal, btTransform &outVal) { +void G_TO_B(Transform3D const &inVal, btTransform &outVal) { G_TO_B(inVal.basis, outVal.getBasis()); G_TO_B(inVal.origin, outVal.getOrigin()); } diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h index ca9b7175dd..e184fe1769 100644 --- a/modules/bullet/bullet_types_converter.h +++ b/modules/bullet/bullet_types_converter.h @@ -32,7 +32,7 @@ #define BULLET_TYPES_CONVERTER_H #include "core/math/basis.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/typedefs.h" @@ -49,14 +49,14 @@ extern void B_TO_G(btVector3 const &inVal, Vector3 &outVal); extern void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal); extern void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal); extern void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal); -extern void B_TO_G(btTransform const &inVal, Transform &outVal); +extern void B_TO_G(btTransform const &inVal, Transform3D &outVal); // Godot TO Bullet extern void G_TO_B(Vector3 const &inVal, btVector3 &outVal); extern void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal); extern void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); extern void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); -extern void G_TO_B(Transform const &inVal, btTransform &outVal); +extern void G_TO_B(Transform3D const &inVal, btTransform &outVal); extern void UNSCALE_BT_BASIS(btTransform &scaledBasis); #endif diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index d9f5beb5a1..c45bd5bbc0 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -49,7 +49,7 @@ CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} -void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) { +void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform3D &p_transform) { G_TO_B(p_transform.get_basis().get_scale_abs(), scale); G_TO_B(p_transform, transform); UNSCALE_BT_BASIS(transform); @@ -193,7 +193,7 @@ int CollisionObjectBullet::get_godot_object_flags() const { return bt_collision_object->getUserIndex2(); } -void CollisionObjectBullet::set_transform(const Transform &p_global_transform) { +void CollisionObjectBullet::set_transform(const Transform3D &p_global_transform) { set_body_scale(p_global_transform.basis.get_scale_abs()); btTransform bt_transform; @@ -203,8 +203,8 @@ void CollisionObjectBullet::set_transform(const Transform &p_global_transform) { set_transform__bullet(bt_transform); } -Transform CollisionObjectBullet::get_transform() const { - Transform t; +Transform3D CollisionObjectBullet::get_transform() const { + Transform3D t; B_TO_G(get_transform__bullet(), t); t.basis.scale(body_scale); return t; @@ -230,7 +230,7 @@ RigidCollisionObjectBullet::~RigidCollisionObjectBullet() { } } -void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform, bool p_disabled) { +void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_disabled) { shapes.push_back(ShapeWrapper(p_shape, p_transform, !p_disabled)); p_shape->add_owner(this); reload_shapes(); @@ -296,7 +296,7 @@ void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBod } } -void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { +void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform3D &p_transform) { ERR_FAIL_INDEX(p_index, get_shape_count()); shapes.write[p_index].set_transform(p_transform); @@ -307,8 +307,8 @@ const btTransform &RigidCollisionObjectBullet::get_bt_shape_transform(int p_inde return shapes[p_index].transform; } -Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const { - Transform trs; +Transform3D RigidCollisionObjectBullet::get_shape_transform(int p_index) const { + Transform3D trs; B_TO_G(shapes[p_index].transform, trs); return trs; } diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index c8081a53f1..944ab89b87 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -31,7 +31,7 @@ #ifndef COLLISION_OBJECT_BULLET_H #define COLLISION_OBJECT_BULLET_H -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/object/class_db.h" #include "core/templates/vset.h" @@ -83,7 +83,7 @@ public: set_transform(p_transform); } - ShapeWrapper(ShapeBullet *p_shape, const Transform &p_transform, bool p_active) : + ShapeWrapper(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_active) : shape(p_shape), active(p_active) { set_transform(p_transform); @@ -102,7 +102,7 @@ public: active = otherShape.active; } - void set_transform(const Transform &p_transform); + void set_transform(const Transform3D &p_transform); void set_transform(const btTransform &p_transform); btTransform get_adjusted_transform() const; @@ -202,8 +202,8 @@ public: void set_godot_object_flags(int flags); int get_godot_object_flags() const; - void set_transform(const Transform &p_global_transform); - Transform get_transform() const; + void set_transform(const Transform3D &p_global_transform); + Transform3D get_transform() const; virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; @@ -225,7 +225,7 @@ public: _FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; } - void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false); + void add_shape(ShapeBullet *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false); void set_shape(int p_index, ShapeBullet *p_shape); int get_shape_count() const; @@ -238,10 +238,10 @@ public: void remove_shape_full(int p_index); void remove_all_shapes(bool p_permanentlyFromThisBody = false, bool p_force_not_reload = false); - void set_shape_transform(int p_index, const Transform &p_transform); + void set_shape_transform(int p_index, const Transform3D &p_transform); const btTransform &get_bt_shape_transform(int p_index) const; - Transform get_shape_transform(int p_index) const; + Transform3D get_shape_transform(int p_index) const; void set_shape_disabled(int p_index, bool p_disabled); bool is_shape_disabled(int p_index); diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp index e785780c5b..34516d8b3b 100644 --- a/modules/bullet/cone_twist_joint_bullet.cpp +++ b/modules/bullet/cone_twist_joint_bullet.cpp @@ -40,16 +40,16 @@ @author AndreaCatania */ -ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame) : +ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : JointBullet() { - Transform scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); btTransform btFrameA; G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); btTransform btFrameB; diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h index 7d6bafd292..7e51f7d644 100644 --- a/modules/bullet/cone_twist_joint_bullet.h +++ b/modules/bullet/cone_twist_joint_bullet.h @@ -43,7 +43,7 @@ class ConeTwistJointBullet : public JointBullet { class btConeTwistConstraint *coneConstraint; public: - ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame); + ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; } diff --git a/modules/bullet/config.py b/modules/bullet/config.py index be7cf74f6f..83605f1f9b 100644 --- a/modules/bullet/config.py +++ b/modules/bullet/config.py @@ -1,6 +1,7 @@ def can_build(env, platform): # API Changed and bullet is disabled at the moment return False + # Later change to return not env["disable_3d"] def configure(env): diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp index 43ad6c56d5..7e04d57b9d 100644 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -40,7 +40,7 @@ @author AndreaCatania */ -Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) : +Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : JointBullet() { for (int i = 0; i < 3; i++) { for (int j = 0; j < PhysicsServer3D::G6DOF_JOINT_FLAG_MAX; j++) { @@ -48,7 +48,7 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu } } - Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); @@ -56,7 +56,7 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); @@ -71,30 +71,30 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu setup(sixDOFConstraint); } -Transform Generic6DOFJointBullet::getFrameOffsetA() const { +Transform3D Generic6DOFJointBullet::getFrameOffsetA() const { btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } -Transform Generic6DOFJointBullet::getFrameOffsetB() const { +Transform3D Generic6DOFJointBullet::getFrameOffsetB() const { btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } -Transform Generic6DOFJointBullet::getFrameOffsetA() { +Transform3D Generic6DOFJointBullet::getFrameOffsetA() { btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } -Transform Generic6DOFJointBullet::getFrameOffsetB() { +Transform3D Generic6DOFJointBullet::getFrameOffsetB() { btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h index 62b8e85a81..00567e3085 100644 --- a/modules/bullet/generic_6dof_joint_bullet.h +++ b/modules/bullet/generic_6dof_joint_bullet.h @@ -48,14 +48,14 @@ class Generic6DOFJointBullet : public JointBullet { bool flags[3][PhysicsServer3D::G6DOF_JOINT_FLAG_MAX]; public: - Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB); + Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; } - Transform getFrameOffsetA() const; - Transform getFrameOffsetB() const; - Transform getFrameOffsetA(); - Transform getFrameOffsetB(); + Transform3D getFrameOffsetA() const; + Transform3D getFrameOffsetB() const; + Transform3D getFrameOffsetA(); + Transform3D getFrameOffsetB(); void set_linear_lower_limit(const Vector3 &linearLower); void set_linear_upper_limit(const Vector3 &linearUpper); diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp index 4ceb98729f..b5fe50cf5f 100644 --- a/modules/bullet/hinge_joint_bullet.cpp +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -40,16 +40,16 @@ @author AndreaCatania */ -HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB) : +HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB) : JointBullet() { - Transform scaled_AFrame(frameA.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(frameA.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); btTransform btFrameA; G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(frameB.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(frameB.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); btTransform btFrameB; diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h index 06a95be374..dd0f69ba68 100644 --- a/modules/bullet/hinge_joint_bullet.h +++ b/modules/bullet/hinge_joint_bullet.h @@ -41,7 +41,7 @@ class HingeJointBullet : public JointBullet { class btHingeConstraint *hingeConstraint; public: - HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB); + HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB); HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; } diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 433bff8c38..ce39d4f0df 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -106,11 +106,11 @@ Vector3 BulletPhysicsDirectBodyState3D::get_angular_velocity() const { return body->get_angular_velocity(); } -void BulletPhysicsDirectBodyState3D::set_transform(const Transform &p_transform) { +void BulletPhysicsDirectBodyState3D::set_transform(const Transform3D &p_transform) { body->set_transform(p_transform); } -Transform BulletPhysicsDirectBodyState3D::get_transform() const { +Transform3D BulletPhysicsDirectBodyState3D::get_transform() const { return body->get_transform(); } @@ -268,7 +268,7 @@ RigidBodyBullet::RigidBodyBullet() : reload_shapes(); setupBulletCollisionObject(btBody); - set_mode(PhysicsServer3D::BODY_MODE_RIGID); + set_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); reload_axis_lock(); areasWhereIam.resize(maxAreasWhereIam); @@ -346,16 +346,17 @@ void RigidBodyBullet::dispatch_callbacks() { Variant variantBodyDirect = bodyDirect; - Object *obj = ObjectDB::get_instance(force_integration_callback->id); + Object *obj = force_integration_callback->callable.get_object(); if (!obj) { // Remove integration callback - set_force_integration_callback(ObjectID(), StringName()); + set_force_integration_callback(Callable()); } else { const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata }; Callable::CallError responseCallError; int argc = (force_integration_callback->udata.get_type() == Variant::NIL) ? 1 : 2; - obj->call(force_integration_callback->method, vp, argc, responseCallError); + Variant rv; + force_integration_callback->callable.call(vp, argc, rv, responseCallError); } } @@ -371,16 +372,15 @@ void RigidBodyBullet::dispatch_callbacks() { previousActiveState = btBody->isActive(); } -void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) { +void RigidBodyBullet::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { if (force_integration_callback) { memdelete(force_integration_callback); force_integration_callback = nullptr; } - if (p_id.is_valid()) { + if (p_callable.get_object()) { force_integration_callback = memnew(ForceIntegrationCallback); - force_integration_callback->id = p_id; - force_integration_callback->method = p_method; + force_integration_callback->callable = p_callable; force_integration_callback->udata = p_udata; } } @@ -531,14 +531,14 @@ void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) { reload_axis_lock(); _internal_set_mass(0); break; - case PhysicsServer3D::BODY_MODE_RIGID: - mode = PhysicsServer3D::BODY_MODE_RIGID; + case PhysicsServer3D::BODY_MODE_DYNAMIC: + mode = PhysicsServer3D::BODY_MODE_DYNAMIC; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - case PhysicsServer3D::BODY_MODE_CHARACTER: - mode = PhysicsServer3D::BODY_MODE_CHARACTER; + case PhysicsServer3D::MODE_DYNAMIC_LOCKED: + mode = PhysicsServer3D::MODE_DYNAMIC_LOCKED; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); @@ -711,7 +711,7 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { void RigidBodyBullet::reload_axis_lock() { btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)))); - if (PhysicsServer3D::BODY_MODE_CHARACTER == mode) { + if (PhysicsServer3D::MODE_DYNAMIC_LOCKED == mode) { /// When character angular is always locked btBody->setAngularFactor(btVector3(0., 0., 0.)); } else { @@ -1006,7 +1006,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { // Rigidbody is dynamic if and only if mass is non Zero, otherwise static const bool isDynamic = p_mass != 0.f; if (isDynamic) { - if (PhysicsServer3D::BODY_MODE_RIGID != mode && PhysicsServer3D::BODY_MODE_CHARACTER != mode) { + if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LOCKED != mode) { return; } @@ -1015,7 +1015,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { mainShape->calculateLocalInertia(p_mass, localInertia); } - if (PhysicsServer3D::BODY_MODE_RIGID == mode) { + if (PhysicsServer3D::BODY_MODE_DYNAMIC == mode) { btBody->setCollisionFlags(clearedCurrentFlags); // Just set the flags without Kin and Static } else { btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_CHARACTER_OBJECT); diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index a4be7f9e07..606df7134b 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -107,8 +107,8 @@ public: virtual void set_angular_velocity(const Vector3 &p_velocity) override; virtual Vector3 get_angular_velocity() const override; - virtual void set_transform(const Transform &p_transform) override; - virtual Transform get_transform() const override; + virtual void set_transform(const Transform3D &p_transform) override; + virtual Transform3D get_transform() const override; virtual void add_central_force(const Vector3 &p_force) override; virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override; @@ -154,8 +154,7 @@ public: }; struct ForceIntegrationCallback { - ObjectID id; - StringName method; + Callable callable; Variant udata; }; @@ -240,7 +239,7 @@ public: virtual void set_space(SpaceBullet *p_space); virtual void dispatch_callbacks(); - void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); + void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant()); void scratch_space_override_modificator(); virtual void on_collision_filters_change(); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 471b154813..40e785d699 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -142,7 +142,7 @@ btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMes } } -btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { +btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { const btScalar ignoredHeightScale(1); const int YAxis = 1; // 0=X, 1=Y, 2=Z const bool flipQuadEdges = false; @@ -480,17 +480,10 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { ERR_FAIL_COND_MSG(l_width < 2, "Map width must be at least 2."); ERR_FAIL_COND_MSG(l_depth < 2, "Map depth must be at least 2."); - // TODO This code will need adjustments if real_t is set to `double`, - // because that precision is unnecessary for a heightmap and Bullet doesn't support it... - - Vector<real_t> l_heights; + Vector<float> l_heights; Variant l_heights_v = d["heights"]; -#ifdef REAL_T_IS_DOUBLE - if (l_heights_v.get_type() == Variant::PACKED_FLOAT64_ARRAY) { -#else if (l_heights_v.get_type() == Variant::PACKED_FLOAT32_ARRAY) { -#endif // Ready-to-use heights can be passed l_heights = l_heights_v; @@ -511,9 +504,9 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { l_heights.resize(l_image->get_width() * l_image->get_height()); - real_t *w = l_heights.ptrw(); + float *w = l_heights.ptrw(); const uint8_t *r = im_data.ptr(); - real_t *rp = (real_t *)r; + float *rp = (float *)r; // At this point, `rp` could be used directly for Bullet, but I don't know how safe it would be. for (int i = 0; i < l_heights.size(); ++i) { @@ -521,11 +514,7 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { } } else { -#ifdef REAL_T_IS_DOUBLE - ERR_FAIL_MSG("Expected PackedFloat64Array or float Image."); -#else ERR_FAIL_MSG("Expected PackedFloat32Array or float Image."); -#endif } ERR_FAIL_COND(l_width <= 0); @@ -534,11 +523,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { // Compute min and max heights if not specified. if (!d.has("min_height") && !d.has("max_height")) { - const real_t *r = l_heights.ptr(); + const float *r = l_heights.ptr(); int heights_size = l_heights.size(); for (int i = 0; i < heights_size; ++i) { - real_t h = r[i]; + float h = r[i]; if (h < l_min_height) { l_min_height = h; @@ -559,7 +548,7 @@ PhysicsServer3D::ShapeType HeightMapShapeBullet::get_type() const { return PhysicsServer3D::SHAPE_HEIGHTMAP; } -void HeightMapShapeBullet::setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { +void HeightMapShapeBullet::setup(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { // TODO cell size must be tweaked using localScaling, which is a shared property for all Bullet shapes // If this array is resized outside of here, it should be preserved due to CoW diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index bfd95747eb..5080d13d99 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -89,7 +89,7 @@ public: /// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface(); static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); - static class btHeightfieldTerrainShape *create_shape_height_field(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); + static class btHeightfieldTerrainShape *create_shape_height_field(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope); }; @@ -212,7 +212,7 @@ private: class HeightMapShapeBullet : public ShapeBullet { public: - Vector<real_t> heights; + Vector<float> heights; int width = 0; int depth = 0; real_t min_height = 0.0; @@ -226,7 +226,7 @@ public: virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: - void setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); + void setup(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); }; class RayShapeBullet : public ShapeBullet { diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp index 45c892851b..1d83118468 100644 --- a/modules/bullet/slider_joint_bullet.cpp +++ b/modules/bullet/slider_joint_bullet.cpp @@ -40,16 +40,16 @@ @author AndreaCatania */ -SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) : +SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : JointBullet() { - Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); btTransform btFrameA; G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); btTransform btFrameB; @@ -70,44 +70,44 @@ const RigidBodyBullet *SliderJointBullet::getRigidBodyB() const { return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyB().getUserPointer()); } -const Transform SliderJointBullet::getCalculatedTransformA() const { +const Transform3D SliderJointBullet::getCalculatedTransformA() const { btTransform btTransform = sliderConstraint->getCalculatedTransformA(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -const Transform SliderJointBullet::getCalculatedTransformB() const { +const Transform3D SliderJointBullet::getCalculatedTransformB() const { btTransform btTransform = sliderConstraint->getCalculatedTransformB(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -const Transform SliderJointBullet::getFrameOffsetA() const { +const Transform3D SliderJointBullet::getFrameOffsetA() const { btTransform btTransform = sliderConstraint->getFrameOffsetA(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -const Transform SliderJointBullet::getFrameOffsetB() const { +const Transform3D SliderJointBullet::getFrameOffsetB() const { btTransform btTransform = sliderConstraint->getFrameOffsetB(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -Transform SliderJointBullet::getFrameOffsetA() { +Transform3D SliderJointBullet::getFrameOffsetA() { btTransform btTransform = sliderConstraint->getFrameOffsetA(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -Transform SliderJointBullet::getFrameOffsetB() { +Transform3D SliderJointBullet::getFrameOffsetB() { btTransform btTransform = sliderConstraint->getFrameOffsetB(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h index 90964671c2..0c93558449 100644 --- a/modules/bullet/slider_joint_bullet.h +++ b/modules/bullet/slider_joint_bullet.h @@ -44,18 +44,18 @@ class SliderJointBullet : public JointBullet { public: /// Reference frame is A - SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB); + SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; } const RigidBodyBullet *getRigidBodyA() const; const RigidBodyBullet *getRigidBodyB() const; - const Transform getCalculatedTransformA() const; - const Transform getCalculatedTransformB() const; - const Transform getFrameOffsetA() const; - const Transform getFrameOffsetB() const; - Transform getFrameOffsetA(); - Transform getFrameOffsetB(); + const Transform3D getCalculatedTransformA() const; + const Transform3D getCalculatedTransformB() const; + const Transform3D getFrameOffsetA() const; + const Transform3D getFrameOffsetB() const; + Transform3D getFrameOffsetA(); + Transform3D getFrameOffsetB(); real_t getLowerLinLimit() const; void setLowerLinLimit(real_t lowerLimit); real_t getUpperLinLimit() const; diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 2c8727baf2..bbbb0e7851 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -136,7 +136,7 @@ void SoftBodyBullet::destroy_soft_body() { bt_soft_body = nullptr; } -void SoftBodyBullet::set_soft_transform(const Transform &p_transform) { +void SoftBodyBullet::set_soft_transform(const Transform3D &p_transform) { reset_all_node_positions(); move_all_nodes(p_transform); } @@ -159,7 +159,7 @@ AABB SoftBodyBullet::get_bounds() const { return aabb; } -void SoftBodyBullet::move_all_nodes(const Transform &p_transform) { +void SoftBodyBullet::move_all_nodes(const Transform3D &p_transform) { if (!bt_soft_body) { return; } diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index 87023b2517..63708b57a7 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -104,11 +104,11 @@ public: void destroy_soft_body(); // Special function. This function has bad performance - void set_soft_transform(const Transform &p_transform); + void set_soft_transform(const Transform3D &p_transform); AABB get_bounds() const; - void move_all_nodes(const Transform &p_transform); + void move_all_nodes(const Transform3D &p_transform); void set_node_position(int node_index, const Vector3 &p_global_position); void set_node_position(int node_index, const btVector3 &p_global_position); void get_node_position(int node_index, Vector3 &r_position) const; diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index ceae3be8bc..33dd9ef56d 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V } } -int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return 0; } @@ -152,7 +152,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { +bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { r_closest_safe = 0.0f; r_closest_unsafe = 0.0f; btVector3 bt_motion; @@ -214,7 +214,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf } /// Returns the list of contacts pairs in this order: Local contact, other body contact -bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return false; } @@ -250,7 +250,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape); ERR_FAIL_COND_V(!shape, false); @@ -445,7 +445,7 @@ real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) { case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: default: - WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned."); + WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned."); return 0.f; } } @@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat; static Ref<StandardMaterial3D> blue_mat; #endif -bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { #if debug_test_motion /// Yes I know this is not good, but I've used it as fast debugging hack. /// I'm leaving it here just for speedup the other eventual debugs @@ -1062,7 +1062,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f return has_penetration; } -int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { +int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { btTransform body_transform; G_TO_B(p_transform, body_transform); UNSCALE_BT_BASIS(body_transform); @@ -1235,6 +1235,10 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran continue; } + if (kin_shape.shape->getShapeType() == EMPTY_SHAPE_PROXYTYPE) { + continue; + } + btTransform shape_transform = p_body_position * kin_shape.transform; shape_transform.getOrigin() += r_delta_recover_movement; diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 87aa2b9e93..36d0538e6b 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -78,11 +78,11 @@ public: virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; /// Returns the list of contacts pairs in this order: Local contact, other body contact - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; }; @@ -188,8 +188,8 @@ public: real_t get_linear_damp() const { return linear_damp; } real_t get_angular_damp() const { return angular_damp; } - bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); - int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); + bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); + int test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); private: void create_empty_world(bool p_create_soft_world); diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm index 3d2053ad23..6bc56add20 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_osx.mm @@ -106,15 +106,15 @@ if (input) { [self removeInput:input]; // don't release this - input = NULL; + input = nullptr; } // free up our output if (output) { [self removeOutput:output]; - [output setSampleBufferDelegate:nil queue:NULL]; + [output setSampleBufferDelegate:nil queue:nullptr]; [output release]; - output = NULL; + output = nullptr; } [self commitConfiguration]; @@ -141,9 +141,9 @@ // get our buffers unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1); - if (dataY == NULL) { + if (dataY == nullptr) { print_line("Couldn't access Y pixel buffer data"); - } else if (dataCbCr == NULL) { + } else if (dataCbCr == nullptr) { print_line("Couldn't access CbCr pixel buffer data"); } else { Ref<Image> img[2]; @@ -162,7 +162,7 @@ uint8_t *w = img_data[0].ptrw(); memcpy(w, dataY, new_width * new_height); - img[0].instance(); + img[0].instantiate(); img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]); } @@ -181,7 +181,7 @@ memcpy(w, dataCbCr, 2 * new_width * new_height); ///TODO GLES2 doesn't support FORMAT_RG8, need to do some form of conversion - img[1].instance(); + img[1].instantiate(); img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]); } @@ -220,8 +220,8 @@ AVCaptureDevice *CameraFeedOSX::get_device() const { }; CameraFeedOSX::CameraFeedOSX() { - device = NULL; - capture_session = NULL; + device = nullptr; + capture_session = nullptr; }; void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { @@ -240,14 +240,14 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { }; CameraFeedOSX::~CameraFeedOSX() { - if (capture_session != NULL) { + if (capture_session != nullptr) { [capture_session release]; - capture_session = NULL; + capture_session = nullptr; }; - if (device != NULL) { + if (device != nullptr) { [device release]; - device = NULL; + device = nullptr; }; }; @@ -267,7 +267,7 @@ void CameraFeedOSX::deactivate_feed() { if (capture_session) { [capture_session cleanup]; [capture_session release]; - capture_session = NULL; + capture_session = nullptr; }; }; @@ -341,7 +341,7 @@ void CameraOSX::update_feeds() { if (!found) { Ref<CameraFeedOSX> newfeed; - newfeed.instance(); + newfeed.instantiate(); newfeed->set_device(device); // assume display camera so inverse diff --git a/modules/csg/config.py b/modules/csg/config.py index 9106cbceca..3991b846f9 100644 --- a/modules/csg/config.py +++ b/modules/csg/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 8b46447f04..5a37486568 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -265,7 +265,7 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< _regen_face_aabbs(); } -void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) { +void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform3D &p_xform) { faces = p_brush.faces; materials = p_brush.materials; @@ -931,7 +931,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ // Delete the old faces in reverse index order. merge_faces_idx.sort(); - merge_faces_idx.invert(); + merge_faces_idx.reverse(); for (int i = 0; i < merge_faces_idx.size(); ++i) { faces.remove(merge_faces_idx[i]); } diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 3fbed66e5c..c872860486 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -33,10 +33,10 @@ #include "core/math/aabb.h" #include "core/math/plane.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/list.h" #include "core/templates/map.h" #include "core/templates/oa_hash_map.h" @@ -60,7 +60,7 @@ struct CSGBrush { // Create a brush from faces. void build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces); - void copy_from(const CSGBrush &p_brush, const Transform &p_xform); + void copy_from(const CSGBrush &p_brush, const Transform3D &p_xform); }; struct CSGBrushOperation { @@ -165,8 +165,8 @@ struct CSGBrushOperation { Vector<Vertex2D> vertices; Vector<Face2D> faces; Plane plane; - Transform to_2D; - Transform to_3D; + Transform3D to_2D; + Transform3D to_3D; float vertex_snap2 = 0.0; inline int _get_point_idx(const Vector2 &p_point); diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index e23442ef99..37a7d96de5 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -99,9 +99,9 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); - Transform gt = cs->get_global_transform(); + Transform3D gt = cs->get_global_transform(); //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -292,27 +292,16 @@ bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const { } void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); - p_gizmo->clear(); - Ref<Material> material; - switch (cs->get_operation()) { - case CSGShape3D::OPERATION_UNION: - material = get_material("shape_union_material", p_gizmo); - break; - case CSGShape3D::OPERATION_INTERSECTION: - material = get_material("shape_intersection_material", p_gizmo); - break; - case CSGShape3D::OPERATION_SUBTRACTION: - material = get_material("shape_subtraction_material", p_gizmo); - break; - } - - Ref<Material> handles_material = get_material("handles"); + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); Vector<Vector3> faces = cs->get_brush_faces(); + if (faces.size() == 0) { + return; + } + Vector<Vector3> lines; lines.resize(faces.size() * 2); { @@ -328,6 +317,21 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } } + Ref<Material> material; + switch (cs->get_operation()) { + case CSGShape3D::OPERATION_UNION: + material = get_material("shape_union_material", p_gizmo); + break; + case CSGShape3D::OPERATION_INTERSECTION: + material = get_material("shape_intersection_material", p_gizmo); + break; + case CSGShape3D::OPERATION_SUBTRACTION: + material = get_material("shape_subtraction_material", p_gizmo); + break; + } + + Ref<Material> handles_material = get_material("handles"); + p_gizmo->add_lines(lines, material); p_gizmo->add_collision_segments(lines); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index b97ee6ce4c..fd8b213293 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -44,7 +44,7 @@ void CSGShape3D::set_use_collision(bool p_enable) { } if (use_collision) { - root_collision_shape.instance(); + root_collision_shape.instantiate(); root_collision_instance = PhysicsServer3D::get_singleton()->body_create(); PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); @@ -89,6 +89,7 @@ uint32_t CSGShape3D::get_collision_mask() const { } void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) { + ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive."); uint32_t mask = get_collision_mask(); if (p_value) { mask |= 1 << p_bit; @@ -99,20 +100,23 @@ void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) { } bool CSGShape3D::get_collision_mask_bit(int p_bit) const { + ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive."); return get_collision_mask() & (1 << p_bit); } void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) { - uint32_t mask = get_collision_layer(); + ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive."); + uint32_t layer = get_collision_layer(); if (p_value) { - mask |= 1 << p_bit; + layer |= 1 << p_bit; } else { - mask &= ~(1 << p_bit); + layer &= ~(1 << p_bit); } - set_collision_layer(mask); + set_collision_layer(layer); } bool CSGShape3D::get_collision_layer_bit(int p_bit) const { + ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive."); return get_collision_layer() & (1 << p_bit); } @@ -407,7 +411,7 @@ void CSGShape3D::_update_shape() { } } - root_mesh.instance(); + root_mesh.instantiate(); //create surfaces for (int i = 0; i < surfaces.size(); i++) { @@ -494,7 +498,7 @@ void CSGShape3D::_notification(int p_what) { } if (use_collision && is_root_shape()) { - root_collision_shape.instance(); + root_collision_shape.instantiate(); root_collision_instance = PhysicsServer3D::get_singleton()->body_create(); PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); @@ -574,7 +578,7 @@ Array CSGShape3D::get_meshes() const { if (root_mesh.is_valid()) { Array arr; arr.resize(2); - arr[0] = Transform(); + arr[0] = Transform3D(); arr[1] = root_mesh; return arr; } @@ -864,7 +868,7 @@ void CSGMesh3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &CSGMesh3D::get_material); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) { @@ -880,7 +884,7 @@ void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) { mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed)); } - _make_dirty(); + _mesh_changed(); } Ref<Mesh> CSGMesh3D::get_mesh() { @@ -919,45 +923,43 @@ CSGBrush *CSGSphere3D::_build_brush() { Ref<Material> *materialsw = materials.ptrw(); bool *invertw = invert.ptrw(); + const double lat_step = 1.0 / rings; + const double lon_step = 1.0 / radial_segments; int face = 0; - const double lat_step = Math_TAU / rings; - const double lon_step = Math_TAU / radial_segments; - for (int i = 1; i <= rings; i++) { - double lat0 = lat_step * (i - 1) - Math_TAU / 4; - double z0 = Math::sin(lat0); - double zr0 = Math::cos(lat0); - double u0 = double(i - 1) / rings; - - double lat1 = lat_step * i - Math_TAU / 4; - double z1 = Math::sin(lat1); - double zr1 = Math::cos(lat1); - double u1 = double(i) / rings; - - for (int j = radial_segments; j >= 1; j--) { - double lng0 = lon_step * (j - 1); + double lat0 = Math_PI * (0.5 - (i - 1) * lat_step); + double c0 = Math::cos(lat0); + double s0 = Math::sin(lat0); + double v0 = double(i - 1) / rings; + + double lat1 = Math_PI * (0.5 - i * lat_step); + double c1 = Math::cos(lat1); + double s1 = Math::sin(lat1); + double v1 = double(i) / rings; + + for (int j = 1; j <= radial_segments; j++) { + double lng0 = Math_TAU * (0.5 - (j - 1) * lon_step); double x0 = Math::cos(lng0); double y0 = Math::sin(lng0); - double v0 = double(i - 1) / radial_segments; + double u0 = double(j - 1) / radial_segments; - double lng1 = lon_step * j; + double lng1 = Math_TAU * (0.5 - j * lon_step); double x1 = Math::cos(lng1); double y1 = Math::sin(lng1); - double v1 = double(i) / radial_segments; + double u1 = double(j) / radial_segments; Vector3 v[4] = { - Vector3(x1 * zr0, z0, y1 * zr0) * radius, - Vector3(x1 * zr1, z1, y1 * zr1) * radius, - Vector3(x0 * zr1, z1, y0 * zr1) * radius, - Vector3(x0 * zr0, z0, y0 * zr0) * radius + Vector3(x0 * c0, s0, y0 * c0) * radius, + Vector3(x1 * c0, s0, y1 * c0) * radius, + Vector3(x1 * c1, s1, y1 * c1) * radius, + Vector3(x0 * c1, s1, y0 * c1) * radius, }; Vector2 u[4] = { - Vector2(v1, u0), - Vector2(v1, u1), - Vector2(v0, u1), - Vector2(v0, u0), - + Vector2(u0, v0), + Vector2(u1, v0), + Vector2(u1, v1), + Vector2(u0, v1), }; if (i < rings) { @@ -1025,7 +1027,7 @@ void CSGSphere3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGSphere3D::set_radius(const float p_radius) { @@ -1195,7 +1197,7 @@ void CSGBox3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGBox3D::set_size(const Vector3 &p_size) { @@ -1371,12 +1373,12 @@ void CSGCylinder3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder3D::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder3D::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cone"), "set_cone", "is_cone"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGCylinder3D::set_radius(const float p_radius) { @@ -1590,12 +1592,12 @@ void CSGTorus3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus3D::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus3D::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_outer_radius", "get_outer_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_sides", "get_ring_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGTorus3D::set_inner_radius(const float p_inner_radius) { @@ -1679,7 +1681,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { Vector<Point2> final_polygon = polygon; if (Triangulate::get_area(final_polygon) > 0) { - final_polygon.invert(); + final_polygon.reverse(); } Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon); @@ -1741,7 +1743,6 @@ CSGBrush *CSGPolygon3D::_build_brush() { path_cache->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited)); path_cache->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed)); - path_cache = nullptr; } curve = path->get_curve(); if (curve.is_null()) { @@ -1977,13 +1978,13 @@ CSGBrush *CSGPolygon3D::_build_brush() { float u1 = 0.0; float u2 = path_continuous_u ? 0.0 : 1.0; - Transform path_to_this; + Transform3D path_to_this; if (!path_local) { // center on paths origin path_to_this = get_global_transform().affine_inverse() * path->get_global_transform(); } - Transform prev_xf; + Transform3D prev_xf; Vector3 lookat_dir; @@ -2005,7 +2006,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { ofs = 0.0; } - Transform xf; + Transform3D xf; xf.origin = curve->interpolate_baked(ofs); Vector3 local_dir; @@ -2157,13 +2158,13 @@ void CSGPolygon3D::_notification(int p_what) { void CSGPolygon3D::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("spin") && mode != MODE_SPIN) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("path") && mode != MODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "depth" && mode != MODE_DEPTH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } CSGShape3D::_validate_property(property); @@ -2223,17 +2224,17 @@ void CSGPolygon3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path"), "set_path_node", "get_path_node"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_path_interval", "get_path_interval"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); BIND_ENUM_CONSTANT(MODE_DEPTH); BIND_ENUM_CONSTANT(MODE_SPIN); diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml index b1d0454b76..5bb1c4e75b 100644 --- a/modules/csg/doc_classes/CSGBox3D.xml +++ b/modules/csg/doc_classes/CSGBox3D.xml @@ -14,7 +14,7 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the box. </member> - <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> + <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)"> The box's width, height and depth. </member> </members> diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml index 1bab8f4ee9..5fa8427843 100644 --- a/modules/csg/doc_classes/CSGMesh3D.xml +++ b/modules/csg/doc_classes/CSGMesh3D.xml @@ -4,7 +4,7 @@ A CSG Mesh shape that uses a mesh resource. </brief_description> <description> - This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more then two faces. + This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more than two faces. </description> <tutorials> </tutorials> @@ -16,6 +16,7 @@ </member> <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> The [Mesh] resource to use as a CSG shape. + [b]Note:[/b] When using an [ArrayMesh], avoid meshes with vertex normals unless a flat shader is required. By default, CSGMesh will ignore the mesh's vertex normals and use a smooth shader calculated using the faces' normals. If a flat shader is required, ensure that all faces' vertex normals are parallel. </member> </members> <constants> diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index c55fa0983e..4f29786779 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -38,7 +38,7 @@ <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation"> The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH]. </member> - <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )"> + <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)"> Point array that defines the shape that we'll extrude. </member> <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false"> diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index dac556c7f1..01ec46e707 100644 --- a/modules/csg/doc_classes/CSGShape3D.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -31,7 +31,7 @@ <return type="Array"> </return> <description> - Returns an [Array] with two elements, the first is the [Transform] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape. + Returns an [Array] with two elements, the first is the [Transform3D] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape. </description> </method> <method name="is_root_shape" qualifiers="const"> diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg index ceef9196a7..2740cc2f8c 100644 --- a/modules/csg/icons/CSGBox3D.svg +++ b/modules/csg/icons/CSGBox3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/><path d="m8 .94531-7 3.5v7.2227l7 3.5.29492-.14844c-.18282-.30101-.29492-.64737-.29492-1.0195v-2c0-.72651.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c.36419 0 .70336.10754 1 .2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc9c9c" stroke-width="1.0667"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/><path d="m8 .94531-7 3.5v7.2227l7 3.5.29492-.14844c-.18282-.30101-.29492-.64737-.29492-1.0195v-2c0-.72651.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c.36419 0 .70336.10754 1 .2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc7f7f" stroke-width="1.0667"/></svg> diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg index 14e582ee84..db4f71864b 100644 --- a/modules/csg/icons/CSGCapsule3D.svg +++ b/modules/csg/icons/CSGCapsule3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922.092943 0 .18367-.008623.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72887.41095-1.3691 1.0059-1.7188v-.28125c.34771-.034464.68259-.10691 1.0156-.19922.10394-.99856.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-.66556-.1047-1.2974-.37231-1.9941-.66211v-1.3223c0-1.3474.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957.4088 1.9941 1.5256 1.9941 2.873v1.3457c-.68406.3054-1.3142.57292-1.9941.66602v-4.8848zm-4.0059 6.334c.67836.2231 1.3126.44599 1.9941.52539v2.8848c-1.1957-.4092-1.9941-1.5237-1.9941-2.8711v-.53906z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922.092943 0 .18367-.008623.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72887.41095-1.3691 1.0059-1.7188v-.28125c.34771-.034464.68259-.10691 1.0156-.19922.10394-.99856.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-.66556-.1047-1.2974-.37231-1.9941-.66211v-1.3223c0-1.3474.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957.4088 1.9941 1.5256 1.9941 2.873v1.3457c-.68406.3054-1.3142.57292-1.9941.66602v-4.8848zm-4.0059 6.334c.67836.2231 1.3126.44599 1.9941.52539v2.8848c-1.1957-.4092-1.9941-1.5237-1.9941-2.8711v-.53906z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg> diff --git a/modules/csg/icons/CSGCombiner3D.svg b/modules/csg/icons/CSGCombiner3D.svg index 50ce4179d9..692ba54cb8 100644 --- a/modules/csg/icons/CSGCombiner3D.svg +++ b/modules/csg/icons/CSGCombiner3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/><path d="m3 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc9c9c"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/><path d="m3 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc7f7f"/></svg> diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg index c84594928a..4bc2427887 100644 --- a/modules/csg/icons/CSGCylinder3D.svg +++ b/modules/csg/icons/CSGCylinder3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.7469 0-3.328.22648-4.5586.63672-.61528.20512-1.1471.45187-1.5898.80078-.44272.34891-.85156.88101-.85156 1.5625v8c0 .68149.40884 1.2155.85156 1.5645.44272.34891.97457.59577 1.5898.80078 1.2306.41024 2.8117.63477 4.5586.63477.095648 0 .18467-.008426.2793-.009766-.1722-.29446-.2793-.62995-.2793-.99023v-1c-1.5668 0-2.9867-.2195-3.9277-.5332-.46329-.15435-.90474-.33752-1.0723-.4668v-5.8125c.1468.058667.2835.12515.44141.17773 1.2306.41024 2.8117.63477 4.5586.63477s3.328-.22453 4.5586-.63477c.15791-.052267.29461-.11864.44141-.17773v1.8125h1c.36396 0 .70348.10774 1 .2832v-4.2832c0-.68149-.40884-1.2136-.85156-1.5625-.44272-.34891-.97457-.59566-1.5898-.80078-1.2306-.41024-2.8117-.63672-4.5586-.63672zm0 2c1.5668 0 2.9867.22145 3.9277.53516.46368.15456.80138.33741.96875.4668-.16752.12928-.50546.3105-.96875.46484-.94102.31371-2.361.5332-3.9277.5332s-2.9867-.2195-3.9277-.5332c-.46329-.15435-.80123-.33556-.96875-.46484.16737-.12939.50507-.31224.96875-.4668.94102-.31371 2.361-.53516 3.9277-.53516z" fill="#fc9c9c" stroke-width="1.0667" transform="scale(.9375)"/><path d="m11.25 8.4375c-.51938 0-.9375.41812-.9375.9375v.9375h1.875v1.875h.9375c.51938 0 .9375-.41812.9375-.9375v-1.875c0-.51938-.41812-.9375-.9375-.9375zm.9375 3.75h-1.875v-1.875h-.9375c-.51938 0-.9375.41812-.9375.9375v1.875c0 .51938.41812.9375.9375.9375h1.875c.51938 0 .9375-.41812.9375-.9375z" fill="#84c2ff"/></svg> +<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.7469 0-3.328.22648-4.5586.63672-.61528.20512-1.1471.45187-1.5898.80078-.44272.34891-.85156.88101-.85156 1.5625v8c0 .68149.40884 1.2155.85156 1.5645.44272.34891.97457.59577 1.5898.80078 1.2306.41024 2.8117.63477 4.5586.63477.095648 0 .18467-.008426.2793-.009766-.1722-.29446-.2793-.62995-.2793-.99023v-1c-1.5668 0-2.9867-.2195-3.9277-.5332-.46329-.15435-.90474-.33752-1.0723-.4668v-5.8125c.1468.058667.2835.12515.44141.17773 1.2306.41024 2.8117.63477 4.5586.63477s3.328-.22453 4.5586-.63477c.15791-.052267.29461-.11864.44141-.17773v1.8125h1c.36396 0 .70348.10774 1 .2832v-4.2832c0-.68149-.40884-1.2136-.85156-1.5625-.44272-.34891-.97457-.59566-1.5898-.80078-1.2306-.41024-2.8117-.63672-4.5586-.63672zm0 2c1.5668 0 2.9867.22145 3.9277.53516.46368.15456.80138.33741.96875.4668-.16752.12928-.50546.3105-.96875.46484-.94102.31371-2.361.5332-3.9277.5332s-2.9867-.2195-3.9277-.5332c-.46329-.15435-.80123-.33556-.96875-.46484.16737-.12939.50507-.31224.96875-.4668.94102-.31371 2.361-.53516 3.9277-.53516z" fill="#fc7f7f" stroke-width="1.0667" transform="scale(.9375)"/><path d="m11.25 8.4375c-.51938 0-.9375.41812-.9375.9375v.9375h1.875v1.875h.9375c.51938 0 .9375-.41812.9375-.9375v-1.875c0-.51938-.41812-.9375-.9375-.9375zm.9375 3.75h-1.875v-1.875h-.9375c-.51938 0-.9375.41812-.9375.9375v1.875c0 .51938.41812.9375.9375.9375h1.875c.51938 0 .9375-.41812.9375-.9375z" fill="#5fb2ff"/></svg> diff --git a/modules/csg/icons/CSGMesh3D.svg b/modules/csg/icons/CSGMesh3D.svg index 962e71f6ae..8f4a1736fb 100644 --- a/modules/csg/icons/CSGMesh3D.svg +++ b/modules/csg/icons/CSGMesh3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h3.2695v-2h-3.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l4.916 4.916c.31428-.20669.68609-.33008 1.084-.33008 0-.3979.12338-.76971.33008-1.084l-4.916-4.916h5.8574c.17478.30301.42598.55488.72852.73047v3.2695h2v-3.2715c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h3.2695v-2h-3.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l4.916 4.916c.31428-.20669.68609-.33008 1.084-.33008 0-.3979.12338-.76971.33008-1.084l-4.916-4.916h5.8574c.17478.30301.42598.55488.72852.73047v3.2695h2v-3.2715c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg> diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg index 1d496e5fd9..971f3577bb 100644 --- a/modules/csg/icons/CSGPolygon3D.svg +++ b/modules/csg/icons/CSGPolygon3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9629 1.002c-.14254.00487-.28238.04016-.41016.10352l-6 3c-.33878.16944-.55276.51574-.55273.89453v5.832c-.105.61631.37487 1.1768 1 1.168h5v2c.0000216.67546.64487 1.1297 1.2617.95898-.16118-.28721-.26172-.61135-.26172-.95898v-2c0-.72673.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c.36397 0 .70348.10774 1 .2832v-3.2773c.000006-.00195.000006-.0039094 0-.0058594.000026-.37879-.21395-.72509-.55273-.89453l-6-3c-.15022-.074574-.31679-.11017-.48438-.10352zm.037109 2.1172 3.7637 1.8809-2.7637 1.3809v-1.3809c-.0000552-.55226-.44774-.99994-1-1h-1.7617l1.7617-.88086zm-5 2.8809h4v4h-4z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9629 1.002c-.14254.00487-.28238.04016-.41016.10352l-6 3c-.33878.16944-.55276.51574-.55273.89453v5.832c-.105.61631.37487 1.1768 1 1.168h5v2c.0000216.67546.64487 1.1297 1.2617.95898-.16118-.28721-.26172-.61135-.26172-.95898v-2c0-.72673.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c.36397 0 .70348.10774 1 .2832v-3.2773c.000006-.00195.000006-.0039094 0-.0058594.000026-.37879-.21395-.72509-.55273-.89453l-6-3c-.15022-.074574-.31679-.11017-.48438-.10352zm.037109 2.1172 3.7637 1.8809-2.7637 1.3809v-1.3809c-.0000552-.55226-.44774-.99994-1-1h-1.7617l1.7617-.88086zm-5 2.8809h4v4h-4z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg> diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg index 639e38f49f..770af80632 100644 --- a/modules/csg/icons/CSGSphere3D.svg +++ b/modules/csg/icons/CSGSphere3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 .093042 0 .18321-.01004.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72673.40794-1.3664 1-1.7168v-.33398c.34074-.019259.67728-.069097 1.0156-.10547.083091-1.0187.94713-1.8438 1.9844-1.8438h2c.35841 0 .69292.10484.98633.27539.003633-.092184.013672-.18235.013672-.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm-5.7793 6.2988c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 .093042 0 .18321-.01004.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72673.40794-1.3664 1-1.7168v-.33398c.34074-.019259.67728-.069097 1.0156-.10547.083091-1.0187.94713-1.8438 1.9844-1.8438h2c.35841 0 .69292.10484.98633.27539.003633-.092184.013672-.18235.013672-.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm-5.7793 6.2988c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg> diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg index eb8c0f37cb..ece9c68d28 100644 --- a/modules/csg/icons/CSGTorus3D.svg +++ b/modules/csg/icons/CSGTorus3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3c-1.8145 0-3.4691.41721-4.7461 1.1621-1.277.745-2.2539 1.9082-2.2539 3.3379 0 1.4298.9769 2.5949 2.2539 3.3398s2.9316 1.1602 4.7461 1.1602c0-1.0907.90931-2 2-2 0-.080836.013744-.15778.023438-.23633-.61769.14673-1.3008.23633-2.0234.23633-1.4992 0-2.8437-.36687-3.7383-.88867-.89456-.5219-1.2617-1.108-1.2617-1.6113 0-.5032.36716-1.0876 1.2617-1.6094.89456-.5219 2.2391-.89062 3.7383-.89062s2.8437.36872 3.7383.89062c.89456.5218 1.2617 1.1062 1.2617 1.6094 0 .15978-.053679.32822-.13281.5h1.1328c.32481 0 .62893.088408.90234.23047.057552-.23582.097656-.47718.097656-.73047 0-1.4297-.9769-2.5929-2.2539-3.3379-1.277-.7449-2.9316-1.1621-4.7461-1.1621z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3c-1.8145 0-3.4691.41721-4.7461 1.1621-1.277.745-2.2539 1.9082-2.2539 3.3379 0 1.4298.9769 2.5949 2.2539 3.3398s2.9316 1.1602 4.7461 1.1602c0-1.0907.90931-2 2-2 0-.080836.013744-.15778.023438-.23633-.61769.14673-1.3008.23633-2.0234.23633-1.4992 0-2.8437-.36687-3.7383-.88867-.89456-.5219-1.2617-1.108-1.2617-1.6113 0-.5032.36716-1.0876 1.2617-1.6094.89456-.5219 2.2391-.89062 3.7383-.89062s2.8437.36872 3.7383.89062c.89456.5218 1.2617 1.1062 1.2617 1.6094 0 .15978-.053679.32822-.13281.5h1.1328c.32481 0 .62893.088408.90234.23047.057552-.23582.097656-.47718.097656-.73047 0-1.4297-.9769-2.5929-2.2539-3.3379-1.277-.7449-2.9316-1.1621-4.7461-1.1621z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg> diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp index e28f44d1eb..a47390c2b2 100644 --- a/modules/csg/register_types.cpp +++ b/modules/csg/register_types.cpp @@ -36,15 +36,15 @@ void register_csg_types() { #ifndef _3D_DISABLED - ClassDB::register_virtual_class<CSGShape3D>(); - ClassDB::register_virtual_class<CSGPrimitive3D>(); - ClassDB::register_class<CSGMesh3D>(); - ClassDB::register_class<CSGSphere3D>(); - ClassDB::register_class<CSGBox3D>(); - ClassDB::register_class<CSGCylinder3D>(); - ClassDB::register_class<CSGTorus3D>(); - ClassDB::register_class<CSGPolygon3D>(); - ClassDB::register_class<CSGCombiner3D>(); + GDREGISTER_VIRTUAL_CLASS(CSGShape3D); + GDREGISTER_VIRTUAL_CLASS(CSGPrimitive3D); + GDREGISTER_CLASS(CSGMesh3D); + GDREGISTER_CLASS(CSGSphere3D); + GDREGISTER_CLASS(CSGBox3D); + GDREGISTER_CLASS(CSGCylinder3D); + GDREGISTER_CLASS(CSGTorus3D); + GDREGISTER_CLASS(CSGPolygon3D); + GDREGISTER_CLASS(CSGCombiner3D); #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<EditorPluginCSG>(); diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp index 1444d33171..60282c3f36 100644 --- a/modules/dds/register_types.cpp +++ b/modules/dds/register_types.cpp @@ -35,7 +35,7 @@ static Ref<ResourceFormatDDS> resource_loader_dds; void register_dds_types() { - resource_loader_dds.instance(); + resource_loader_dds.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_dds); } diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 2fef576b77..fced61a600 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -30,7 +30,7 @@ #include "texture_loader_dds.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0]))) diff --git a/modules/enet/config.py b/modules/enet/config.py index 5fd343c75d..3662b2d94e 100644 --- a/modules/enet/config.py +++ b/modules/enet/config.py @@ -8,7 +8,7 @@ def configure(env): def get_doc_classes(): return [ - "NetworkedMultiplayerENet", + "ENetMultiplayerPeer", ] diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index c8f32ffde6..5b2c72dce4 100644 --- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> PacketPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library. </brief_description> <description> - A PacketPeer implementation that should be passed to [member SceneTree.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals. + A PacketPeer implementation that should be passed to [member MultiplayerAPI.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals. ENet's purpose is to provide a relatively thin, simple and robust network communication layer on top of UDP (User Datagram Protocol). [b]Note:[/b] ENet only uses UDP, not TCP. When forwarding the server port to make your server accessible on the public Internet, you only need to forward the server port in UDP. You can use the [UPNP] class to try to forward the server port automatically when starting the server. </description> @@ -33,10 +33,10 @@ </argument> <argument index="3" name="out_bandwidth" type="int" default="0"> </argument> - <argument index="4" name="client_port" type="int" default="0"> + <argument index="4" name="local_port" type="int" default="0"> </argument> <description> - Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]client_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. + Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. </description> </method> <method name="create_server"> @@ -51,7 +51,7 @@ <argument index="3" name="out_bandwidth" type="int" default="0"> </argument> <description> - Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. + Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. </description> </method> <method name="disconnect_peer"> @@ -72,6 +72,13 @@ Returns the channel of the last packet fetched via [method PacketPeer.get_packet]. </description> </method> + <method name="get_local_port" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the local port to which this peer is bound. + </description> + </method> <method name="get_packet_channel" qualifiers="const"> <return type="int"> </return> @@ -137,18 +144,18 @@ </argument> <description> Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds. - The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the avarage round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped. + The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the average round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped. </description> </method> </methods> <members> <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false"> - Enforce ordered packets when using [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system. + Enforce ordered packets when using [constant MultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant MultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system. </member> <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count" default="3"> The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per-channel basis. This is done to combat latency and reduces ordering restrictions on packets. The delivery status of a packet in one channel won't stall the delivery of other packets in another channel. </member> - <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="NetworkedMultiplayerENet.CompressionMode" default="0"> + <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="ENetMultiplayerPeer.CompressionMode" default="0"> The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. </member> <member name="dtls_verify" type="bool" setter="set_dtls_verify_enabled" getter="is_dtls_verify_enabled" default="true"> @@ -161,7 +168,7 @@ <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1"> Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels: one for reliable packets, and one for unreliable packets. The channel [code]0[/code] is reserved and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data. See [member channel_count] for more information about ENet channels. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> <member name="use_dtls" type="bool" setter="set_dtls_enabled" getter="is_dtls_enabled" default="false"> When enabled, the client or server created by this peer, will use [PacketPeerDTLS] instead of raw UDP sockets for communicating with the remote peer. This will make the communication encrypted with DTLS at the cost of higher resource usage and potentially larger packet size. Note: When creating a DTLS server, make sure you setup the key/certificate pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS clients, have a look at the [member dtls_verify] option, and configure the certificate accordingly via [method set_dtls_certificate]. diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/enet_multiplayer_peer.cpp index 25b87145b6..a9726426ad 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_enet.cpp */ +/* enet_multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,47 +28,47 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "networked_multiplayer_enet.h" +#include "enet_multiplayer_peer.h" #include "core/io/ip.h" #include "core/io/marshalls.h" #include "core/os/os.h" -void NetworkedMultiplayerENet::set_transfer_mode(TransferMode p_mode) { +void ENetMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } -NetworkedMultiplayerPeer::TransferMode NetworkedMultiplayerENet::get_transfer_mode() const { +MultiplayerPeer::TransferMode ENetMultiplayerPeer::get_transfer_mode() const { return transfer_mode; } -void NetworkedMultiplayerENet::set_target_peer(int p_peer) { +void ENetMultiplayerPeer::set_target_peer(int p_peer) { target_peer = p_peer; } -int NetworkedMultiplayerENet::get_packet_peer() const { +int ENetMultiplayerPeer::get_packet_peer() const { ERR_FAIL_COND_V_MSG(!active, 1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, 1); return incoming_packets.front()->get().from; } -int NetworkedMultiplayerENet::get_packet_channel() const { +int ENetMultiplayerPeer::get_packet_channel() const { ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, -1); return incoming_packets.front()->get().channel; } -int NetworkedMultiplayerENet::get_last_packet_channel() const { +int ENetMultiplayerPeer::get_last_packet_channel() const { ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(!current_packet.packet, -1); return current_packet.channel; } -Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { +Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The port number must be set between 0 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive)."); ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); @@ -115,46 +115,37 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int connection_status = CONNECTION_CONNECTED; return OK; } - -Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) { +Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) { ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The server port number must be set between 0 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER, "The client port number must be set between 0 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_local_port < 0 || p_local_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); - if (p_client_port != 0) { - ENetAddress c_client; + ENetAddress c_client; #ifdef GODOT_ENET - if (bind_ip.is_wildcard()) { - c_client.wildcard = 1; - } else { - enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16); - } + if (bind_ip.is_wildcard()) { + c_client.wildcard = 1; + } else { + enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16); + } #else - if (bind_ip.is_wildcard()) { - c_client.host = 0; - } else { - ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6."); - c_client.host = *(uint32_t *)bind_ip.get_ipv4(); - } + if (bind_ip.is_wildcard()) { + c_client.host = 0; + } else { + ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6."); + c_client.host = *(uint32_t *)bind_ip.get_ipv4(); + } #endif - c_client.port = p_client_port; + c_client.port = p_local_port; - host = enet_host_create(&c_client /* create a client host */, - 1 /* only allow 1 outgoing connection */, - channel_count /* allow up to channel_count to be used */, - p_in_bandwidth /* limit incoming bandwidth if > 0 */, - p_out_bandwidth /* limit outgoing bandwidth if > 0 */); - } else { - host = enet_host_create(nullptr /* create a client host */, - 1 /* only allow 1 outgoing connection */, - channel_count /* allow up to channel_count to be used */, - p_in_bandwidth /* limit incoming bandwidth if > 0 */, - p_out_bandwidth /* limit outgoing bandwidth if > 0 */); - } + host = enet_host_create(&c_client /* create a client host */, + 1 /* only allow 1 outgoing connection */, + channel_count /* allow up to channel_count to be used */, + p_in_bandwidth /* limit incoming bandwidth if > 0 */, + p_out_bandwidth /* limit outgoing bandwidth if > 0 */); ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host."); #ifdef GODOT_ENET @@ -166,7 +157,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por _setup_compressor(); - IP_Address ip; + IPAddress ip; if (p_address.is_valid_ip_address()) { ip = p_address; } else { @@ -208,7 +199,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por return OK; } -void NetworkedMultiplayerENet::poll() { +void ENetMultiplayerPeer::poll() { ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); _pop_current_packet(); @@ -371,7 +362,10 @@ void NetworkedMultiplayerENet::poll() { // To myself and only myself incoming_packets.push_back(packet); } else if (!server_relay) { - // No other destination is allowed when server is not relaying + // When relaying is disabled, other destinations will only be processed by the server. + if (target == 0 || target < -1) { + incoming_packets.push_back(packet); + } continue; } else if (target == 0) { // Re-send to everyone but sender :| @@ -432,13 +426,13 @@ void NetworkedMultiplayerENet::poll() { } } -bool NetworkedMultiplayerENet::is_server() const { +bool ENetMultiplayerPeer::is_server() const { ERR_FAIL_COND_V_MSG(!active, false, "The multiplayer instance isn't currently active."); return server; } -void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) { +void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) { ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); _pop_current_packet(); @@ -469,7 +463,7 @@ void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) { connection_status = CONNECTION_DISCONNECTED; } -void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { +void ENetMultiplayerPeer::disconnect_peer(int p_peer, bool now) { ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_MSG(!is_server(), "Can't disconnect a peer when not acting as a server."); ERR_FAIL_COND_MSG(!peer_map.has(p_peer), vformat("Peer ID %d not found in the list of peers.", p_peer)); @@ -504,11 +498,11 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { } } -int NetworkedMultiplayerENet::get_available_packet_count() const { +int ENetMultiplayerPeer::get_available_packet_count() const { return incoming_packets.size(); } -Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { +Error ENetMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V_MSG(incoming_packets.size() == 0, ERR_UNAVAILABLE, "No incoming packets available."); _pop_current_packet(); @@ -522,7 +516,7 @@ Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buff return OK; } -Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer_size) { +Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V_MSG(!active, ERR_UNCONFIGURED, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client."); @@ -562,7 +556,7 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags); encode_uint32(unique_id, &packet->data[0]); // Source ID encode_uint32(target_peer, &packet->data[4]); // Dest ID - copymem(&packet->data[8], p_buffer, p_buffer_size); + memcpy(&packet->data[8], p_buffer, p_buffer_size); if (server) { if (target_peer == 0) { @@ -597,11 +591,11 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer return OK; } -int NetworkedMultiplayerENet::get_max_packet_size() const { +int ENetMultiplayerPeer::get_max_packet_size() const { return 1 << 24; // Anything is good } -void NetworkedMultiplayerENet::_pop_current_packet() { +void ENetMultiplayerPeer::_pop_current_packet() { if (current_packet.packet) { enet_packet_destroy(current_packet.packet); current_packet.packet = nullptr; @@ -610,11 +604,11 @@ void NetworkedMultiplayerENet::_pop_current_packet() { } } -NetworkedMultiplayerPeer::ConnectionStatus NetworkedMultiplayerENet::get_connection_status() const { +MultiplayerPeer::ConnectionStatus ENetMultiplayerPeer::get_connection_status() const { return connection_status; } -uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { +uint32_t ENetMultiplayerPeer::_gen_unique_id() const { uint32_t hash = 0; while (hash == 0 || hash == 1) { @@ -635,12 +629,12 @@ uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { return hash; } -int NetworkedMultiplayerENet::get_unique_id() const { +int ENetMultiplayerPeer::get_unique_id() const { ERR_FAIL_COND_V_MSG(!active, 0, "The multiplayer instance isn't currently active."); return unique_id; } -void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) { +void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enable) { refuse_connections = p_enable; #ifdef GODOT_ENET if (active) { @@ -649,20 +643,20 @@ void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) { #endif } -bool NetworkedMultiplayerENet::is_refusing_new_connections() const { +bool ENetMultiplayerPeer::is_refusing_new_connections() const { return refuse_connections; } -void NetworkedMultiplayerENet::set_compression_mode(CompressionMode p_mode) { +void ENetMultiplayerPeer::set_compression_mode(CompressionMode p_mode) { compression_mode = p_mode; } -NetworkedMultiplayerENet::CompressionMode NetworkedMultiplayerENet::get_compression_mode() const { +ENetMultiplayerPeer::CompressionMode ENetMultiplayerPeer::get_compression_mode() const { return compression_mode; } -size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet *)(context); +size_t ENetMultiplayerPeer::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { + ENetMultiplayerPeer *enet = (ENetMultiplayerPeer *)(context); if (size_t(enet->src_compressor_mem.size()) < inLimit) { enet->src_compressor_mem.resize(inLimit); @@ -673,7 +667,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * while (total) { for (size_t i = 0; i < inBufferCount; i++) { int to_copy = MIN(total, int(inBuffers[i].dataLength)); - copymem(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy); + memcpy(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy); ofs += to_copy; total -= to_copy; } @@ -710,13 +704,13 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * return 0; // Do not bother } - copymem(outData, enet->dst_compressor_mem.ptr(), ret); + memcpy(outData, enet->dst_compressor_mem.ptr(), ret); return ret; } -size_t NetworkedMultiplayerENet::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet *)(context); +size_t ENetMultiplayerPeer::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { + ENetMultiplayerPeer *enet = (ENetMultiplayerPeer *)(context); int ret = -1; switch (enet->compression_mode) { case COMPRESS_FASTLZ: { @@ -738,7 +732,7 @@ size_t NetworkedMultiplayerENet::enet_decompress(void *context, const enet_uint8 } } -void NetworkedMultiplayerENet::_setup_compressor() { +void ENetMultiplayerPeer::_setup_compressor() { switch (compression_mode) { case COMPRESS_NONE: { enet_host_compress(host, nullptr); @@ -754,16 +748,16 @@ void NetworkedMultiplayerENet::_setup_compressor() { } } -void NetworkedMultiplayerENet::enet_compressor_destroy(void *context) { +void ENetMultiplayerPeer::enet_compressor_destroy(void *context) { // Nothing to do } -IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const { - ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IP_Address(), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); - ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IP_Address(), "Can't get the address of peers other than the server (ID -1) when acting as a client."); - ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); +IPAddress ENetMultiplayerPeer::get_peer_address(int p_peer_id) const { + ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IPAddress(), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); + ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IPAddress(), "Can't get the address of peers other than the server (ID -1) when acting as a client."); + ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IPAddress(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); - IP_Address out; + IPAddress out; #ifdef GODOT_ENET out.set_ipv6((uint8_t *)&(peer_map[p_peer_id]->address.host)); #else @@ -773,7 +767,7 @@ IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const { return out; } -int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const { +int ENetMultiplayerPeer::get_peer_port(int p_peer_id) const { ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), 0, vformat("Peer ID %d not found in the list of peers.", p_peer_id)); ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, 0, "Can't get the address of peers other than the server (ID -1) when acting as a client."); ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); @@ -784,7 +778,12 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const { #endif } -void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) { +int ENetMultiplayerPeer::get_local_port() const { + ERR_FAIL_COND_V_MSG(!active || !host, 0, "The multiplayer instance isn't currently active."); + return host->address.port; +} + +void ENetMultiplayerPeer::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) { ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client."); ERR_FAIL_COND_MSG(peer_map[p_peer_id] == nullptr, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); @@ -792,72 +791,73 @@ void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_lim enet_peer_timeout(peer_map[p_peer_id], p_timeout_limit, p_timeout_min, p_timeout_max); } -void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) { +void ENetMultiplayerPeer::set_transfer_channel(int p_channel) { ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel)); ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, vformat("The channel %d is reserved.", SYSCH_CONFIG)); transfer_channel = p_channel; } -int NetworkedMultiplayerENet::get_transfer_channel() const { +int ENetMultiplayerPeer::get_transfer_channel() const { return transfer_channel; } -void NetworkedMultiplayerENet::set_channel_count(int p_channel) { +void ENetMultiplayerPeer::set_channel_count(int p_channel) { ERR_FAIL_COND_MSG(active, "The channel count can't be set while the multiplayer instance is active."); ERR_FAIL_COND_MSG(p_channel < SYSCH_MAX, vformat("The channel count must be greater than or equal to %d to account for reserved channels (got %d).", SYSCH_MAX, p_channel)); channel_count = p_channel; } -int NetworkedMultiplayerENet::get_channel_count() const { +int ENetMultiplayerPeer::get_channel_count() const { return channel_count; } -void NetworkedMultiplayerENet::set_always_ordered(bool p_ordered) { +void ENetMultiplayerPeer::set_always_ordered(bool p_ordered) { always_ordered = p_ordered; } -bool NetworkedMultiplayerENet::is_always_ordered() const { +bool ENetMultiplayerPeer::is_always_ordered() const { return always_ordered; } -void NetworkedMultiplayerENet::set_server_relay_enabled(bool p_enabled) { +void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) { ERR_FAIL_COND_MSG(active, "Server relaying can't be toggled while the multiplayer instance is active."); server_relay = p_enabled; } -bool NetworkedMultiplayerENet::is_server_relay_enabled() const { +bool ENetMultiplayerPeer::is_server_relay_enabled() const { return server_relay; } -void NetworkedMultiplayerENet::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "client_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100)); - ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode); - ClassDB::bind_method(D_METHOD("get_compression_mode"), &NetworkedMultiplayerENet::get_compression_mode); - ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &NetworkedMultiplayerENet::set_bind_ip); - ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_enabled); - ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &NetworkedMultiplayerENet::is_dtls_enabled); - ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &NetworkedMultiplayerENet::set_dtls_key); - ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &NetworkedMultiplayerENet::set_dtls_certificate); - ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_verify_enabled); - ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled); - ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address); - ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port); - ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout); - - ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel); - ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &NetworkedMultiplayerENet::get_last_packet_channel); - ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &NetworkedMultiplayerENet::set_transfer_channel); - ClassDB::bind_method(D_METHOD("get_transfer_channel"), &NetworkedMultiplayerENet::get_transfer_channel); - ClassDB::bind_method(D_METHOD("set_channel_count", "channels"), &NetworkedMultiplayerENet::set_channel_count); - ClassDB::bind_method(D_METHOD("get_channel_count"), &NetworkedMultiplayerENet::get_channel_count); - ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &NetworkedMultiplayerENet::set_always_ordered); - ClassDB::bind_method(D_METHOD("is_always_ordered"), &NetworkedMultiplayerENet::is_always_ordered); - ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &NetworkedMultiplayerENet::set_server_relay_enabled); - ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &NetworkedMultiplayerENet::is_server_relay_enabled); +void ENetMultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &ENetMultiplayerPeer::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &ENetMultiplayerPeer::close_connection, DEFVAL(100)); + ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &ENetMultiplayerPeer::disconnect_peer, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &ENetMultiplayerPeer::set_compression_mode); + ClassDB::bind_method(D_METHOD("get_compression_mode"), &ENetMultiplayerPeer::get_compression_mode); + ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetMultiplayerPeer::set_bind_ip); + ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &ENetMultiplayerPeer::set_dtls_enabled); + ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &ENetMultiplayerPeer::is_dtls_enabled); + ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &ENetMultiplayerPeer::set_dtls_key); + ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &ENetMultiplayerPeer::set_dtls_certificate); + ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &ENetMultiplayerPeer::set_dtls_verify_enabled); + ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &ENetMultiplayerPeer::is_dtls_verify_enabled); + ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &ENetMultiplayerPeer::get_peer_address); + ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &ENetMultiplayerPeer::get_peer_port); + ClassDB::bind_method(D_METHOD("get_local_port"), &ENetMultiplayerPeer::get_local_port); + ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &ENetMultiplayerPeer::set_peer_timeout); + + ClassDB::bind_method(D_METHOD("get_packet_channel"), &ENetMultiplayerPeer::get_packet_channel); + ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &ENetMultiplayerPeer::get_last_packet_channel); + ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &ENetMultiplayerPeer::set_transfer_channel); + ClassDB::bind_method(D_METHOD("get_transfer_channel"), &ENetMultiplayerPeer::get_transfer_channel); + ClassDB::bind_method(D_METHOD("set_channel_count", "channels"), &ENetMultiplayerPeer::set_channel_count); + ClassDB::bind_method(D_METHOD("get_channel_count"), &ENetMultiplayerPeer::get_channel_count); + ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &ENetMultiplayerPeer::set_always_ordered); + ClassDB::bind_method(D_METHOD("is_always_ordered"), &ENetMultiplayerPeer::is_always_ordered); + ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &ENetMultiplayerPeer::set_server_relay_enabled); + ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &ENetMultiplayerPeer::is_server_relay_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "compression_mode", PROPERTY_HINT_ENUM, "None,Range Coder,FastLZ,ZLib,ZStd"), "set_compression_mode", "get_compression_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel"), "set_transfer_channel", "get_transfer_channel"); @@ -874,16 +874,16 @@ void NetworkedMultiplayerENet::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESS_ZSTD); } -NetworkedMultiplayerENet::NetworkedMultiplayerENet() { +ENetMultiplayerPeer::ENetMultiplayerPeer() { enet_compressor.context = this; enet_compressor.compress = enet_compress; enet_compressor.decompress = enet_decompress; enet_compressor.destroy = enet_compressor_destroy; - bind_ip = IP_Address("*"); + bind_ip = IPAddress("*"); } -NetworkedMultiplayerENet::~NetworkedMultiplayerENet() { +ENetMultiplayerPeer::~ENetMultiplayerPeer() { if (active) { close_connection(); } @@ -891,36 +891,36 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet() { // Sets IP for ENet to bind when using create_server or create_client // if no IP is set, then ENet bind to ENET_HOST_ANY -void NetworkedMultiplayerENet::set_bind_ip(const IP_Address &p_ip) { +void ENetMultiplayerPeer::set_bind_ip(const IPAddress &p_ip) { ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip))); bind_ip = p_ip; } -void NetworkedMultiplayerENet::set_dtls_enabled(bool p_enabled) { +void ENetMultiplayerPeer::set_dtls_enabled(bool p_enabled) { ERR_FAIL_COND(active); dtls_enabled = p_enabled; } -bool NetworkedMultiplayerENet::is_dtls_enabled() const { +bool ENetMultiplayerPeer::is_dtls_enabled() const { return dtls_enabled; } -void NetworkedMultiplayerENet::set_dtls_verify_enabled(bool p_enabled) { +void ENetMultiplayerPeer::set_dtls_verify_enabled(bool p_enabled) { ERR_FAIL_COND(active); dtls_verify = p_enabled; } -bool NetworkedMultiplayerENet::is_dtls_verify_enabled() const { +bool ENetMultiplayerPeer::is_dtls_verify_enabled() const { return dtls_verify; } -void NetworkedMultiplayerENet::set_dtls_key(Ref<CryptoKey> p_key) { +void ENetMultiplayerPeer::set_dtls_key(Ref<CryptoKey> p_key) { ERR_FAIL_COND(active); dtls_key = p_key; } -void NetworkedMultiplayerENet::set_dtls_certificate(Ref<X509Certificate> p_cert) { +void ENetMultiplayerPeer::set_dtls_certificate(Ref<X509Certificate> p_cert) { ERR_FAIL_COND(active); dtls_cert = p_cert; } diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/enet_multiplayer_peer.h index b99b14d218..e6d45eb16a 100644 --- a/modules/enet/networked_multiplayer_enet.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_enet.h */ +/* enet_multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,12 +33,12 @@ #include "core/crypto/crypto.h" #include "core/io/compression.h" -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include <enet/enet.h> -class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer { - GDCLASS(NetworkedMultiplayerENet, NetworkedMultiplayerPeer); +class ENetMultiplayerPeer : public MultiplayerPeer { + GDCLASS(ENetMultiplayerPeer, MultiplayerPeer); public: enum CompressionMode { @@ -108,7 +108,7 @@ private: static void enet_compressor_destroy(void *context); void _setup_compressor(); - IP_Address bind_ip; + IPAddress bind_ip; bool dtls_enabled = false; Ref<CryptoKey> dtls_key; @@ -125,12 +125,13 @@ public: virtual int get_packet_peer() const override; - virtual IP_Address get_peer_address(int p_peer_id) const; + virtual IPAddress get_peer_address(int p_peer_id) const; virtual int get_peer_port(int p_peer_id) const; + virtual int get_local_port() const; void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max); Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0); - Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0); + Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0); void close_connection(uint32_t wait_usec = 100); @@ -167,10 +168,10 @@ public: void set_server_relay_enabled(bool p_enabled); bool is_server_relay_enabled() const; - NetworkedMultiplayerENet(); - ~NetworkedMultiplayerENet(); + ENetMultiplayerPeer(); + ~ENetMultiplayerPeer(); - void set_bind_ip(const IP_Address &p_ip); + void set_bind_ip(const IPAddress &p_ip); void set_dtls_enabled(bool p_enabled); bool is_dtls_enabled() const; void set_dtls_verify_enabled(bool p_enabled); @@ -179,6 +180,6 @@ public: void set_dtls_certificate(Ref<X509Certificate> p_cert); }; -VARIANT_ENUM_CAST(NetworkedMultiplayerENet::CompressionMode); +VARIANT_ENUM_CAST(ENetMultiplayerPeer::CompressionMode); #endif // NETWORKED_MULTIPLAYER_ENET_H diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp index 8da2d17e13..38870316e4 100644 --- a/modules/enet/register_types.cpp +++ b/modules/enet/register_types.cpp @@ -30,7 +30,7 @@ #include "register_types.h" #include "core/error/error_macros.h" -#include "networked_multiplayer_enet.h" +#include "enet_multiplayer_peer.h" static bool enet_ok = false; @@ -41,7 +41,7 @@ void register_enet_types() { enet_ok = true; } - ClassDB::register_class<NetworkedMultiplayerENet>(); + GDREGISTER_CLASS(ENetMultiplayerPeer); } void unregister_enet_types() { diff --git a/modules/etc/SCsub b/modules/etc/SCsub deleted file mode 100644 index 9b46f17916..0000000000 --- a/modules/etc/SCsub +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_etc = env_modules.Clone() - -# Thirdparty source files - -thirdparty_obj = [] - -# Not unbundled so far since not widespread as shared library -thirdparty_dir = "#thirdparty/etc2comp/" -thirdparty_sources = [ - "EtcBlock4x4.cpp", - "EtcBlock4x4Encoding.cpp", - "EtcBlock4x4Encoding_ETC1.cpp", - "EtcBlock4x4Encoding_R11.cpp", - "EtcBlock4x4Encoding_RG11.cpp", - "EtcBlock4x4Encoding_RGB8A1.cpp", - "EtcBlock4x4Encoding_RGB8.cpp", - "EtcBlock4x4Encoding_RGBA8.cpp", - "Etc.cpp", - "EtcDifferentialTrys.cpp", - "EtcFilter.cpp", - "EtcImage.cpp", - "EtcIndividualTrys.cpp", - "EtcMath.cpp", - "EtcSortedBlockList.cpp", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env_etc.Prepend(CPPPATH=[thirdparty_dir]) - -env_thirdparty = env_etc.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_etc.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/etc/image_compress_etc.cpp b/modules/etc/image_compress_etc.cpp deleted file mode 100644 index 41cbbe3f54..0000000000 --- a/modules/etc/image_compress_etc.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/*************************************************************************/ -/* image_compress_etc.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 "image_compress_etc.h" - -#include "core/io/image.h" -#include "core/os/copymem.h" -#include "core/os/os.h" -#include "core/string/print_string.h" - -#include <Etc.h> -#include <EtcFilter.h> - -static Image::Format _get_etc2_mode(Image::UsedChannels format) { - switch (format) { - case Image::USED_CHANNELS_R: - return Image::FORMAT_ETC2_R11; - - case Image::USED_CHANNELS_RG: - return Image::FORMAT_ETC2_RG11; - - case Image::USED_CHANNELS_RGB: - return Image::FORMAT_ETC2_RGB8; - - case Image::USED_CHANNELS_RGBA: - return Image::FORMAT_ETC2_RGBA8; - - // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551 - default: - // TODO: Kept for compatibility, but should be investigated whether it's correct or if it should error out - return Image::FORMAT_ETC2_RGBA8; - } -} - -static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) { - switch (format) { - case Image::FORMAT_ETC: - return Etc::Image::Format::ETC1; - - case Image::FORMAT_ETC2_R11: - return Etc::Image::Format::R11; - - case Image::FORMAT_ETC2_R11S: - return Etc::Image::Format::SIGNED_R11; - - case Image::FORMAT_ETC2_RG11: - return Etc::Image::Format::RG11; - - case Image::FORMAT_ETC2_RG11S: - return Etc::Image::Format::SIGNED_RG11; - - case Image::FORMAT_ETC2_RGB8: - return Etc::Image::Format::RGB8; - - case Image::FORMAT_ETC2_RGBA8: - return Etc::Image::Format::RGBA8; - - case Image::FORMAT_ETC2_RGB8A1: - return Etc::Image::Format::RGB8A1; - - default: - ERR_FAIL_V(Etc::Image::Format::UNKNOWN); - } -} - -static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_format, Image::UsedChannels p_channels) { - Image::Format img_format = p_img->get_format(); - - if (img_format >= Image::FORMAT_DXT1) { - return; //do not compress, already compressed - } - - if (img_format > Image::FORMAT_RGBA8) { - // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually - return; - } - - // FIXME: Commented out during Vulkan rebase. - /* - if (force_etc1_format) { - // If VRAM compression is using ETC, but image has alpha, convert to RGBA4444 or LA8 - // This saves space while maintaining the alpha channel - if (detected_channels == Image::USED_CHANNELS_RGBA) { - if (p_img->has_mipmaps()) { - // Image doesn't support mipmaps with RGBA4444 textures - p_img->clear_mipmaps(); - } - p_img->convert(Image::FORMAT_RGBA4444); - return; - } else if (detected_channels == Image::USE_CHANNELS_LA) { - p_img->convert(Image::FORMAT_LA8); - return; - } - } - */ - - uint32_t imgw = p_img->get_width(), imgh = p_img->get_height(); - - Image::Format etc_format = force_etc1_format ? Image::FORMAT_ETC : _get_etc2_mode(p_channels); - - Ref<Image> img = p_img->duplicate(); - - if (img->get_format() != Image::FORMAT_RGBA8) { - img->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert - } - - if (img->has_mipmaps()) { - if (next_power_of_2(imgw) != imgw || next_power_of_2(imgh) != imgh) { - img->resize_to_po2(); - imgw = img->get_width(); - imgh = img->get_height(); - } - } else { - if (imgw % 4 != 0 || imgh % 4 != 0) { - if (imgw % 4) { - imgw += 4 - imgw % 4; - } - if (imgh % 4) { - imgh += 4 - imgh % 4; - } - - img->resize(imgw, imgh); - } - } - - const uint8_t *r = img->get_data().ptr(); - ERR_FAIL_COND(!r); - - unsigned int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps()); - int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0); - - Vector<uint8_t> dst_data; - dst_data.resize(target_size); - - uint8_t *w = dst_data.ptrw(); - - // prepare parameters to be passed to etc2comp - int num_cpus = OS::get_singleton()->get_processor_count(); - int encoding_time = 0; - float effort = 0.0; //default, reasonable time - - if (p_lossy_quality > 0.95) { - effort = 80; - } else if (p_lossy_quality > 0.85) { - effort = 60; - } else if (p_lossy_quality > 0.75) { - effort = 40; - } - - Etc::ErrorMetric error_metric = Etc::ErrorMetric::RGBX; // NOTE: we can experiment with other error metrics - Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format); - - int wofs = 0; - - print_verbose("ETC: Begin encoding, format: " + Image::get_format_name(etc_format)); - uint64_t t = OS::get_singleton()->get_ticks_msec(); - for (int i = 0; i < mmc; i++) { - // convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF) - // NOTE: We can alternatively add a case to Image::convert to handle Image::FORMAT_RGBAF conversion. - int mipmap_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0; - img->get_mipmap_offset_size_and_dimensions(i, mipmap_ofs, mipmap_size, mipmap_w, mipmap_h); - const uint8_t *src = &r[mipmap_ofs]; - - Etc::ColorFloatRGBA *src_rgba_f = new Etc::ColorFloatRGBA[mipmap_w * mipmap_h]; - for (int j = 0; j < mipmap_w * mipmap_h; j++) { - int si = j * 4; // RGBA8 - src_rgba_f[j] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]); - } - - unsigned char *etc_data = nullptr; - unsigned int etc_data_len = 0; - unsigned int extended_width = 0, extended_height = 0; - Etc::Encode((float *)src_rgba_f, mipmap_w, mipmap_h, etc2comp_etc_format, error_metric, effort, num_cpus, num_cpus, &etc_data, &etc_data_len, &extended_width, &extended_height, &encoding_time); - - CRASH_COND(wofs + etc_data_len > target_size); - memcpy(&w[wofs], etc_data, etc_data_len); - wofs += etc_data_len; - - delete[] etc_data; - delete[] src_rgba_f; - } - - print_verbose("ETC: Time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t)); - - p_img->create(imgw, imgh, p_img->has_mipmaps(), etc_format, dst_data); -} - -static void _compress_etc1(Image *p_img, float p_lossy_quality) { - _compress_etc(p_img, p_lossy_quality, true, Image::USED_CHANNELS_RGB); -} - -static void _compress_etc2(Image *p_img, float p_lossy_quality, Image::UsedChannels p_channels) { - _compress_etc(p_img, p_lossy_quality, false, p_channels); -} - -void _register_etc_compress_func() { - Image::_image_compress_etc1_func = _compress_etc1; - Image::_image_compress_etc2_func = _compress_etc2; -} diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp deleted file mode 100644 index 95db9315d5..0000000000 --- a/modules/etc/texture_loader_pkm.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/*************************************************************************/ -/* texture_loader_pkm.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 "texture_loader_pkm.h" - -#include "core/os/file_access.h" -#include <string.h> - -struct ETC1Header { - char tag[6]; // "PKM 10" - uint16_t format = 0; // Format == number of mips (== zero) - uint16_t texWidth = 0; // Texture dimensions, multiple of 4 (big-endian) - uint16_t texHeight = 0; - uint16_t origWidth = 0; // Original dimensions (big-endian) - uint16_t origHeight = 0; -}; - -RES ResourceFormatPKM::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) { - if (r_error) { - *r_error = ERR_CANT_OPEN; - } - - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return RES(); - } - - FileAccessRef fref(f); - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - - ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open PKM texture file '" + p_path + "'."); - - // big endian - f->set_endian_swap(true); - - ETC1Header h; - f->get_buffer((uint8_t *)&h.tag, sizeof(h.tag)); - ERR_FAIL_COND_V_MSG(strncmp(h.tag, "PKM 10", sizeof(h.tag)), RES(), "Invalid or unsupported PKM texture file '" + p_path + "'."); - - h.format = f->get_16(); - h.texWidth = f->get_16(); - h.texHeight = f->get_16(); - h.origWidth = f->get_16(); - h.origHeight = f->get_16(); - - Vector<uint8_t> src_data; - - uint32_t size = h.texWidth * h.texHeight / 2; - src_data.resize(size); - uint8_t *wb = src_data.ptrw(); - f->get_buffer(wb, size); - - int mipmaps = h.format; - int width = h.origWidth; - int height = h.origHeight; - - Ref<Image> img = memnew(Image(width, height, mipmaps, Image::FORMAT_ETC, src_data)); - - Ref<ImageTexture> texture = memnew(ImageTexture); - texture->create_from_image(img); - - if (r_error) { - *r_error = OK; - } - - f->close(); - memdelete(f); - return texture; -} - -void ResourceFormatPKM::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("pkm"); -} - -bool ResourceFormatPKM::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Texture2D"); -} - -String ResourceFormatPKM::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "pkm") { - return "ImageTexture"; - } - return ""; -} diff --git a/modules/etcpak/SCsub b/modules/etcpak/SCsub new file mode 100644 index 0000000000..2d3b69be75 --- /dev/null +++ b/modules/etcpak/SCsub @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_etcpak = env_modules.Clone() + +# Thirdparty source files + +thirdparty_obj = [] + +thirdparty_dir = "#thirdparty/etcpak/" +thirdparty_sources = [ + "Dither.cpp", + "ProcessDxtc.cpp", + "ProcessRGB.cpp", + "Tables.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_etcpak.Prepend(CPPPATH=[thirdparty_dir]) + +env_thirdparty = env_etcpak.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_etcpak.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/etc/config.py b/modules/etcpak/config.py index 53b8f2f2e3..53b8f2f2e3 100644 --- a/modules/etc/config.py +++ b/modules/etcpak/config.py diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp new file mode 100644 index 0000000000..abc3c26188 --- /dev/null +++ b/modules/etcpak/image_compress_etcpak.cpp @@ -0,0 +1,184 @@ +/*************************************************************************/ +/* image_compress_etcpak.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 "image_compress_etcpak.h" + +#include "core/os/os.h" +#include "core/string/print_string.h" + +#include "thirdparty/etcpak/ProcessDxtc.hpp" +#include "thirdparty/etcpak/ProcessRGB.hpp" + +EtcpakType _determine_etc_type(Image::UsedChannels p_channels) { + switch (p_channels) { + case Image::USED_CHANNELS_L: + return EtcpakType::ETCPAK_TYPE_ETC1; + case Image::USED_CHANNELS_LA: + return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA; + case Image::USED_CHANNELS_R: + return EtcpakType::ETCPAK_TYPE_ETC2; + case Image::USED_CHANNELS_RG: + return EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG; + case Image::USED_CHANNELS_RGB: + return EtcpakType::ETCPAK_TYPE_ETC2; + case Image::USED_CHANNELS_RGBA: + return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA; + default: + return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA; + } +} + +EtcpakType _determine_dxt_type(Image::UsedChannels p_channels) { + switch (p_channels) { + case Image::USED_CHANNELS_L: + return EtcpakType::ETCPAK_TYPE_DXT1; + case Image::USED_CHANNELS_LA: + return EtcpakType::ETCPAK_TYPE_DXT5; + case Image::USED_CHANNELS_R: + return EtcpakType::ETCPAK_TYPE_DXT5; + case Image::USED_CHANNELS_RG: + return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG; + case Image::USED_CHANNELS_RGB: + return EtcpakType::ETCPAK_TYPE_DXT5; + case Image::USED_CHANNELS_RGBA: + return EtcpakType::ETCPAK_TYPE_DXT5; + default: + return EtcpakType::ETCPAK_TYPE_DXT5; + } +} + +void _compress_etc1(Image *r_img, float p_lossy_quality) { + _compress_etcpak(EtcpakType::ETCPAK_TYPE_ETC1, r_img, p_lossy_quality); +} + +void _compress_etc2(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels) { + EtcpakType type = _determine_etc_type(p_channels); + _compress_etcpak(type, r_img, p_lossy_quality); +} + +void _compress_bc(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels) { + EtcpakType type = _determine_dxt_type(p_channels); + _compress_etcpak(type, r_img, p_lossy_quality); +} + +void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_quality) { + uint64_t start_time = OS::get_singleton()->get_ticks_msec(); + + // TODO: See how to handle lossy quality. + + Image::Format img_format = r_img->get_format(); + if (img_format >= Image::FORMAT_DXT1) { + return; // Do not compress, already compressed. + } + if (img_format > Image::FORMAT_RGBA8) { + // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually + return; + } + + // Use RGBA8 to convert. + if (img_format != Image::FORMAT_RGBA8) { + r_img->convert(Image::FORMAT_RGBA8); + } + + // Determine output format based on Etcpak type. + Image::Format target_format = Image::FORMAT_RGBA8; + if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) { + target_format = Image::FORMAT_ETC; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2) { + target_format = Image::FORMAT_ETC2_RGB8; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) { + target_format = Image::FORMAT_ETC2_RA_AS_RG; + r_img->convert_rg_to_ra_rgba8(); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) { + target_format = Image::FORMAT_ETC2_RGBA8; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) { + target_format = Image::FORMAT_DXT1; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) { + target_format = Image::FORMAT_DXT5_RA_AS_RG; + r_img->convert_rg_to_ra_rgba8(); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) { + target_format = Image::FORMAT_DXT5; + } else { + ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format."); + } + + // Compress image data and (if required) mipmaps. + + const bool mipmaps = r_img->has_mipmaps(); + const int width = r_img->get_width(); + const int height = r_img->get_height(); + const uint8_t *src_read = r_img->get_data().ptr(); + + print_verbose(vformat("ETCPAK: Encoding image size %dx%d to format %s.", width, height, Image::get_format_name(target_format))); + + int dest_size = Image::get_image_data_size(width, height, target_format, mipmaps); + Vector<uint8_t> dest_data; + dest_data.resize(dest_size); + uint8_t *dest_write = dest_data.ptrw(); + + int mip_count = mipmaps ? Image::get_image_required_mipmaps(width, height, target_format) : 0; + + for (int i = 0; i < mip_count + 1; i++) { + // Get write mip metrics for target image. + int mip_w, mip_h; + int mip_ofs = Image::get_image_mipmap_offset_and_dimensions(width, height, target_format, i, mip_w, mip_h); + // Ensure that mip offset is a multiple of 8 (etcpak expects uint64_t pointer). + ERR_FAIL_COND(mip_ofs % 8 != 0); + uint64_t *dest_mip_write = (uint64_t *)&dest_write[mip_ofs]; + + // Block size. Align stride to multiple of 4 (RGBA8). + mip_w = (mip_w + 3) & ~3; + mip_h = (mip_h + 3) & ~3; + const uint32_t blocks = mip_w * mip_h / 16; + + // Get mip data from source image for reading. + int src_mip_ofs = r_img->get_mipmap_offset(i); + const uint32_t *src_mip_read = (const uint32_t *)&src_read[src_mip_ofs]; + + if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) { + CompressEtc1RgbDither(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2 || p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) { + CompressEtc2Rgb(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) { + CompressEtc2Rgba(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) { + CompressDxt1Dither(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) { + CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w); + } else { + ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format."); + } + } + + // Replace original image with compressed one. + r_img->create(width, height, mipmaps, target_format, dest_data); + + print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time))); +} diff --git a/modules/etcpak/image_compress_etcpak.h b/modules/etcpak/image_compress_etcpak.h new file mode 100644 index 0000000000..ccf157fada --- /dev/null +++ b/modules/etcpak/image_compress_etcpak.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* image_compress_etcpak.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 IMAGE_COMPRESS_ETCPAK_H +#define IMAGE_COMPRESS_ETCPAK_H + +#include "core/io/image.h" + +enum class EtcpakType { + ETCPAK_TYPE_ETC1, + ETCPAK_TYPE_ETC2, + ETCPAK_TYPE_ETC2_ALPHA, + ETCPAK_TYPE_ETC2_RA_AS_RG, + ETCPAK_TYPE_DXT1, + ETCPAK_TYPE_DXT5, + ETCPAK_TYPE_DXT5_RA_AS_RG, +}; + +void _compress_etc1(Image *r_img, float p_lossy_quality); +void _compress_etc2(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels); +void _compress_bc(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels); + +void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_quality); + +#endif // IMAGE_COMPRESS_ETCPAK_H diff --git a/modules/etcpak/register_types.cpp b/modules/etcpak/register_types.cpp new file mode 100644 index 0000000000..d57d2f747a --- /dev/null +++ b/modules/etcpak/register_types.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "register_types.h" + +#include "image_compress_etcpak.h" + +void register_etcpak_types() { + Image::_image_compress_etc1_func = _compress_etc1; + Image::_image_compress_etc2_func = _compress_etc2; + Image::_image_compress_bc_func = _compress_bc; +} + +void unregister_etcpak_types() { +} diff --git a/modules/gdnavigation/register_types.h b/modules/etcpak/register_types.h index c2bb08c649..a9e10a4aae 100644 --- a/modules/gdnavigation/register_types.h +++ b/modules/etcpak/register_types.h @@ -28,14 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -/** - @author AndreaCatania -*/ +#ifndef ETCPAK_REGISTER_TYPES_H +#define ETCPAK_REGISTER_TYPES_H -#ifndef GDNAVIGATION_REGISTER_TYPES_H -#define GDNAVIGATION_REGISTER_TYPES_H +void register_etcpak_types(); +void unregister_etcpak_types(); -void register_gdnavigation_types(); -void unregister_gdnavigation_types(); - -#endif // GDNAVIGATION_REGISTER_TYPES_H +#endif // ETCPAK_REGISTER_TYPES_H diff --git a/modules/fbx/README.md b/modules/fbx/README.md index 2a2f186463..8eca4bd3c9 100644 --- a/modules/fbx/README.md +++ b/modules/fbx/README.md @@ -15,7 +15,7 @@ functionality. If anything we should give this parser back to assimp at some poi # Updating assimp fbx parser -Don't. it's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed. +Don't. It's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed. Many days were put into rewriting the parser to use safe code and safe memory accessors. @@ -79,23 +79,23 @@ enum RotOrder { // references: ComputePivotTransform / run the calculation // This is the local pivot transform for the node, not the global transforms Transform ComputePivotTransform( - Transform chain[TransformationComp_MAXIMUM], - Transform &geometric_transform) { + Transform3D chain[TransformationComp_MAXIMUM], + Transform3D &geometric_transform) { // Maya pivots - Transform T = chain[TransformationComp_Translation]; - Transform Roff = chain[TransformationComp_RotationOffset]; - Transform Rp = chain[TransformationComp_RotationPivot]; - Transform Rpre = chain[TransformationComp_PreRotation]; - Transform R = chain[TransformationComp_Rotation]; - Transform Rpost = chain[TransformationComp_PostRotation]; - Transform Soff = chain[TransformationComp_ScalingOffset]; - Transform Sp = chain[TransformationComp_ScalingPivot]; - Transform S = chain[TransformationComp_Scaling]; + Transform3D T = chain[TransformationComp_Translation]; + Transform3D Roff = chain[TransformationComp_RotationOffset]; + Transform3D Rp = chain[TransformationComp_RotationPivot]; + Transform3D Rpre = chain[TransformationComp_PreRotation]; + Transform3D R = chain[TransformationComp_Rotation]; + Transform3D Rpost = chain[TransformationComp_PostRotation]; + Transform3D Soff = chain[TransformationComp_ScalingOffset]; + Transform3D Sp = chain[TransformationComp_ScalingPivot]; + Transform3D S = chain[TransformationComp_Scaling]; // 3DS Max Pivots - Transform OT = chain[TransformationComp_GeometricTranslation]; - Transform OR = chain[TransformationComp_GeometricRotation]; - Transform OS = chain[TransformationComp_GeometricScaling]; + Transform3D OT = chain[TransformationComp_GeometricTranslation]; + Transform3D OR = chain[TransformationComp_GeometricRotation]; + Transform3D OS = chain[TransformationComp_GeometricScaling]; // Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node) geometric_transform = OT * OR * OS; diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub index 84220a66fa..0311fddfee 100644 --- a/modules/fbx/SCsub +++ b/modules/fbx/SCsub @@ -8,6 +8,9 @@ env_fbx = env_modules.Clone() # Make includes relative to the folder path specified here so our includes are clean env_fbx.Prepend(CPPPATH=["#modules/fbx/"]) +if env["builtin_zlib"]: + env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"]) + # Godot's own source files env_fbx.add_source_files(env.modules_sources, "tools/*.cpp") env_fbx.add_source_files(env.modules_sources, "data/*.cpp") diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h index efba147b89..83918ad1e2 100644 --- a/modules/fbx/data/fbx_bone.h +++ b/modules/fbx/data/fbx_bone.h @@ -38,7 +38,7 @@ struct PivotTransform; -struct FBXBone : public Reference { +struct FBXBone : public RefCounted { uint64_t parent_bone_id = 0; uint64_t bone_id = 0; diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp index 5995097b2f..fb6c67f7b9 100644 --- a/modules/fbx/data/fbx_material.cpp +++ b/modules/fbx/data/fbx_material.cpp @@ -29,6 +29,10 @@ /*************************************************************************/ #include "fbx_material.h" + +// FIXME: Shouldn't depend on core_bind.h! Use DirAccessRef like the rest of +// the engine instead of _Directory. +#include "core/core_bind.h" #include "scene/resources/material.h" #include "scene/resources/texture.h" #include "tools/validation_tools.h" @@ -160,7 +164,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { const String p_fbx_current_directory = state.path; Ref<StandardMaterial3D> spatial_material; - spatial_material.instance(); + spatial_material.instantiate(); // read the material file // is material two sided @@ -223,7 +227,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } else if (fbx_texture_data != nullptr && fbx_texture_data->Media() != nullptr && fbx_texture_data->Media()->IsEmbedded()) { // This is an embedded texture. Extract it. Ref<Image> image; - //image.instance(); // oooo double instance bug? why make Image::_png_blah call + //image.instantiate(); // oooo double instance bug? why make Image::_png_blah call const String extension = texture_name.get_extension().to_upper(); if (extension == "PNG") { @@ -256,7 +260,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } Ref<ImageTexture> image_texture; - image_texture.instance(); + image_texture.instantiate(); image_texture->create_from_image(image); texture = image_texture; @@ -277,7 +281,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } /// ALL below is related to properties - for (FBXDocParser::LazyPropertyMap::value_type iter : material->Props()->GetLazyProperties()) { + for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) { const std::string name = iter.first; if (name.empty()) { @@ -317,14 +321,14 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it."); - const FBXDocParser::PropertyTable *tbl = material->Props(); + const FBXDocParser::PropertyTable *tbl = material; FBXDocParser::PropertyPtr prop = tbl->Get(name); ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str())); if (spatial_material.is_null()) { // Done here so if no data no material is created. - spatial_material.instance(); + spatial_material.instantiate(); } const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop); @@ -420,7 +424,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } break; case PROPERTY_DESC_COAT_ROUGHNESS: { // meaning is that approx equal to zero is disabled not actually zero. ;) - if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) { + if (real_value && Math::is_zero_approx(real_value->Value())) { print_verbose("clearcoat real value: " + rtos(real_value->Value())); spatial_material->set_clearcoat_gloss(1.0 - real_value->Value()); } else { @@ -428,7 +432,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } } break; case PROPERTY_DESC_EMISSIVE: { - if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) { + if (real_value && Math::is_zero_approx(real_value->Value())) { print_verbose("Emissive real value: " + rtos(real_value->Value())); spatial_material->set_emission_energy(real_value->Value()); } else if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) { diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h index 23310b8e1d..5fd4d9212b 100644 --- a/modules/fbx/data/fbx_material.h +++ b/modules/fbx/data/fbx_material.h @@ -33,10 +33,10 @@ #include "tools/import_utils.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" -struct FBXMaterial : public Reference { +struct FBXMaterial : public RefCounted { String material_name = String(); bool warning_non_pbr_material = false; FBXDocParser::Material *material = nullptr; @@ -266,7 +266,7 @@ struct FBXMaterial : public Reference { /* storing the texture properties like color */ template <class T> - struct TexturePropertyMapping : Reference { + struct TexturePropertyMapping : RefCounted { StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO; const T property = T(); }; diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index b088dd8640..0d33b8e7c6 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -101,20 +101,6 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash return collection; } -typedef int Vertex; -typedef int SurfaceId; -typedef int PolygonId; -typedef int DataIndex; - -struct SurfaceData { - Ref<SurfaceTool> surface_tool; - OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index. - LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation. - Ref<Material> material; - HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex; - Array morphs; -}; - EditorSceneImporterMeshNode3D *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. @@ -225,7 +211,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s const int surface_id = polygon_surfaces[*polygon_id]; if (surfaces.has(surface_id) == false) { SurfaceData sd; - sd.surface_tool.instance(); + sd.surface_tool.instantiate(); sd.surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); if (surface_id < 0) { @@ -307,11 +293,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s // Triangulate the various polygons and add the indices. for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) { const Vector<DataIndex> *indices = surface->surface_polygon_vertex.getptr(*polygon_id); - triangulate_polygon( - surface->surface_tool, + surface, *indices, - surface->vertices_map, vertices); } } @@ -332,11 +316,11 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s Vector3 *normals_ptr = morph_data->normals.ptrw(); Ref<SurfaceTool> morph_st; - morph_st.instance(); + morph_st.instantiate(); morph_st->begin(Mesh::PRIMITIVE_TRIANGLES); for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) { - const Vertex vertex = surface->vertices_map[vi]; + const Vertex &vertex = surface->vertices_map[vi]; add_vertex( state, morph_st, @@ -361,7 +345,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s // Phase 6. Compose the mesh and return it. Ref<EditorSceneImporterMesh> mesh; - mesh.instance(); + mesh.instantiate(); // Add blend shape info. for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { @@ -398,6 +382,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D); godot_mesh->set_mesh(mesh); + const String name = ImportUtils::FBXNodeToName(model->Name()); + godot_mesh->set_name(name); // hurry up compiling >.< + mesh->set_name("mesh3d-" + name); return godot_mesh; } @@ -816,8 +803,10 @@ void FBXMeshData::add_vertex( p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale); } -void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, const Vector<Vertex> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const { +void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const { + Ref<SurfaceTool> st(surface->surface_tool); const int polygon_vertex_count = p_polygon_vertex.size(); + //const Vector<Vertex>& p_surface_vertex_map if (polygon_vertex_count == 1) { // point to triangle st->add_index(p_polygon_vertex[0]); @@ -856,9 +845,9 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon is_simple_convex = true; Vector3 first_vec; for (int i = 0; i < polygon_vertex_count; i += 1) { - const Vector3 p1 = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]]; - const Vector3 p2 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]]; - const Vector3 p3 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]]; + const Vector3 p1 = p_vertices[surface->vertices_map[p_polygon_vertex[i]]]; + const Vector3 p2 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]]; + const Vector3 p3 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]]; const Vector3 edge1 = p1 - p2; const Vector3 edge2 = p3 - p2; @@ -893,7 +882,7 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon std::vector<Vector3> poly_vertices(polygon_vertex_count); for (int i = 0; i < polygon_vertex_count; i += 1) { - poly_vertices[i] = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]]; + poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]]; } const Vector3 poly_norm = get_poly_normal(poly_vertices); @@ -956,7 +945,7 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { TPPLPoly &tp = I->get(); - ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator retuned more points, how this is possible?"); + ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator returned more points, how this is possible?"); // Find Index for (int i = 2; i >= 0; i -= 1) { const Vector2 vertex = tp.GetPoint(i); @@ -1137,8 +1126,8 @@ HashMap<int, R> FBXMeshData::extract_per_vertex_data( } const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR8"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9."); - ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10."); + ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9."); + ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10."); ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] >= (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR11."); aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[p_mapping_data.index[polygon_vertex_index]] }); } diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h index 77510ff2ec..7486c5c59c 100644 --- a/modules/fbx/data/fbx_mesh_data.h +++ b/modules/fbx/data/fbx_mesh_data.h @@ -32,6 +32,8 @@ #define FBX_MESH_DATA_H #include "core/templates/hash_map.h" +#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/mesh_instance_3d.h" @@ -47,6 +49,20 @@ struct FBXMeshData; struct FBXBone; struct ImportState; +typedef int Vertex; +typedef int SurfaceId; +typedef int PolygonId; +typedef int DataIndex; + +struct SurfaceData { + Ref<SurfaceTool> surface_tool; + OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index. + LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation. + Ref<Material> material; + HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex; + Array morphs; +}; + struct VertexWeightMapping { Vector<real_t> weights; Vector<int> bones; @@ -62,7 +78,7 @@ struct VertexData { }; // Caches mesh information and instantiates meshes for you using helper functions. -struct FBXMeshData : Reference { +struct FBXMeshData : RefCounted { struct MorphVertexData { // TODO we have only these?? /// Each element is a vertex. Not supposed to be void. @@ -127,7 +143,7 @@ private: const Vector3 &p_morph_value = Vector3(), const Vector3 &p_morph_normal = Vector3()); - void triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const; + void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const; /// This function is responsible to convert the FBX polygon vertex to /// vertex index. @@ -140,7 +156,7 @@ private: /// [0, 2, 1, 3, 4] /// The negative values are computed using this formula: `(-value) - 1` /// - /// Returns the vertex index from the poligon vertex. + /// Returns the vertex index from the polygon vertex. /// Returns -1 if `p_index` is invalid. int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const; diff --git a/modules/fbx/data/fbx_node.h b/modules/fbx/data/fbx_node.h index a6f62f3388..75461e397d 100644 --- a/modules/fbx/data/fbx_node.h +++ b/modules/fbx/data/fbx_node.h @@ -40,7 +40,7 @@ class Node3D; struct PivotTransform; -struct FBXNode : Reference, ModelAbstraction { +struct FBXNode : RefCounted, ModelAbstraction { uint64_t current_node_id = 0; String node_name = String(); Node3D *godot_node = nullptr; diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp index 622b589feb..1ac4922acf 100644 --- a/modules/fbx/data/fbx_skeleton.cpp +++ b/modules/fbx/data/fbx_skeleton.cpp @@ -69,7 +69,7 @@ void FBXSkeleton::init_skeleton(const ImportState &state) { // Make sure the bone name is unique. const String bone_name = bone->bone_name; int same_name_count = 0; - for (int y = x; y < skeleton_bone_count; y++) { + for (int y = x + 1; y < skeleton_bone_count; y++) { Ref<FBXBone> other_bone = skeleton_bones[y]; if (other_bone.is_valid()) { if (other_bone->bone_name == bone_name) { diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h index df937cde49..b6103df949 100644 --- a/modules/fbx/data/fbx_skeleton.h +++ b/modules/fbx/data/fbx_skeleton.h @@ -35,14 +35,14 @@ #include "fbx_node.h" #include "model_abstraction.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "scene/3d/skeleton_3d.h" struct FBXNode; struct ImportState; struct FBXBone; -struct FBXSkeleton : Reference { +struct FBXSkeleton : RefCounted { Ref<FBXNode> fbx_node = Ref<FBXNode>(); Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>(); Skeleton3D *skeleton = nullptr; diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h index 83bc43faff..9ba60eaacf 100644 --- a/modules/fbx/data/import_state.h +++ b/modules/fbx/data/import_state.h @@ -37,7 +37,6 @@ #include "pivot_transform.h" -#include "core/core_bind.h" #include "core/io/resource_importer.h" #include "core/templates/vector.h" #include "editor/import/resource_importer_scene.h" diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp index 1895af6f9f..4cf42257a4 100644 --- a/modules/fbx/data/pivot_transform.cpp +++ b/modules/fbx/data/pivot_transform.cpp @@ -33,7 +33,7 @@ #include "tools/import_utils.h" void PivotTransform::ReadTransformChain() { - const FBXDocParser::PropertyTable *props = fbx_model->Props(); + const FBXDocParser::PropertyTable *props = fbx_model; const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder(); const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType(); inherit_type = inheritType; // copy the inherit type we need it in the second step. @@ -90,7 +90,7 @@ void PivotTransform::ReadTransformChain() { if (ok) { geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation)); } else { - geometric_rotation = Quat(); + geometric_rotation = Quaternion(); } const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok)); @@ -100,7 +100,7 @@ void PivotTransform::ReadTransformChain() { geometric_translation = Vector3(0, 0, 0); } - if (geometric_rotation != Quat()) { + if (geometric_rotation != Quaternion()) { print_error("geometric rotation is unsupported!"); //CRASH_COND(true); } @@ -116,8 +116,8 @@ void PivotTransform::ReadTransformChain() { } } -Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const { - Transform T, Roff, Rp, Soff, Sp, S; +Transform3D PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const { + Transform3D T, Roff, Rp, Soff, Sp, S; // Here I assume this is the operation which needs done. // Its WorldTransform * V @@ -132,29 +132,29 @@ Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_ro // Scaling node S.scale(p_scaling); // Rotation pivots - Transform Rpre = Transform(pre_rotation); - Transform R = Transform(p_rotation); - Transform Rpost = Transform(post_rotation); + Transform3D Rpre = Transform3D(pre_rotation); + Transform3D R = Transform3D(p_rotation); + Transform3D Rpost = Transform3D(post_rotation); return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); } -Transform PivotTransform::ComputeGlobalTransform(Transform t) const { +Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const { Vector3 pos = t.origin; Vector3 scale = t.basis.get_scale(); - Quat rot = t.basis.get_rotation_quat(); + Quaternion rot = t.basis.get_rotation_quaternion(); return ComputeGlobalTransform(pos, rot, scale); } -Transform PivotTransform::ComputeLocalTransform(Transform t) const { +Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const { Vector3 pos = t.origin; Vector3 scale = t.basis.get_scale(); - Quat rot = t.basis.get_rotation_quat(); + Quaternion rot = t.basis.get_rotation_quaternion(); return ComputeLocalTransform(pos, rot, scale); } -Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const { - Transform T, Roff, Rp, Soff, Sp, S; +Transform3D PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const { + Transform3D T, Roff, Rp, Soff, Sp, S; // Here I assume this is the operation which needs done. // Its WorldTransform * V @@ -170,26 +170,26 @@ Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_r S.scale(p_scaling); // Rotation pivots - Transform Rpre = Transform(pre_rotation); - Transform R = Transform(p_rotation); - Transform Rpost = Transform(post_rotation); + Transform3D Rpre = Transform3D(pre_rotation); + Transform3D R = Transform3D(p_rotation); + Transform3D Rpost = Transform3D(post_rotation); - Transform parent_global_xform; - Transform parent_local_scaling_m; + Transform3D parent_global_xform; + Transform3D parent_local_scaling_m; if (parent_transform.is_valid()) { parent_global_xform = parent_transform->GlobalTransform; parent_local_scaling_m = parent_transform->Local_Scaling_Matrix; } - Transform local_rotation_m, parent_global_rotation_m; - Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat(); - parent_global_rotation_m.basis.set_quat(parent_global_rotation); + Transform3D local_rotation_m, parent_global_rotation_m; + Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion(); + parent_global_rotation_m.basis.set_quaternion(parent_global_rotation); local_rotation_m = Rpre * R * Rpost; - //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized()); + //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized()); - Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; + Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; Vector3 parent_translation = parent_global_xform.get_origin(); parent_shear_translation.origin = parent_translation; parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform; @@ -197,26 +197,26 @@ Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_r local_shear_scaling = S; // Inherit type handler - we don't care about T here, just reordering RSrs etc. - Transform global_rotation_scale; + Transform3D global_rotation_scale; if (inherit_type == FBXDocParser::Transform_RrSs) { global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_RSrs) { global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_Rrs) { - Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse(); + Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse(); global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling; } - Transform local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); - //Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin); + Transform3D local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); + //Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); - ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform(), "Det == 0 prevented in scene file"); + ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform3D(), "Det == 0 prevented in scene file"); // manual hack to force SSC not to be compensated for - until we can handle it properly with tests return parent_global_xform * local_transform; } void PivotTransform::ComputePivotTransform() { - Transform T, Roff, Rp, Soff, Sp, S; + Transform3D T, Roff, Rp, Soff, Sp, S; // Here I assume this is the operation which needs done. // Its WorldTransform * V @@ -237,26 +237,26 @@ void PivotTransform::ComputePivotTransform() { Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this. // Rotation pivots - Transform Rpre = Transform(pre_rotation); - Transform R = Transform(rotation); - Transform Rpost = Transform(post_rotation); + Transform3D Rpre = Transform3D(pre_rotation); + Transform3D R = Transform3D(rotation); + Transform3D Rpost = Transform3D(post_rotation); - Transform parent_global_xform; - Transform parent_local_scaling_m; + Transform3D parent_global_xform; + Transform3D parent_local_scaling_m; if (parent_transform.is_valid()) { parent_global_xform = parent_transform->GlobalTransform; parent_local_scaling_m = parent_transform->Local_Scaling_Matrix; } - Transform local_rotation_m, parent_global_rotation_m; - Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat(); - parent_global_rotation_m.basis.set_quat(parent_global_rotation); + Transform3D local_rotation_m, parent_global_rotation_m; + Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion(); + parent_global_rotation_m.basis.set_quaternion(parent_global_rotation); local_rotation_m = Rpre * R * Rpost; - //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized()); + //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized()); - Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; + Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; Vector3 parent_translation = parent_global_xform.get_origin(); parent_shear_translation.origin = parent_translation; parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform; @@ -264,24 +264,24 @@ void PivotTransform::ComputePivotTransform() { local_shear_scaling = S; // Inherit type handler - we don't care about T here, just reordering RSrs etc. - Transform global_rotation_scale; + Transform3D global_rotation_scale; if (inherit_type == FBXDocParser::Transform_RrSs) { global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_RSrs) { global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_Rrs) { - Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse(); + Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse(); global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling; } - LocalTransform = Transform(); + LocalTransform = Transform3D(); LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset"); - Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin); - GlobalTransform = Transform(); + Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); + GlobalTransform = Transform3D(); //GlobalTransform = parent_global_xform * LocalTransform; - Transform global_origin = Transform(Basis(), parent_translation); + Transform3D global_origin = Transform3D(Basis(), parent_translation); GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale; ImportUtils::debug_xform("local xform calculation", LocalTransform); diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h index 9996027870..099b268075 100644 --- a/modules/fbx/data/pivot_transform.h +++ b/modules/fbx/data/pivot_transform.h @@ -31,8 +31,8 @@ #ifndef PIVOT_TRANSFORM_H #define PIVOT_TRANSFORM_H -#include "core/math/transform.h" -#include "core/object/reference.h" +#include "core/math/transform_3d.h" +#include "core/object/ref_counted.h" #include "model_abstraction.h" @@ -55,13 +55,13 @@ enum TransformationComp { TransformationComp_MAXIMUM }; // Abstract away pivot data so its simpler to handle -struct PivotTransform : Reference, ModelAbstraction { +struct PivotTransform : RefCounted, ModelAbstraction { // at the end we want to keep geometric_ everything, post and pre rotation // these are used during animation data processing / keyframe ingestion the rest can be simplified down / out. - Quat pre_rotation = Quat(); - Quat post_rotation = Quat(); - Quat rotation = Quat(); - Quat geometric_rotation = Quat(); + Quaternion pre_rotation = Quaternion(); + Quaternion post_rotation = Quaternion(); + Quaternion rotation = Quaternion(); + Quaternion geometric_rotation = Quaternion(); Vector3 rotation_pivot = Vector3(); Vector3 rotation_offset = Vector3(); Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0); @@ -85,10 +85,10 @@ struct PivotTransform : Reference, ModelAbstraction { print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI)); } - Transform ComputeGlobalTransform(Transform t) const; - Transform ComputeLocalTransform(Transform t) const; - Transform ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const; - Transform ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const; + Transform3D ComputeGlobalTransform(Transform3D t) const; + Transform3D ComputeLocalTransform(Transform3D t) const; + Transform3D ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const; + Transform3D ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const; /* Extract into xforms and calculate once */ void ComputePivotTransform(); @@ -105,10 +105,10 @@ struct PivotTransform : Reference, ModelAbstraction { //Transform chain[TransformationComp_MAXIMUM]; // cached for later use - Transform GlobalTransform = Transform(); - Transform LocalTransform = Transform(); - Transform Local_Scaling_Matrix = Transform(); // used for inherit type. - Transform GeometricTransform = Transform(); // 3DS max only + Transform3D GlobalTransform = Transform3D(); + Transform3D LocalTransform = Transform3D(); + Transform3D Local_Scaling_Matrix = Transform3D(); // used for inherit type. + Transform3D GeometricTransform = Transform3D(); // 3DS max only FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3 }; diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index e18ebe3930..e3f36ef3e3 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -44,7 +44,6 @@ #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/light_3d.h" -#include "scene/3d/mesh_instance_3d.h" #include "scene/main/node.h" #include "scene/resources/material.h" @@ -94,7 +93,7 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl Error err; FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - ERR_FAIL_COND_V(!f, NULL); + ERR_FAIL_COND_V(!f, nullptr); { PackedByteArray data; @@ -103,7 +102,10 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl FBXDocParser::TokenList tokens; bool is_binary = false; - data.resize(f->get_len()); + data.resize(f->get_length()); + + ERR_FAIL_COND_V(data.size() < 64, nullptr); + f->get_buffer(data.ptrw(), data.size()); PackedByteArray fbx_header; fbx_header.resize(64); @@ -118,15 +120,27 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl print_verbose("[doc] opening fbx file: " + p_path); print_verbose("[doc] fbx header: " + fbx_header_string); + bool corrupt = false; // safer to check this way as there can be different formatted headers if (fbx_header_string.find("Kaydara FBX Binary", 0) != -1) { is_binary = true; print_verbose("[doc] is binary"); - FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size()); + + FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt); + } else { print_verbose("[doc] is ascii"); - FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size()); + FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt); + } + + if (corrupt) { + for (FBXDocParser::TokenPtr token : tokens) { + delete token; + } + tokens.clear(); + ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path)); + return memnew(Node3D); } // The import process explained: @@ -138,6 +152,16 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl // use this information to construct a very rudimentary // parse-tree representing the FBX scope structure FBXDocParser::Parser parser(tokens, is_binary); + + if (parser.IsCorrupt()) { + for (FBXDocParser::TokenPtr token : tokens) { + delete token; + } + tokens.clear(); + ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path)); + return memnew(Node3D); + } + FBXDocParser::ImportSettings settings; settings.strictMode = false; @@ -150,12 +174,10 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl // safety for version handling if (doc.IsSafeToImport()) { bool is_blender_fbx = false; - //const FBXDocParser::PropertyPtr app_vendor = p_document->GlobalSettingsPtr()->Props() - // p_document->Creator() - const FBXDocParser::PropertyTable *import_props = doc.GetMetadataProperties(); - const FBXDocParser::PropertyPtr app_name = import_props->Get("Original|ApplicationName"); - const FBXDocParser::PropertyPtr app_vendor = import_props->Get("Original|ApplicationVendor"); - const FBXDocParser::PropertyPtr app_version = import_props->Get("Original|ApplicationVersion"); + const FBXDocParser::PropertyTable &import_props = doc.GetMetadataProperties(); + const FBXDocParser::PropertyPtr app_name = import_props.Get("Original|ApplicationName"); + const FBXDocParser::PropertyPtr app_vendor = import_props.Get("Original|ApplicationVendor"); + const FBXDocParser::PropertyPtr app_version = import_props.Get("Original|ApplicationVersion"); // if (app_name) { const FBXDocParser::TypedProperty<std::string> *app_name_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_name); @@ -197,6 +219,11 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl return spatial; } else { + for (FBXDocParser::TokenPtr token : tokens) { + delete token; + } + tokens.clear(); + ERR_PRINT(vformat("Cannot import FBX file: %s. It uses file format %d which is unsupported by Godot. Please re-export it or convert it to a newer format.", p_path, doc.FBXVersion())); } } @@ -231,24 +258,24 @@ struct EditorSceneImporterAssetImportInterpolate { //thank you for existing, partial specialization template <> -struct EditorSceneImporterAssetImportInterpolate<Quat> { - Quat lerp(const Quat &a, const Quat &b, float c) const { - ERR_FAIL_COND_V(!a.is_normalized(), Quat()); - ERR_FAIL_COND_V(!b.is_normalized(), Quat()); +struct EditorSceneImporterAssetImportInterpolate<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()); return a.slerp(b, c).normalized(); } - Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) { - ERR_FAIL_COND_V(!p1.is_normalized(), Quat()); - ERR_FAIL_COND_V(!p2.is_normalized(), Quat()); + Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, float c) { + ERR_FAIL_COND_V(!p1.is_normalized(), Quaternion()); + ERR_FAIL_COND_V(!p2.is_normalized(), Quaternion()); return p1.slerp(p2, c).normalized(); } - Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) { - ERR_FAIL_COND_V(!start.is_normalized(), Quat()); - ERR_FAIL_COND_V(!end.is_normalized(), Quat()); + Quaternion bezier(Quaternion start, Quaternion control_1, Quaternion control_2, Quaternion end, float t) { + ERR_FAIL_COND_V(!start.is_normalized(), Quaternion()); + ERR_FAIL_COND_V(!end.is_normalized(), Quaternion()); return start.slerp(end, t).normalized(); } @@ -260,8 +287,9 @@ T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const //could use binary search, worth it? int idx = -1; for (int i = 0; i < p_times.size(); i++) { - if (p_times[i] > p_time) + if (p_times[i] > p_time) { break; + } idx++; } @@ -334,7 +362,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( ImportState state; state.is_blender_fbx = p_is_blender_fbx; state.path = p_path; - state.animation_player = NULL; + state.animation_player = nullptr; // create new root node for scene Node3D *scene_root = memnew(Node3D); @@ -345,7 +373,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( scene_root->add_child(state.root); state.root->set_owner(scene_root); - state.fbx_root_node.instance(); + state.fbx_root_node.instantiate(); state.fbx_root_node->godot_node = state.root; // Size relative to cm. @@ -361,11 +389,11 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // Enabled by default. state.enable_animation_import = true; Ref<FBXNode> root_node; - root_node.instance(); + root_node.instantiate(); // make sure fake noFBXDocParser::PropertyPtr ptrde always has a transform too ;) Ref<PivotTransform> pivot_transform; - pivot_transform.instance(); + pivot_transform.instantiate(); root_node->pivot_transform = pivot_transform; root_node->node_name = "root node"; root_node->current_node_id = 0; @@ -451,7 +479,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( if (state.renderer_mesh_data.has(mesh_id)) { mesh_vertex_data = state.renderer_mesh_data[mesh_id]; } else { - mesh_vertex_data.instance(); + mesh_vertex_data.instantiate(); state.renderer_mesh_data.insert(mesh_id, mesh_vertex_data); } @@ -507,7 +535,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( ERR_CONTINUE_MSG(!mat, "Could not convert fbx material by id: " + itos(material_id)); Ref<FBXMaterial> material; - material.instance(); + material.instantiate(); material->set_imported_material(mat); Ref<StandardMaterial3D> godot_material = material->import_material(state); @@ -547,7 +575,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( if (state.skeleton_map.has(armature_id)) { fbx_skeleton_inst = state.skeleton_map[armature_id]; } else { - fbx_skeleton_inst.instance(); + fbx_skeleton_inst.instantiate(); state.skeleton_map.insert(armature_id, fbx_skeleton_inst); } @@ -610,8 +638,9 @@ Node3D *EditorSceneImporterFBX::_generate_scene( for (const FBXDocParser::Geometry *mesh : geometry) { print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name); - if (mesh == nullptr) + if (mesh == nullptr) { continue; + } const FBXDocParser::MeshGeometry *mesh_geometry = dynamic_cast<const FBXDocParser::MeshGeometry *>(mesh); if (mesh_geometry) { @@ -621,14 +650,14 @@ Node3D *EditorSceneImporterFBX::_generate_scene( if (state.renderer_mesh_data.has(mesh_id)) { mesh_data_precached = state.renderer_mesh_data[mesh_id]; } else { - mesh_data_precached.instance(); + mesh_data_precached.instantiate(); state.renderer_mesh_data.insert(mesh_id, mesh_data_precached); } mesh_data_precached->mesh_node = fbx_node; // mesh node, mesh id - mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, 0); + mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, false); if (!state.MeshNodes.has(mesh_id)) { state.MeshNodes.insert(mesh_id, fbx_node); } @@ -706,7 +735,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( Ref<Skin> skin; if (!state.MeshSkins.has(mesh_id)) { print_verbose("Created new skin"); - skin.instance(); + skin.instantiate(); state.MeshSkins.insert(mesh_id, skin); } else { print_verbose("Grabbed skin"); @@ -819,7 +848,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } Ref<Animation> animation; - animation.instance(); + animation.instantiate(); animation->set_name(animation_name); animation->set_length(duration); @@ -859,7 +888,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // we need to know what object the curves are for. // we need the target ID and the target name for the track reduction. - FBXDocParser::Model::RotOrder quat_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ; + FBXDocParser::Model::RotOrder quaternion_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ; // T:: R:: S:: Visible:: Custom:: for (const FBXDocParser::AnimationCurveNode *curve_node : node_list) { @@ -881,13 +910,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene( continue; } else { //print_verbose("[doc] applied rotation order: " + itos(target->RotationOrder())); - quat_rotation_order = target->RotationOrder(); + quaternion_rotation_order = target->RotationOrder(); } uint64_t target_id = target->ID(); String target_name = ImportUtils::FBXNodeToName(target->Name()); - const FBXDocParser::PropertyTable *properties = curve_node->Props(); + const FBXDocParser::PropertyTable *properties = curve_node; bool got_x = false, got_y = false, got_z = false; float offset_x = FBXDocParser::PropertyGet<float>(properties, "d|X", got_x); float offset_y = FBXDocParser::PropertyGet<float>(properties, "d|Y", got_y); @@ -982,10 +1011,9 @@ 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_TRANSFORM); + int track_idx = animation->add_track(Animation::TYPE_TRANSFORM3D); // animation->track_set_path(track_idx, node_path); - // 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. @@ -995,7 +1023,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( bone = state.fbx_bone_map[target_id]; } - Transform target_transform; + Transform3D target_transform; if (state.fbx_target_map.has(target_id)) { Ref<FBXNode> node_ref = state.fbx_target_map[target_id]; @@ -1028,7 +1056,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( //print_verbose("[doc] node animation path: " + node_path); } } else { - // note: this could actually be unsafe this means we should be careful about continuing here, if we see bizzare effects later we should disable this. + // note: this could actually be unsafe this means we should be careful about continuing here, if we see bizarre effects later we should disable this. // I am not sure if this is unsafe or not, testing will tell us this. print_error("[doc] invalid fbx target detected for this track"); continue; @@ -1042,7 +1070,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( Ref<FBXNode> target_node = state.fbx_target_map[target_id]; const FBXDocParser::Model *model = target_node->fbx_model; - const FBXDocParser::PropertyTable *props = model->Props(); + const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model); Map<StringName, FBXTrack> &track_data = track->value(); FBXTrack &translation_keys = track_data[StringName("T")]; @@ -1058,7 +1086,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( Vector<float> pos_times; Vector<Vector3> scale_values; Vector<float> scale_times; - Vector<Quat> rot_values; + Vector<Quaternion> rot_values; Vector<float> rot_times; double max_duration = 0; @@ -1094,8 +1122,8 @@ Node3D *EditorSceneImporterFBX::_generate_scene( bool got_pre = false; bool got_post = false; - Quat post_rotation; - Quat pre_rotation; + Quaternion post_rotation; + Quaternion pre_rotation; // Rotation matrix const Vector3 &PreRotation = FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", got_pre); @@ -1109,24 +1137,24 @@ Node3D *EditorSceneImporterFBX::_generate_scene( post_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PostRotation)); } - Quat lastQuat = Quat(); + Quaternion lastQuaternion = Quaternion(); for (std::pair<int64_t, Vector3> rotation_key : rotation_keys.keyframes) { double animation_track_time = CONVERT_FBX_TIME(rotation_key.first); //print_verbose("euler rotation key: " + rotation_key.second); - Quat rot_key_value = ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_key.second)); + Quaternion rot_key_value = ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_key.second)); - if (lastQuat != Quat() && rot_key_value.dot(lastQuat) < 0) { + if (lastQuaternion != Quaternion() && rot_key_value.dot(lastQuaternion) < 0) { rot_key_value.x = -rot_key_value.x; rot_key_value.y = -rot_key_value.y; rot_key_value.z = -rot_key_value.z; rot_key_value.w = -rot_key_value.w; } // pre_post rotation possibly could fix orientation - Quat final_rotation = pre_rotation * rot_key_value * post_rotation; + Quaternion final_rotation = pre_rotation * rot_key_value * post_rotation; - lastQuat = final_rotation; + lastQuaternion = final_rotation; if (animation_track_time > max_duration) { max_duration = animation_track_time; @@ -1137,7 +1165,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } bool valid_rest = false; - Transform bone_rest; + Transform3D bone_rest; int skeleton_bone = -1; if (state.fbx_bone_map.has(target_id)) { if (bone.is_valid() && bone->fbx_skeleton.is_valid()) { @@ -1154,13 +1182,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } const Vector3 def_pos = translation_keys.has_default ? (translation_keys.default_value * state.scale) : bone_rest.origin; - const Quat def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quat(); + const Quaternion def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quaternion(); 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 + ")"); while (true) { Vector3 pos = def_pos; - Quat rot = def_rot; + Quaternion rot = def_rot; Vector3 scale = def_scale; if (pos_values.size()) { @@ -1169,7 +1197,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } if (rot_values.size()) { - rot = _interpolate_track<Quat>(rot_times, rot_values, time, + rot = _interpolate_track<Quaternion>(rot_times, rot_values, time, AssetImportAnimation::INTERP_LINEAR); } @@ -1180,13 +1208,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // node animations must also include pivots if (skeleton_bone >= 0) { - Transform xform = Transform(); - xform.basis.set_quat_scale(rot, scale); + Transform3D xform = Transform3D(); + xform.basis.set_quaternion_scale(rot, scale); xform.origin = pos; - const Transform t = bone_rest.affine_inverse() * xform; + const Transform3D t = bone_rest.affine_inverse() * xform; // populate this again - rot = t.basis.get_rotation_quat(); + rot = t.basis.get_rotation_quaternion(); rot.normalize(); scale = t.basis.get_scale(); pos = t.origin; @@ -1284,7 +1312,7 @@ void EditorSceneImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone, // declare our bone element reference (invalid, unless we create a bone in this step) // this lets us pass valid armature information into children objects and this is why we moved this up here - // previously this was created .instanced() on the same line. + // previously this was created .instantiated() on the same line. Ref<FBXBone> bone_element; if (model != nullptr) { @@ -1296,7 +1324,7 @@ void EditorSceneImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone, ERR_FAIL_COND_MSG(state.fbx_bone_map.has(limb_node->ID()), "[serious] duplicate LimbNode detected"); bool parent_is_bone = state.fbx_bone_map.find(p_id); - bone_element.instance(); + bone_element.instantiate(); // used to build the bone hierarchy in the skeleton bone_element->parent_bone_id = parent_is_bone ? p_id : 0; @@ -1376,12 +1404,12 @@ void EditorSceneImporterFBX::BuildDocumentNodes( uint64_t current_node_id = model->ID(); Ref<FBXNode> new_node; - new_node.instance(); + new_node.instantiate(); new_node->current_node_id = current_node_id; new_node->node_name = ImportUtils::FBXNodeToName(model->Name()); Ref<PivotTransform> fbx_transform; - fbx_transform.instance(); + fbx_transform.instantiate(); fbx_transform->set_parent(parent_transform); fbx_transform->set_model(model); fbx_transform->debug_pivot_xform("name: " + new_node->node_name); diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h index 39f8648b0f..4a3b78480b 100644 --- a/modules/fbx/editor_scene_importer_fbx.h +++ b/modules/fbx/editor_scene_importer_fbx.h @@ -36,7 +36,6 @@ #include "data/import_state.h" #include "tools/import_utils.h" -#include "core/core_bind.h" #include "core/io/resource_importer.h" #include "core/string/ustring.h" #include "core/templates/local_vector.h" @@ -128,7 +127,7 @@ public: virtual void get_extensions(List<String> *r_extensions) const override; virtual uint32_t get_import_flags() const override; - virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) override; + virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; #endif // TOOLS_ENABLED diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h index f759c9117c..5c16383974 100644 --- a/modules/fbx/fbx_parser/ByteSwapper.h +++ b/modules/fbx/fbx_parser/ByteSwapper.h @@ -264,8 +264,9 @@ struct Getter { le = !le; if (le) { ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout); - } else + } else { ByteSwapper<T, false>()(inout); + } } }; diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp index b11e2c7f55..0fbff035fd 100644 --- a/modules/fbx/fbx_parser/FBXAnimation.cpp +++ b/modules/fbx/fbx_parser/FBXAnimation.cpp @@ -128,11 +128,9 @@ AnimationCurve::~AnimationCurve() { // ------------------------------------------------------------------------------------------------ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name, - const Document &doc, const char *const *target_prop_whitelist /*= NULL*/, + const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/, size_t whitelist_size /*= 0*/) : Object(id, element, name), target(), doc(doc) { - const ScopePtr sc = GetRequiredScope(element); - // find target node const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" }; const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3); @@ -154,8 +152,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co prop = con->PropertyName(); break; } - - props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false); } // ------------------------------------------------------------------------------------------------ @@ -187,10 +183,6 @@ const AnimationMap &AnimationCurveNode::Curves() const { // ------------------------------------------------------------------------------------------------ AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : Object(id, element, name), doc(doc) { - const ScopePtr sc = GetRequiredScope(element); - - // note: the props table here bears little importance and is usually absent - props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true); } // ------------------------------------------------------------------------------------------------ @@ -248,11 +240,6 @@ const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_pro // ------------------------------------------------------------------------------------------------ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - - // note: we don't currently use any of these properties so we shouldn't bother if it is missing - props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true); - // resolve attached animation layers const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer"); layers.reserve(conns.size()); @@ -282,9 +269,5 @@ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std: // ------------------------------------------------------------------------------------------------ AnimationStack::~AnimationStack() { - if (props != nullptr) { - delete props; - props = nullptr; - } } } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp index 1d2b7765c5..1eee10b251 100644 --- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp +++ b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp @@ -130,6 +130,7 @@ Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset line(offset), column(BINARY_MARKER) { #ifdef DEBUG_ENABLED + // contents is bad.. :/ contents = std::string(sbegin, static_cast<size_t>(send - sbegin)); #endif // calc length @@ -232,9 +233,11 @@ unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const ch } // ------------------------------------------------------------------------------------------------ -void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) { +void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) { if (Offset(cursor, end) < 1) { TokenizeError("cannot ReadData, out of bounds reading length", input, cursor); + corrupt = true; + return; } const char type = *cursor; @@ -328,9 +331,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, } cursor += comp_len; break; - } - - // string + } // string case 'S': { const char *sb, *se; // 0 characters can legally happen in such strings @@ -338,11 +339,15 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, break; } default: + corrupt = true; // must exit TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor); + return; } if (cursor > end) { + corrupt = true; // must exit TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor); + return; } // the type code is contained in the returned range @@ -350,7 +355,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, } // ------------------------------------------------------------------------------------------------ -bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) { +bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) { // the first word contains the offset at which this block ends const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); @@ -364,8 +369,12 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, if (end_offset > Offset(input, end)) { TokenizeError("block offset is out of range", input, cursor); + corrupt = true; + return false; } else if (end_offset < Offset(input, cursor)) { TokenizeError("block offset is negative out of range", input, cursor); + corrupt = true; + return false; } // the second data word contains the number of properties in the scope @@ -375,7 +384,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // now comes the name of the scope/key - const char *sbeg, *send; + const char *sbeg = nullptr, *send = nullptr; ReadString(sbeg, send, input, cursor, end); output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor))); @@ -383,7 +392,10 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, // now come the individual properties const char *begin_cursor = cursor; for (unsigned int i = 0; i < prop_count; ++i) { - ReadData(sbeg, send, input, cursor, begin_cursor + prop_length); + ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt); + if (corrupt) { + return false; + } output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor))); @@ -394,6 +406,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, if (Offset(begin_cursor, cursor) != prop_length) { TokenizeError("property length not reached, something is wrong", input, cursor); + corrupt = true; + return false; } // at the end of each nested block, there is a NUL record to indicate @@ -410,13 +424,18 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, // XXX this is vulnerable to stack overflowing .. while (Offset(input, cursor) < end_offset - sentinel_block_length) { - ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); + ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt); + if (corrupt) { + return false; + } } output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor))); for (unsigned int i = 0; i < sentinel_block_length; ++i) { if (cursor[i] != '\0') { TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor); + corrupt = true; + return false; } } cursor += sentinel_block_length; @@ -424,6 +443,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, if (Offset(input, cursor) != end_offset) { TokenizeError("scope length not reached, something is wrong", input, cursor); + corrupt = true; + return false; } return true; @@ -432,7 +453,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, // ------------------------------------------------------------------------------------------------ // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent -void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) { +void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) { if (length < 0x1b) { //TokenizeError("file is too short",0); } @@ -459,7 +480,7 @@ void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) const bool is64bits = version >= 7500; const char *end = input + length; while (cursor < end) { - if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { + if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) { break; } } diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp index 4b774e6b2a..4220ba62a7 100644 --- a/modules/fbx/fbx_parser/FBXDeformer.cpp +++ b/modules/fbx/fbx_parser/FBXDeformer.cpp @@ -78,7 +78,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXMeshGeometry.h" #include "FBXParser.h" #include "core/math/math_funcs.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include <iostream> @@ -89,10 +89,6 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - - const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2)); - props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true); } // ------------------------------------------------------------------------------------------------ @@ -101,10 +97,6 @@ Deformer::~Deformer() { Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2)); - // used something.fbx as this is a cache name. - props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true); } Constraint::~Constraint() { diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp index bcf7fa1565..89c69d2ee8 100644 --- a/modules/fbx/fbx_parser/FBXDocument.cpp +++ b/modules/fbx/fbx_parser/FBXDocument.cpp @@ -93,7 +93,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) : - doc(doc), element(element), id(id), flags() { + doc(doc), element(element), id(id) { // empty } @@ -228,7 +228,7 @@ ObjectPtr LazyObject::LoadObject() { // ------------------------------------------------------------------------------------------------ Object::Object(uint64_t id, const ElementPtr element, const std::string &name) : - element(element), name(name), id(id) { + PropertyTable(element), element(element), name(name), id(id) { } // ------------------------------------------------------------------------------------------------ @@ -237,22 +237,18 @@ Object::~Object() { } // ------------------------------------------------------------------------------------------------ -FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) : - props(props), doc(doc) { +FileGlobalSettings::FileGlobalSettings(const Document &doc) : + PropertyTable(), doc(doc) { // empty } // ------------------------------------------------------------------------------------------------ FileGlobalSettings::~FileGlobalSettings() { - if (props != nullptr) { - delete props; - props = nullptr; - } } // ------------------------------------------------------------------------------------------------ Document::Document(const Parser &parser, const ImportSettings &settings) : - settings(settings), parser(parser), SafeToImport(false) { + settings(settings), parser(parser) { // Cannot use array default initialization syntax because vc8 fails on it for (unsigned int &timeStamp : creationTimeStamp) { timeStamp = 0; @@ -287,15 +283,12 @@ Document::~Document() { delete v.second; } - if (metadata_properties != nullptr) { - delete metadata_properties; - } // clear globals import pointer globals.reset(); } // ------------------------------------------------------------------------------------------------ -static const unsigned int LowerSupportedVersion = 7300; +static const unsigned int LowerSupportedVersion = 7100; static const unsigned int UpperSupportedVersion = 7700; bool Document::ReadHeader() { @@ -306,6 +299,11 @@ bool Document::ReadHeader() { DOMError("no FBXHeaderExtension dictionary found"); } + if (parser.IsCorrupt()) { + DOMError("File is corrupt"); + return false; + } + const ScopePtr shead = ehead->Compound(); fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0)); @@ -325,18 +323,11 @@ bool Document::ReadHeader() { creator = ParseTokenAsString(GetRequiredToken(ecreator, 0)); } - // // Scene Info - // - const ElementPtr scene_info = shead->GetElement("SceneInfo"); if (scene_info) { - PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true)); - - if (fileExportProps) { - metadata_properties = fileExportProps; - } + metadata_properties.Setup(scene_info); } const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp"); @@ -358,23 +349,7 @@ bool Document::ReadHeader() { void Document::ReadGlobalSettings() { ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported"); - const ScopePtr sc = parser.GetRootScope(); - const ElementPtr ehead = sc->GetElement("GlobalSettings"); - if (nullptr == ehead || !ehead->Compound()) { - DOMWarning("no GlobalSettings dictionary found"); - globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable()); - return; - } - - const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true); - - //double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 ); - - if (!props) { - DOMError("GlobalSettings dictionary contains no property table"); - } - - globals = std::make_shared<FileGlobalSettings>(*this, props); + globals = std::make_shared<FileGlobalSettings>(*this); } // ------------------------------------------------------------------------------------------------ @@ -445,58 +420,6 @@ void Document::ReadObjects() { // ------------------------------------------------------------------------------------------------ void Document::ReadPropertyTemplates() { - const ScopePtr sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const ElementPtr edefs = sc->GetElement("Definitions"); - if (!edefs || !edefs->Compound()) { - DOMWarning("no Definitions dictionary found"); - return; - } - - const ScopePtr sdefs = edefs->Compound(); - const ElementCollection otypes = sdefs->GetCollection("ObjectType"); - for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) { - const ElementPtr el = (*it).second; - const ScopePtr sc_2 = el->Compound(); - if (!sc_2) { - DOMWarning("expected nested scope in ObjectType, ignoring", el); - continue; - } - - const TokenList &tok = el->Tokens(); - if (tok.empty()) { - DOMWarning("expected name for ObjectType element, ignoring", el); - continue; - } - - const std::string &oname = ParseTokenAsString(tok[0]); - - const ElementCollection templs = sc_2->GetCollection("PropertyTemplate"); - for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) { - const ElementPtr el_2 = (*iter).second; - const ScopePtr sc_3 = el_2->Compound(); - if (!sc_3) { - DOMWarning("expected nested scope in PropertyTemplate, ignoring", el); - continue; - } - - const TokenList &tok_2 = el_2->Tokens(); - if (tok_2.empty()) { - DOMWarning("expected name for PropertyTemplate element, ignoring", el); - continue; - } - - const std::string &pname = ParseTokenAsString(tok_2[0]); - - const ElementPtr Properties70 = sc_3->GetElement("Properties70"); - if (Properties70) { - // PropertyTable(const ElementPtr element, const PropertyTable* templateProps); - const PropertyTable *props = new PropertyTable(Properties70, nullptr); - - templates[oname + "." + pname] = props; - } - } - } } // ------------------------------------------------------------------------------------------------ @@ -564,7 +487,7 @@ const std::vector<const AnimationStack *> &Document::AnimationStacks() const { const AnimationStack *stack = lazy->Get<AnimationStack>(); ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure"); - // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it wont be cleaned up. + // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it won't be cleaned up. animationStacksResolved.push_back(stack); } diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h index b810197d7e..885ff8fca4 100644 --- a/modules/fbx/fbx_parser/FBXDocument.h +++ b/modules/fbx/fbx_parser/FBXDocument.h @@ -37,7 +37,7 @@ #include "FBXCommon.h" #include "FBXParser.h" #include "FBXProperties.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" #include "core/string/print_string.h" @@ -130,7 +130,7 @@ private: }; /** Base class for in-memory (DOM) representations of FBX objects */ -class Object { +class Object : public PropertyTable { public: Object(uint64_t id, const ElementPtr element, const std::string &name); @@ -149,9 +149,9 @@ public: } protected: - const ElementPtr element; + const ElementPtr element = nullptr; const std::string name; - const uint64_t id = 0; + const uint64_t id; }; /** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, @@ -159,22 +159,13 @@ protected: class NodeAttribute : public Object { public: NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~NodeAttribute(); - - const PropertyTable *Props() const { - return props; - } - -private: - const PropertyTable *props; }; /** DOM base class for FBX camera settings attached to a node */ class CameraSwitcher : public NodeAttribute { public: CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~CameraSwitcher(); int CameraID() const { @@ -190,26 +181,26 @@ public: } private: - int cameraId; + int cameraId = 0; std::string cameraName; std::string cameraIndexName; }; #define fbx_stringize(a) #a -#define fbx_simple_property(name, type, default_value) \ - type name() const { \ - return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \ +#define fbx_simple_property(name, type, default_value) \ + type name() const { \ + return PropertyGet<type>(this, fbx_stringize(name), (default_value)); \ } // XXX improve logging -#define fbx_simple_enum_property(name, type, default_value) \ - type name() const { \ - const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \ - if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ - return static_cast<type>(default_value); \ - } \ - return static_cast<type>(ival); \ +#define fbx_simple_enum_property(name, type, default_value) \ + type name() const { \ + const int ival = PropertyGet<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \ + if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ + return static_cast<type>(default_value); \ + } \ + return static_cast<type>(ival); \ } class FbxPoseNode; @@ -251,20 +242,19 @@ public: return target_id; } - Transform GetBindPose() const { + Transform3D GetBindPose() const { return transform; } private: - uint64_t target_id; - Transform transform; + uint64_t target_id = 0; + Transform3D transform; }; /** DOM base class for FBX cameras attached to a node */ class Camera : public NodeAttribute { public: Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Camera(); fbx_simple_property(Position, Vector3, Vector3(0, 0, 0)); @@ -380,7 +370,6 @@ public: }; Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Model(); fbx_simple_property(QuaternionInterpolate, int, 0); @@ -466,10 +455,6 @@ public: return culling; } - const PropertyTable *Props() const { - return props; - } - /** Get material links */ const std::vector<const Material *> &GetMaterials() const { return materials; @@ -498,13 +483,11 @@ private: std::string shading; std::string culling; - const PropertyTable *props = nullptr; }; class ModelLimbNode : public Model { public: ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~ModelLimbNode(); }; @@ -512,7 +495,6 @@ public: class Texture : public Object { public: Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Texture(); const std::string &Type() const { @@ -539,10 +521,6 @@ public: return uvScaling; } - const PropertyTable *Props() const { - return props; - } - // return a 4-tuple const unsigned int *Crop() const { return crop; @@ -560,10 +538,8 @@ private: std::string relativeFileName; std::string fileName; std::string alphaSource; - const PropertyTable *props = nullptr; unsigned int crop[4] = { 0 }; - const Video *media = nullptr; }; @@ -626,8 +602,8 @@ public: private: std::vector<const Texture *> textures; - BlendMode blendMode; - float alpha; + BlendMode blendMode = BlendMode::BlendMode_Additive; + float alpha = 0; }; typedef std::map<std::string, const Texture *> TextureMap; @@ -656,10 +632,6 @@ public: return relativeFileName; } - const PropertyTable *Props() const { - return props; - } - const uint8_t *Content() const { return content; } @@ -670,7 +642,7 @@ public: uint8_t *RelinquishContent() { uint8_t *ptr = content; - content = 0; + content = nullptr; return ptr; } @@ -687,7 +659,6 @@ private: std::string type; std::string relativeFileName; std::string fileName; - const PropertyTable *props = nullptr; uint64_t contentLength = 0; uint8_t *content = nullptr; @@ -708,10 +679,6 @@ public: return multilayer; } - const PropertyTable *Props() const { - return props; - } - const TextureMap &Textures() const { return textures; } @@ -722,8 +689,7 @@ public: private: std::string shading; - bool multilayer; - const PropertyTable *props; + bool multilayer = false; TextureMap textures; LayeredTextureMap layeredTextures; @@ -733,7 +699,7 @@ private: typedef std::vector<int64_t> KeyTimeList; typedef std::vector<float> KeyValueList; -/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */ +/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */ class AnimationCurve : public Object { public: AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); @@ -791,13 +757,9 @@ public: virtual ~AnimationCurveNode(); - const PropertyTable *Props() const { - return props; - } - const AnimationMap &Curves() const; - /** Object the curve is assigned to, this can be NULL if the + /** Object the curve is assigned to, this can be nullptr if the * target object has no DOM representation or could not * be read for other reasons.*/ Object *Target() const { @@ -819,7 +781,6 @@ public: private: Object *target = nullptr; - const PropertyTable *props; mutable AnimationMap curves; std::string prop; const Document &doc; @@ -837,18 +798,12 @@ public: AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~AnimationLayer(); - const PropertyTable *Props() const { - //ai_assert(props.get()); - return props; - } - /* the optional white list specifies a list of property names for which the caller wants animations for. Curves not matching this list will not be added to the animation layer. */ const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const; private: - const PropertyTable *props; const Document &doc; }; @@ -863,16 +818,11 @@ public: fbx_simple_property(ReferenceStart, int64_t, 0L); fbx_simple_property(ReferenceStop, int64_t, 0L); - const PropertyTable *Props() const { - return props; - } - const AnimationLayerList &Layers() const { return layers; } private: - const PropertyTable *props = nullptr; AnimationLayerList layers; }; @@ -881,14 +831,6 @@ class Deformer : public Object { public: Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Deformer(); - - const PropertyTable *Props() const { - //ai_assert(props.get()); - return props; - } - -private: - const PropertyTable *props; }; /** Constraints are from Maya they can help us with BoneAttachments :) **/ @@ -896,9 +838,6 @@ class Constraint : public Object { public: Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Constraint(); - -private: - const PropertyTable *props; }; typedef std::vector<float> WeightArray; @@ -924,7 +863,7 @@ public: } private: - float percent; + float percent = 0; WeightArray fullWeights; std::vector<const ShapeGeometry *> shapeGeometries; }; @@ -966,11 +905,11 @@ public: } /** */ - const Transform &GetTransform() const { + const Transform3D &GetTransform() const { return transform; } - const Transform &TransformLink() const { + const Transform3D &TransformLink() const { return transformLink; } @@ -978,7 +917,7 @@ public: return node; } - const Transform &TransformAssociateModel() const { + const Transform3D &TransformAssociateModel() const { return transformAssociateModel; } @@ -1002,11 +941,11 @@ private: std::vector<float> weights; std::vector<unsigned int> indices; - Transform transform; - Transform transformLink; - Transform transformAssociateModel; + Transform3D transform; + Transform3D transformLink; + Transform3D transformAssociateModel; SkinLinkMode link_mode; - bool valid_transformAssociateModel; + bool valid_transformAssociateModel = false; const Model *node = nullptr; }; @@ -1037,8 +976,8 @@ public: } private: - float accuracy; - SkinType skinType; + float accuracy = 0; + SkinType skinType = SkinType::Skin_Linear; std::vector<const Cluster *> clusters; }; @@ -1050,7 +989,7 @@ public: // note: a connection ensures that the source and dest objects exist, but // not that they have DOM representations, so the return value of one of - // these functions can still be NULL. + // these functions can still be nullptr. Object *SourceObject() const; Object *DestinationObject() const; @@ -1087,10 +1026,10 @@ public: } public: - uint64_t insertionOrder; + uint64_t insertionOrder = 0; const std::string prop; - uint64_t src, dest; + uint64_t src = 0, dest = 0; const Document &doc; }; @@ -1105,15 +1044,10 @@ typedef std::multimap<uint64_t, const Connection *> ConnectionMap; /** DOM class for global document settings, a single instance per document can * be accessed via Document.Globals(). */ -class FileGlobalSettings { +class FileGlobalSettings : public PropertyTable { public: - FileGlobalSettings(const Document &doc, const PropertyTable *props); - - ~FileGlobalSettings(); - - const PropertyTable *Props() const { - return props; - } + FileGlobalSettings(const Document &doc); + virtual ~FileGlobalSettings(); const Document &GetDocument() const { return doc; @@ -1158,7 +1092,6 @@ public: fbx_simple_property(CustomFrameRate, float, -1.0f); private: - const PropertyTable *props = nullptr; const Document &doc; }; @@ -1196,7 +1129,7 @@ public: return globals.get(); } - const PropertyTable *GetMetadataProperties() const { + const PropertyTable &GetMetadataProperties() const { return metadata_properties; } @@ -1293,7 +1226,7 @@ private: std::vector<uint64_t> materials; std::vector<uint64_t> skins; mutable std::vector<const AnimationStack *> animationStacksResolved; - PropertyTable *metadata_properties = nullptr; + PropertyTable metadata_properties; std::shared_ptr<FileGlobalSettings> globals = nullptr; }; } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp index 835b66ab23..4a33024969 100644 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp +++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp @@ -95,14 +95,14 @@ void DOMError(const std::string &message, const std::shared_ptr<Token> token) { print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); } -void DOMError(const std::string &message, const Element *element /*= NULL*/) { +void DOMError(const std::string &message, const Element *element /*= nullptr*/) { if (element) { DOMError(message, element->KeyToken()); } print_error("[FBX-DOM] " + String(message.c_str())); } -void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) { +void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) { if (element) { DOMError(message, element->KeyToken()); } @@ -117,7 +117,7 @@ void DOMWarning(const std::string &message, const Token *token) { print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); } -void DOMWarning(const std::string &message, const Element *element /*= NULL*/) { +void DOMWarning(const std::string &message, const Element *element /*= nullptr*/) { if (element) { DOMWarning(message, element->KeyToken()); return; @@ -129,7 +129,7 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Token> token) print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); } -void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) { +void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) { if (element) { DOMWarning(message, element->KeyToken()); return; @@ -137,36 +137,5 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Element> eleme print_verbose("[FBX-DOM] warning:" + String(message.c_str())); } -// ------------------------------------------------------------------------------------------------ -// fetch a property table and the corresponding property template -const PropertyTable *GetPropertyTable(const Document &doc, - const std::string &templateName, - const ElementPtr element, - const ScopePtr sc, - bool no_warn /*= false*/) { - // todo: make this an abstraction - const ElementPtr Properties70 = sc->GetElement("Properties70"); - const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr); - - if (templateName.length()) { - PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName); - if (it != doc.Templates().end()) { - templateProps = (*it).second; - } - } - - if (!Properties70 || !Properties70->Compound()) { - if (!no_warn) { - DOMWarning("property table (Properties70) not found", element); - } - if (templateProps) { - return templateProps; - } else { - return new const PropertyTable(); - } - } - - return new PropertyTable(Properties70, templateProps); -} } // namespace Util } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h index daa9de4a33..ba86191c4a 100644 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.h +++ b/modules/fbx/fbx_parser/FBXDocumentUtil.h @@ -98,13 +98,6 @@ void DOMWarning(const std::string &message, const Element *element); void DOMWarning(const std::string &message, const std::shared_ptr<Token> token); void DOMWarning(const std::string &message, const std::shared_ptr<Element> element); -// fetch a property table and the corresponding property template -const PropertyTable *GetPropertyTable(const Document &doc, - const std::string &templateName, - const ElementPtr element, - const ScopePtr sc, - bool no_warn = false); - // ------------------------------------------------------------------------------------------------ template <typename T> const T *ProcessSimpleConnection(const Connection &con, diff --git a/modules/fbx/fbx_parser/FBXImportSettings.h b/modules/fbx/fbx_parser/FBXImportSettings.h index 97ce496eaf..b016db174b 100644 --- a/modules/fbx/fbx_parser/FBXImportSettings.h +++ b/modules/fbx/fbx_parser/FBXImportSettings.h @@ -80,60 +80,52 @@ namespace FBXDocParser { /** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */ struct ImportSettings { - ImportSettings() : - strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) { - // empty - } - /** enable strict mode: * - only accept fbx 2012, 2013 files * - on the slightest error, give up. * * Basically, strict mode means that the fbx file will actually - * be validated. Strict mode is off by default. */ - bool strictMode; + * be validated.*/ + bool strictMode = true; /** specifies whether all geometry layers are read and scanned for * usable data channels. The FBX spec indicates that many readers * will only read the first channel and that this is in some way * the recommended way- in reality, however, it happens a lot that - * vertex data is spread among multiple layers. The default - * value for this option is true.*/ - bool readAllLayers; + * vertex data is spread among multiple layers.*/ + bool readAllLayers = true; /** specifies whether all materials are read, or only those that * are referenced by at least one mesh. Reading all materials * may make FBX reading a lot slower since all objects - * need to be processed . - * This bit is ignored unless readMaterials=true*/ - bool readAllMaterials; + * need to be processed. + * This bit is ignored unless readMaterials=true.*/ + bool readAllMaterials = true; /** import materials (true) or skip them and assign a default - * material. The default value is true.*/ - bool readMaterials; + * material.*/ + bool readMaterials = true; - /** import embedded textures? Default value is true.*/ - bool readTextures; + /** import embedded textures?*/ + bool readTextures = true; - /** import cameras? Default value is true.*/ - bool readCameras; + /** import cameras?*/ + bool readCameras = true; - /** import light sources? Default value is true.*/ - bool readLights; + /** import light sources?*/ + bool readLights = true; /** import animations (i.e. animation curves, the node - * skeleton is always imported). Default value is true. */ - bool readAnimations; + * skeleton is always imported).*/ + bool readAnimations = true; - /** read bones (vertex weights and deform info). - * Default value is true. */ - bool readWeights; + /** read bones (vertex weights and deform info).*/ + bool readWeights = true; /** preserve transformation pivots and offsets. Since these can * not directly be represented in assimp, additional dummy * nodes will be generated. Note that settings this to false - * can make animation import a lot slower. The default value - * is true. + * can make animation import a lot slower. * * The naming scheme for the generated nodes is: * <OriginalName>_$AssimpFbx$_<TransformName> @@ -149,24 +141,21 @@ struct ImportSettings { * Scaling * Rotation **/ - bool preservePivots; + bool preservePivots = true; /** do not import animation curves that specify a constant - * values matching the corresponding node transformation. - * The default value is true. */ - bool optimizeEmptyAnimationCurves; + * values matching the corresponding node transformation.*/ + bool optimizeEmptyAnimationCurves = true; - /** use legacy naming for embedded textures eg: (*0, *1, *2) - */ - bool useLegacyEmbeddedTextureNaming; + /** use legacy naming for embedded textures eg: (*0, *1, *2).*/ + bool useLegacyEmbeddedTextureNaming = false; - /** Empty bones shall be removed - */ - bool removeEmptyBones; + /** Empty bones shall be removed.*/ + bool removeEmptyBones = true; - /** Set to true to perform a conversion from cm to meter after the import - */ - bool convertToMeters; + /** Set to true to perform a conversion from cm to meter after + * the import.*/ + bool convertToMeters = false; }; } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp index 9970a2b0b1..bf8922267e 100644 --- a/modules/fbx/fbx_parser/FBXMaterial.cpp +++ b/modules/fbx/fbx_parser/FBXMaterial.cpp @@ -118,8 +118,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c DOMWarning("shading mode not recognized: " + shading, element); } - props = GetPropertyTable(doc, templateName, element, sc); - // resolve texture links const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID()); for (const Connection *con : conns) { @@ -163,15 +161,11 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c // ------------------------------------------------------------------------------------------------ Material::~Material() { - if (props != nullptr) { - delete props; - props = nullptr; - } } // ------------------------------------------------------------------------------------------------ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) { + Object(id, element, name), uvScaling(1.0f, 1.0f) { const ScopePtr sc = GetRequiredScope(element); const ElementPtr Type = sc->GetElement("Type"); @@ -219,17 +213,15 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0)); } - props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc); - // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available. - bool ok; - const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok); + bool ok = true; + const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok); if (ok) { uvScaling.x = scaling.x; uvScaling.y = scaling.y; } - const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok); + const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok); if (ok) { uvTrans.x = trans.x; uvTrans.y = trans.y; @@ -254,10 +246,6 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con } Texture::~Texture() { - if (props != nullptr) { - delete props; - props = nullptr; - } } LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) : @@ -267,10 +255,10 @@ LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Docu ElementPtr BlendModes = sc->GetElement("BlendModes"); ElementPtr Alphas = sc->GetElement("Alphas"); - if (BlendModes != 0) { + if (BlendModes != nullptr) { blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0)); } - if (Alphas != 0) { + if (Alphas != nullptr) { alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0)); } } @@ -297,7 +285,7 @@ void LayeredTexture::fillTexture(const Document &doc) { // ------------------------------------------------------------------------------------------------ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), contentLength(0), content(0) { + Object(id, element, name) { const ScopePtr sc = GetRequiredScope(element); const ElementPtr Type = sc->GetElement("Type"); @@ -337,7 +325,7 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s DOMError("embedded content is not surrounded by quotation marks", element); } else { size_t targetLength = 0; - auto numTokens = Content->Tokens().size(); + const size_t numTokens = Content->Tokens().size(); // First time compute size (it could be large like 64Gb and it is good to allocate it once) for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) { const Token *dataToken = GetRequiredToken(Content, tokenIdx); @@ -390,18 +378,11 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s // runtimeError.what()); } } - - props = GetPropertyTable(doc, "Video.FbxVideo", element, sc); } Video::~Video() { if (content) { delete[] content; } - - if (props != nullptr) { - delete props; - props = nullptr; - } } } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp index ccc06550fe..2cc25a0690 100644 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp +++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp @@ -88,7 +88,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Object(id, element, name), skin() { + Object(id, element, name) { const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); for (const Connection *con : conns) { const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element); @@ -125,7 +125,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str ScopePtr sc = element->Compound(); ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash"); - ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertexes, didn't populate the mesh"); + ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertices, didn't populate the mesh"); // must have Mesh elements: const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element); @@ -140,7 +140,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str ParseVectorDataArray(m_vertices, Vertices); ParseVectorDataArray(m_face_indices, PolygonVertexIndex); - ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertexes in FBX file, did you mean to delete it?"); + ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertices in FBX file, did you mean to delete it?"); ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?"); // Retrieve layer elements, for all of the mesh @@ -278,7 +278,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str } } // As the algorithm above, this check is useless. Because the first - // ever vertex is always considered the begining of a polygon. + // ever vertex is always considered the beginning of a polygon. ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted."); } else { @@ -418,7 +418,7 @@ MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array( // parse data into array ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName)); - // index array wont always exist + // index array won't always exist const ElementPtr element = GetOptionalElement(source, indexDataElementName); if (element) { ParseVectorDataArray(tempData.index, element); diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.h b/modules/fbx/fbx_parser/FBXMeshGeometry.h index 710e644c68..c9b25f008d 100644 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.h +++ b/modules/fbx/fbx_parser/FBXMeshGeometry.h @@ -96,7 +96,7 @@ public: Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~Geometry(); - /** Get the Skin attached to this geometry or NULL */ + /** Get the Skin attached to this geometry or nullptr */ const Skin *DeformerSkin() const; const std::vector<const BlendShape *> &get_blend_shapes() const; @@ -122,7 +122,7 @@ typedef std::vector<int> MatIndexArray; /// ## Map Type: /// * None The mapping is undetermined. /// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex). -/// * If you have direct reference type verticies[x] +/// * If you have direct reference type vertices[x] /// * If you have IndexToDirect reference type the UV /// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex) /// * ByPolygon There can be only one mapping coordinate for the whole polygon. @@ -186,7 +186,7 @@ public: /// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't // matter. static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b); - // Retuns the edge point bu that ID, or the edge with -1 vertices if the + // Returns the edge point bu that ID, or the edge with -1 vertices if the // id is not valid. static Edge get_edge(const std::vector<Edge> &p_map, int p_id); diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp index 767994441f..03c9de0c35 100644 --- a/modules/fbx/fbx_parser/FBXModel.cpp +++ b/modules/fbx/fbx_parser/FBXModel.cpp @@ -98,16 +98,11 @@ Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const s culling = ParseTokenAsString(GetRequiredToken(Culling, 0)); } - props = GetPropertyTable(doc, "Model.FbxNode", element, sc); ResolveLinks(element, doc); } // ------------------------------------------------------------------------------------------------ Model::~Model() { - if (props != nullptr) { - delete props; - props = nullptr; - } } ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp index 2749fc9f4d..15184a0f5d 100644 --- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp +++ b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp @@ -84,16 +84,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), props() { - const ScopePtr sc = GetRequiredScope(element); - - const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2)); - - // hack on the deriving type but Null/LimbNode attributes are the only case in which - // the property table is by design absent and no warning should be generated - // for it. - const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode"); - props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb); + Object(id, element, name) { } // ------------------------------------------------------------------------------------------------ diff --git a/modules/fbx/fbx_parser/FBXParseTools.h b/modules/fbx/fbx_parser/FBXParseTools.h index 21472f5b7b..b4003bbec5 100644 --- a/modules/fbx/fbx_parser/FBXParseTools.h +++ b/modules/fbx/fbx_parser/FBXParseTools.h @@ -61,7 +61,7 @@ inline bool IsLineEnd(char_t c) { // Special version of the function, providing higher accuracy and safety // It is mainly used by fast_atof to prevent ugly and unwanted integer overflows. // ------------------------------------------------------------------------------------ -inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = 0, unsigned int *max_inout = 0) { +inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) { unsigned int cur = 0; uint64_t value = 0; diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp index 44c24ff926..a92b23f4ee 100644 --- a/modules/fbx/fbx_parser/FBXParser.cpp +++ b/modules/fbx/fbx_parser/FBXParser.cpp @@ -74,15 +74,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the FBX parser and the rudimentary DOM that we use */ -#include "thirdparty/zlib/zlib.h" #include <stdlib.h> /* strtol */ +#include <zlib.h> #include "ByteSwapper.h" #include "FBXParseTools.h" #include "FBXParser.h" #include "FBXTokenizer.h" #include "core/math/math_defs.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/string/print_string.h" @@ -131,6 +131,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) : if (!n) { print_error("unexpected end of file, expected bracket, comma or key" + String(parser.LastToken()->StringContents().c_str())); + parser.corrupt = true; + return; } const TokenType ty = n->Type(); @@ -143,6 +145,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) : if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { print_error("unexpected token; expected bracket, comma or key" + String(n->StringContents().c_str())); + parser.corrupt = true; + return; } } @@ -150,11 +154,17 @@ Element::Element(const TokenPtr key_token, Parser &parser) : compound = new_Scope(parser); parser.scopes.push_back(compound); + if (parser.corrupt) { + return; + } + // current token should be a TOK_CLOSE_BRACKET n = parser.CurrentToken(); if (n && n->Type() != TokenType_CLOSE_BRACKET) { print_error("expected closing bracket" + String(n->StringContents().c_str())); + parser.corrupt = true; + return; } parser.AdvanceToNextToken(); @@ -173,22 +183,31 @@ Scope::Scope(Parser &parser, bool topLevel) { TokenPtr t = parser.CurrentToken(); if (t->Type() != TokenType_OPEN_BRACKET) { print_error("expected open bracket" + String(t->StringContents().c_str())); + parser.corrupt = true; + return; } } TokenPtr n = parser.AdvanceToNextToken(); if (n == nullptr) { print_error("unexpected end of file"); + parser.corrupt = true; + return; } // note: empty scopes are allowed while (n && n->Type() != TokenType_CLOSE_BRACKET) { if (n->Type() != TokenType_KEY) { print_error("unexpected token, expected TOK_KEY" + String(n->StringContents().c_str())); + parser.corrupt = true; + return; } const std::string str = n->StringContents(); + if (parser.corrupt) { + return; + } // std::multimap<std::string, ElementPtr> (key and value) elements.insert(ElementMap::value_type(str, new_Element(n, parser))); @@ -216,7 +235,7 @@ Scope::~Scope() { // ------------------------------------------------------------------------------------------------ Parser::Parser(const TokenList &tokens, bool is_binary) : - tokens(tokens), last(), current(), cursor(tokens.begin()), is_binary(is_binary) { + corrupt(false), tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) { root = new_Scope(*this, true); scopes.push_back(root); } @@ -1138,7 +1157,7 @@ void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el) { } // ------------------------------------------------------------------------------------------------ -Transform ReadMatrix(const ElementPtr element) { +Transform3D ReadMatrix(const ElementPtr element) { std::vector<float> values; ParseVectorDataArray(values, element); @@ -1148,12 +1167,12 @@ Transform ReadMatrix(const ElementPtr element) { // clean values to prevent any IBM damage on inverse() / affine_inverse() for (float &value : values) { - if (::Math::is_equal_approx(0, value)) { + if (::Math::is_zero_approx(value)) { value = 0; } } - Transform xform; + Transform3D xform; Basis basis; basis.set( @@ -1187,7 +1206,7 @@ std::string ParseTokenAsString(const TokenPtr t) { // ------------------------------------------------------------------------------------------------ // extract a required element from a scope, abort if the element cannot be found -ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) { +ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) { const ElementPtr el = sc->GetElement(index); TokenPtr token = el->KeyToken(); ERR_FAIL_COND_V(!token, nullptr); @@ -1208,7 +1227,7 @@ bool HasElement(const ScopePtr sc, const std::string &index) { // ------------------------------------------------------------------------------------------------ // extract a required element from a scope, abort if the element cannot be found -ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) { +ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) { const ElementPtr el = sc->GetElement(index); return el; } @@ -1231,6 +1250,21 @@ ScopePtr GetRequiredScope(const ElementPtr el) { } // ------------------------------------------------------------------------------------------------ +// extract optional compound scope +ScopePtr GetOptionalScope(const ElementPtr el) { + if (el) { + ScopePtr s = el->Compound(); + TokenPtr token = el->KeyToken(); + + if (token && s) { + return s; + } + } + + return nullptr; +} + +// ------------------------------------------------------------------------------------------------ // get token at a particular index TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index) { if (el) { diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h index 37d27d3dca..93836c2205 100644 --- a/modules/fbx/fbx_parser/FBXParser.h +++ b/modules/fbx/fbx_parser/FBXParser.h @@ -81,7 +81,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <memory> #include "core/math/color.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" @@ -160,7 +160,7 @@ public: } ElementPtr FindElementCaseInsensitive(const std::string &elementName) const { - for (auto element = elements.begin(); element != elements.end(); ++element) { + for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) { if (element->first.compare(elementName)) { return element->second; } @@ -199,6 +199,10 @@ public: return is_binary; } + bool IsCorrupt() const { + return corrupt; + } + private: friend class Scope; friend class Element; @@ -208,6 +212,7 @@ private: TokenPtr CurrentToken() const; private: + bool corrupt = false; ScopeList scopes; const TokenList &tokens; @@ -249,6 +254,8 @@ bool HasElement(const ScopePtr sc, const std::string &index); // extract a required element from a scope, abort if the element cannot be found ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr); ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application) +ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now) + ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr); // extract required compound scope ScopePtr GetRequiredScope(const ElementPtr el); @@ -257,7 +264,7 @@ TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index); // ------------------------------------------------------------------------------------------------ // read a 4x4 matrix from an array of 16 floats -Transform ReadMatrix(const ElementPtr element); +Transform3D ReadMatrix(const ElementPtr element); } // namespace FBXDocParser #endif // FBX_PARSER_H diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp index 8ab94e1ef4..37717e9109 100644 --- a/modules/fbx/fbx_parser/FBXProperties.cpp +++ b/modules/fbx/fbx_parser/FBXProperties.cpp @@ -94,7 +94,7 @@ Property::~Property() { namespace { // ------------------------------------------------------------------------------------------------ -// read a typed property out of a FBX element. The return value is NULL if the property cannot be read. +// read a typed property out of a FBX element. The return value is nullptr if the property cannot be read. PropertyPtr ReadTypedProperty(const ElementPtr element) { //ai_assert(element.KeyToken().StringContents() == "P"); @@ -146,14 +146,32 @@ std::string PeekPropertyName(const Element &element) { // ------------------------------------------------------------------------------------------------ PropertyTable::PropertyTable() : - templateProps(), element() { + element(nullptr) { +} + +// Is used when dealing with FBX Objects not metadata. +PropertyTable::PropertyTable(const ElementPtr element) : + element(element) { + Setup(element); } // ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) : - templateProps(templateProps), element(element) { - const ScopePtr scope = GetRequiredScope(element); - ERR_FAIL_COND(!scope); +PropertyTable::~PropertyTable() { + for (PropertyMap::value_type &v : props) { + delete v.second; + } +} + +void PropertyTable::Setup(ElementPtr ptr) { + const ScopePtr sc = GetRequiredScope(ptr); + const ElementPtr Properties70 = sc->GetElement("Properties70"); + const ScopePtr scope = GetOptionalScope(Properties70); + + // no scope, no care. + if (!scope) { + return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it. + } + for (const ElementMap::value_type &v : scope->Elements()) { if (v.first != "P") { DOMWarning("expected only P elements in property table", v.second); @@ -178,13 +196,6 @@ PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *temp } // ------------------------------------------------------------------------------------------------ -PropertyTable::~PropertyTable() { - for (PropertyMap::value_type &v : props) { - delete v.second; - } -} - -// ------------------------------------------------------------------------------------------------ PropertyPtr PropertyTable::Get(const std::string &name) const { PropertyMap::const_iterator it = props.find(name); if (it == props.end()) { @@ -199,10 +210,6 @@ PropertyPtr PropertyTable::Get(const std::string &name) const { if (it == props.end()) { // check property template - if (templateProps) { - return templateProps->Get(name); - } - return nullptr; } } @@ -216,8 +223,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const { // Loop through all the lazy properties (which is all the properties) for (const LazyPropertyMap::value_type &element : lazyProps) { // Skip parsed properties - if (props.end() != props.find(element.first)) + if (props.end() != props.find(element.first)) { continue; + } // Read the element's value. // Wrap the naked pointer (since the call site is required to acquire ownership) @@ -225,8 +233,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const { Property *prop = ReadTypedProperty(element.second); // Element could not be read. Skip it. - if (!prop) + if (!prop) { continue; + } // Add to result result[element.first] = prop; diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h index 27cacfaf76..bfd27ac94e 100644 --- a/modules/fbx/fbx_parser/FBXProperties.h +++ b/modules/fbx/fbx_parser/FBXProperties.h @@ -137,35 +137,31 @@ class PropertyTable { public: // in-memory property table with no source element PropertyTable(); - PropertyTable(const ElementPtr element, const PropertyTable *templateProps); - ~PropertyTable(); + PropertyTable(const ElementPtr element); + virtual ~PropertyTable(); PropertyPtr Get(const std::string &name) const; + void Setup(ElementPtr ptr); // PropertyTable's need not be coupled with FBX elements so this can be NULL - ElementPtr GetElement() const { + ElementPtr GetElement() { return element; } - PropertyMap &GetProperties() const { + PropertyMap &GetProperties() { return props; } - const LazyPropertyMap &GetLazyProperties() const { + const LazyPropertyMap &GetLazyProperties() { return lazyProps; } - const PropertyTable *TemplateProps() const { - return templateProps; - } - DirectPropertyMap GetUnparsedProperties() const; private: LazyPropertyMap lazyProps; mutable PropertyMap props; - const PropertyTable *templateProps = nullptr; - const ElementPtr element = nullptr; + ElementPtr element = nullptr; }; // ------------------------------------------------------------------------------------------------ @@ -190,16 +186,11 @@ template <typename T> inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) { PropertyPtr prop = in->Get(name); if (nullptr == prop) { - if (!useTemplate) { - result = false; - return T(); - } - const PropertyTable *templ = in->TemplateProps(); - if (nullptr == templ) { + if (nullptr == in) { result = false; return T(); } - prop = templ->Get(name); + prop = in->Get(name); if (nullptr == prop) { result = false; return T(); diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp index ea4568fe32..81c5b128e8 100644 --- a/modules/fbx/fbx_parser/FBXTokenizer.cpp +++ b/modules/fbx/fbx_parser/FBXTokenizer.cpp @@ -141,7 +141,7 @@ void ProcessDataToken(TokenList &output_tokens, const char *&start, const char * } // namespace // ------------------------------------------------------------------------------------------------ -void Tokenize(TokenList &output_tokens, const char *input, size_t length) { +void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) { // line and column numbers numbers are one-based unsigned int line = 1; unsigned int column = 1; @@ -185,6 +185,8 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length) { case '\"': if (token_begin) { TokenizeError("unexpected double-quote", line, column); + corrupt = true; + return; } token_begin = cur; in_double_quotes = true; diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h index 1e7e5e6535..184d0fd894 100644 --- a/modules/fbx/fbx_parser/FBXTokenizer.h +++ b/modules/fbx/fbx_parser/FBXTokenizer.h @@ -187,7 +187,7 @@ typedef std::vector<TokenPtr> TokenList; * @param output_tokens Receives a list of all tokens in the input data. * @param input_buffer Textual input buffer to be processed, 0-terminated. * @print_error if something goes wrong */ -void Tokenize(TokenList &output_tokens, const char *input, size_t length); +void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt); /** Tokenizer function for binary FBX files. * @@ -197,7 +197,7 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length); * @param input_buffer Binary input buffer to be processed. * @param length Length of input buffer, in bytes. There is no 0-terminal. * @print_error if something goes wrong */ -void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length); +void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt); } // namespace FBXDocParser #endif // FBX_TOKENIZER_H diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp index 80ea5fab4c..1f14a69099 100644 --- a/modules/fbx/fbx_parser/FBXUtil.cpp +++ b/modules/fbx/fbx_parser/FBXUtil.cpp @@ -121,9 +121,10 @@ static const uint8_t base64DecodeTable[128] = { }; uint8_t DecodeBase64(char ch) { - const auto idx = static_cast<uint8_t>(ch); - if (idx > 127) + const uint8_t idx = static_cast<uint8_t>(ch); + if (idx > 127) { return 255; + } return base64DecodeTable[idx]; } @@ -211,8 +212,9 @@ std::string EncodeBase64(const char *data, size_t length) { EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); // add '=' at the end - for (size_t i = 0; i < 4 * extraBytes / 3; i++) + for (size_t i = 0; i < 4 * extraBytes / 3; i++) { encoded_string[encodedBytes - i - 1] = '='; + } } return encoded_string; } diff --git a/modules/fbx/register_types.cpp b/modules/fbx/register_types.cpp index c0591dbc77..a75da8f3a9 100644 --- a/modules/fbx/register_types.cpp +++ b/modules/fbx/register_types.cpp @@ -36,7 +36,7 @@ #ifdef TOOLS_ENABLED static void _editor_init() { Ref<EditorSceneImporterFBX> import_fbx; - import_fbx.instance(); + import_fbx.instantiate(); ResourceImporterScene::get_singleton()->add_importer(import_fbx); } #endif @@ -46,7 +46,7 @@ void register_fbx_types() { ClassDB::APIType prev_api = ClassDB::get_current_api(); ClassDB::set_current_api(ClassDB::API_EDITOR); - ClassDB::register_class<EditorSceneImporterFBX>(); + GDREGISTER_CLASS(EditorSceneImporterFBX); ClassDB::set_current_api(prev_api); diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp index c87dd1fd3a..66b0153308 100644 --- a/modules/fbx/tools/import_utils.cpp +++ b/modules/fbx/tools/import_utils.cpp @@ -80,7 +80,7 @@ Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector return ret; } -Quat ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) { +Quaternion ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) { return ImportUtils::EulerToBasis(mode, p_rotation); } @@ -117,18 +117,18 @@ Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basi } } -Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation) { +Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation) { return BasisToEuler(mode, p_rotation); } -Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) { - Transform unscaled = Transform(p_initial.basis, p_initial.origin * p_scale); - ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform(), "det is zero unscaled?"); +Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale) { + Transform3D unscaled = Transform3D(p_initial.basis, p_initial.origin * p_scale); + ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform3D(), "det is zero unscaled?"); return unscaled; } Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) { - ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necesary"); + ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necessary"); // Using long double to make sure that normal is computed for even really tiny objects. typedef long double ldouble; ldouble x = 0.0; diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h index 6261138812..fbe7dbd82f 100644 --- a/modules/fbx/tools/import_utils.h +++ b/modules/fbx/tools/import_utils.h @@ -56,15 +56,15 @@ public: static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); /// Converts rotation order vector (in rad) to quaternion. - static Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); + static Quaternion EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); /// Converts basis into rotation order vector (in rad). static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation); /// Converts quaternion into rotation order vector (in rad). - static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation); + static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation); - static void debug_xform(String name, const Transform &t) { + static void debug_xform(String name, const Transform3D &t) { print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI))); } @@ -137,15 +137,15 @@ public: static Vector3 safe_import_vector3(const Vector3 &p_vec) { Vector3 vector = p_vec; - if (Math::is_equal_approx(0, vector.x)) { + if (Math::is_zero_approx(vector.x)) { vector.x = 0; } - if (Math::is_equal_approx(0, vector.y)) { + if (Math::is_zero_approx(vector.y)) { vector.y = 0; } - if (Math::is_equal_approx(0, vector.z)) { + if (Math::is_zero_approx(vector.z)) { vector.z = 0; } return vector; @@ -267,7 +267,7 @@ public: */ // static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) { // ERR_FAIL_COND(texture.is_null()); - // ERR_FAIL_COND(map_mode == NULL); + // ERR_FAIL_COND(map_mode == nullptr); // aiTextureMapMode tex_mode = map_mode[0]; // int32_t flags = Texture::FLAGS_DEFAULT; @@ -317,7 +317,7 @@ public: // } // } else { // Ref<Image> img; - // img.instance(); + // img.instantiate(); // PoolByteArray arr; // uint32_t size = tex->mWidth * tex->mHeight; // arr.resize(size); @@ -339,7 +339,7 @@ public: // } else { // Ref<Texture> texture = ResourceLoader::load(p_path); // ERR_FAIL_COND_V(texture.is_null(), Ref<Image>()); - // Ref<Image> image = texture->get_data(); + // Ref<Image> image = texture->get_image(); // ERR_FAIL_COND_V(image.is_null(), Ref<Image>()); // state.path_to_image_cache.insert(p_path, image); // return image; @@ -362,7 +362,7 @@ public: // if (found) { // image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path); // if (image_state.raw_image.is_valid()) { - // image_state.texture.instance(); + // image_state.texture.instantiate(); // image_state.texture->create_from_image(image_state.raw_image); // image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY); // return true; @@ -382,7 +382,7 @@ public: // String &path, // AssimpImageData &image_state) { // aiString ai_filename = aiString(); - // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) { + // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) { // return CreateAssimpTexture(state, ai_filename, filename, path, image_state); // } @@ -391,7 +391,7 @@ public: }; // Apply the transforms so the basis will have scale 1. -Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale); +Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale); /// Uses the Newell's method to compute any polygon normal. /// The polygon must be at least size of 3 or bigger. diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h index ced100aed2..906a721045 100644 --- a/modules/fbx/tools/validation_tools.h +++ b/modules/fbx/tools/validation_tools.h @@ -33,9 +33,8 @@ #ifdef TOOLS_ENABLED -#include "core/io/json.h" -#include "core/os/file_access.h" -#include "core/string/ustring.h" +#include "core/io/file_access.h" +#include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/map.h" @@ -65,8 +64,9 @@ protected: Error err; FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err); if (!file || err) { - if (file) + if (file) { memdelete(file); + } print_error("ValidationTracker Error - failed to create file - path: %s\n" + path); return; } diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml index 44d9e32ed8..4f1530598c 100644 --- a/modules/gdnative/doc_classes/GDNative.xml +++ b/modules/gdnative/doc_classes/GDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDNative" inherits="Reference" version="4.0"> +<class name="GDNative" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml index 9f33d32e81..b88f5e7e1e 100644 --- a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml +++ b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="MultiplayerPeerGDNative" inherits="MultiplayerPeer" version="4.0"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 86bd8b820d..1ff591a87f 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -32,8 +32,9 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "scene/main/scene_tree.h" @@ -51,7 +52,7 @@ extern const godot_gdnative_core_api_struct api_struct; Map<String, Vector<Ref<GDNative>>> GDNativeLibrary::loaded_libraries; GDNativeLibrary::GDNativeLibrary() { - config_file.instance(); + config_file.instantiate(); symbol_prefix = default_symbol_prefix; load_once = default_load_once; @@ -111,7 +112,7 @@ bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_property) const } void GDNativeLibrary::reset_state() { - config_file.instance(); + config_file.instantiate(); current_library_path = ""; current_dependencies.clear(); symbol_prefix = default_symbol_prefix; @@ -159,6 +160,8 @@ void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const { } void GDNativeLibrary::set_config_file(Ref<ConfigFile> p_config_file) { + ERR_FAIL_COND(p_config_file.is_null()); + set_singleton(p_config_file->get_value("general", "singleton", default_singleton)); set_load_once(p_config_file->get_value("general", "load_once", default_load_once)); set_symbol_prefix(p_config_file->get_value("general", "symbol_prefix", default_symbol_prefix)); @@ -249,7 +252,7 @@ void GDNativeLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix); ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile", 0), "set_config_file", "get_config_file"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile", PROPERTY_USAGE_NONE), "set_config_file", "get_config_file"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton"); @@ -333,9 +336,18 @@ bool GDNative::initialize() { // On OSX the exported libraries are located under the Frameworks directory. // So we need to replace the library path. String path = ProjectSettings::get_singleton()->globalize_path(lib_path); - if (!FileAccess::exists(path)) { + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + + if (!da->file_exists(path) && !da->dir_exists(path)) { path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(lib_path.get_file()); } + + if (da->dir_exists(path)) { // Target library is a ".framework", add library base name to the path. + path = path.plus_file(path.get_file().get_basename()); + } + + memdelete(da); + #else String path = ProjectSettings::get_singleton()->globalize_path(lib_path); #endif @@ -520,7 +532,7 @@ Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_ RES GDNativeLibraryResourceLoader::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) { Ref<GDNativeLibrary> lib; - lib.instance(); + lib.instantiate(); Ref<ConfigFile> config = lib->get_config_file(); diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index a28c58ec0d..0cc6487ea4 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -138,8 +138,8 @@ struct GDNativeCallRegistry { Vector<StringName> get_native_call_types(); }; -class GDNative : public Reference { - GDCLASS(GDNative, Reference); +class GDNative : public RefCounted { + GDCLASS(GDNative, RefCounted); Ref<GDNativeLibrary> library; diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quaternion.cpp index 8ebcf7c91f..62bcbbd382 100644 --- a/modules/gdnative/gdnative/quat.cpp +++ b/modules/gdnative/gdnative/quaternion.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.cpp */ +/* quaternion.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,31 +28,31 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gdnative/quat.h" +#include "gdnative/quaternion.h" -#include "core/math/quat.h" +#include "core/math/quaternion.h" -static_assert(sizeof(godot_quat) == sizeof(Quat), "Quat size mismatch"); +static_assert(sizeof(godot_quaternion) == sizeof(Quaternion), "Quaternion size mismatch"); #ifdef __cplusplus extern "C" { #endif -void GDAPI godot_quat_new(godot_quat *p_self) { - memnew_placement(p_self, Quat); +void GDAPI godot_quaternion_new(godot_quaternion *p_self) { + memnew_placement(p_self, Quaternion); } -void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src) { - memnew_placement(r_dest, Quat(*(Quat *)p_src)); +void GDAPI godot_quaternion_new_copy(godot_quaternion *r_dest, const godot_quaternion *p_src) { + memnew_placement(r_dest, Quaternion(*(Quaternion *)p_src)); } -godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index) { - Quat *self = (Quat *)p_self; +godot_real_t GDAPI *godot_quaternion_operator_index(godot_quaternion *p_self, godot_int p_index) { + Quaternion *self = (Quaternion *)p_self; return (godot_real_t *)&self->operator[](p_index); } -const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index) { - const Quat *self = (const Quat *)p_self; +const godot_real_t GDAPI *godot_quaternion_operator_index_const(const godot_quaternion *p_self, godot_int p_index) { + const Quaternion *self = (const Quaternion *)p_self; return (const godot_real_t *)&self->operator[](p_index); } diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform_3d.cpp index bfaaa13db2..8bd2a68d63 100644 --- a/modules/gdnative/gdnative/transform.cpp +++ b/modules/gdnative/gdnative/transform_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.cpp */ +/* transform_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,22 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gdnative/transform.h" +#include "gdnative/transform_3d.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" -static_assert(sizeof(godot_transform) == sizeof(Transform), "Transform size mismatch"); +static_assert(sizeof(godot_transform3d) == sizeof(Transform3D), "Transform3D size mismatch"); #ifdef __cplusplus extern "C" { #endif -void GDAPI godot_transform_new(godot_transform *p_self) { - memnew_placement(p_self, Transform); +void GDAPI godot_transform3d_new(godot_transform3d *p_self) { + memnew_placement(p_self, Transform3D); } -void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src) { - memnew_placement(r_dest, Transform(*(Transform *)p_src)); +void GDAPI godot_transform3d_new_copy(godot_transform3d *r_dest, const godot_transform3d *p_src) { + memnew_placement(r_dest, Transform3D(*(Transform3D *)p_src)); } #ifdef __cplusplus diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp index 7801e21ab2..cfb57137bb 100644 --- a/modules/gdnative/gdnative/variant.cpp +++ b/modules/gdnative/gdnative/variant.cpp @@ -30,7 +30,7 @@ #include "gdnative/variant.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/variant/variant.h" #ifdef __cplusplus @@ -143,10 +143,10 @@ void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_p memnew_placement_custom(dest, Variant, Variant(*plane)); } -void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat) { +void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion) { Variant *dest = (Variant *)r_dest; - const Quat *quat = (const Quat *)p_quat; - memnew_placement_custom(dest, Variant, Variant(*quat)); + const Quaternion *quaternion = (const Quaternion *)p_quaternion; + memnew_placement_custom(dest, Variant, Variant(*quaternion)); } void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) { @@ -161,9 +161,9 @@ void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_b memnew_placement_custom(dest, Variant, Variant(*basis)); } -void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans) { +void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans) { Variant *dest = (Variant *)r_dest; - const Transform *trans = (const Transform *)p_trans; + const Transform3D *trans = (const Transform3D *)p_trans; memnew_placement_custom(dest, Variant, Variant(*trans)); } @@ -200,17 +200,17 @@ void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) { Variant *dest = (Variant *)r_dest; const Object *obj = (const Object *)p_obj; - const Reference *reference = Object::cast_to<Reference>(obj); + const RefCounted *ref_counted = Object::cast_to<RefCounted>(obj); REF ref; - if (reference) { - ref = REF(reference); + if (ref_counted) { + ref = REF(ref_counted); } if (!ref.is_null()) { memnew_placement_custom(dest, Variant, Variant(ref)); } else { #if defined(DEBUG_METHODS_ENABLED) - if (reference) { - ERR_PRINT("Reference object has 0 refcount in godot_variant_new_object - you lost it somewhere."); + if (ref_counted) { + ERR_PRINT("RefCounted object has 0 refcount in godot_variant_new_object - you lost it somewhere."); } #endif memnew_placement_custom(dest, Variant, Variant(obj)); @@ -378,10 +378,10 @@ godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self) { return raw_dest; } -godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self) { - godot_quat raw_dest; +godot_quaternion GDAPI godot_variant_as_quaternion(const godot_variant *p_self) { + godot_quaternion raw_dest; const Variant *self = (const Variant *)p_self; - Quat *dest = (Quat *)&raw_dest; + Quaternion *dest = (Quaternion *)&raw_dest; *dest = *self; return raw_dest; } @@ -402,10 +402,10 @@ godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self) { return raw_dest; } -godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self) { - godot_transform raw_dest; +godot_transform3d GDAPI godot_variant_as_transform3d(const godot_variant *p_self) { + godot_transform3d raw_dest; const Variant *self = (const Variant *)p_self; - Transform *dest = (Transform *)&raw_dest; + Transform3D *dest = (Transform3D *)&raw_dest; *dest = *self; return raw_dest; } diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 59b078f2b6..8c65447e5d 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -469,7 +469,7 @@ ] }, { - "name": "godot_variant_new_quat", + "name": "godot_variant_new_quaternion", "return_type": "void", "arguments": [ [ @@ -477,8 +477,8 @@ "r_dest" ], [ - "const godot_quat *", - "p_quat" + "const godot_quaternion *", + "p_quaternion" ] ] }, @@ -511,7 +511,7 @@ ] }, { - "name": "godot_variant_new_transform", + "name": "godot_variant_new_transform3d", "return_type": "void", "arguments": [ [ @@ -519,7 +519,7 @@ "r_dest" ], [ - "const godot_transform *", + "const godot_transform3d *", "p_trans" ] ] @@ -893,8 +893,8 @@ ] }, { - "name": "godot_variant_as_quat", - "return_type": "godot_quat", + "name": "godot_variant_as_quaternion", + "return_type": "godot_quaternion", "arguments": [ [ "const godot_variant *", @@ -923,8 +923,8 @@ ] }, { - "name": "godot_variant_as_transform", - "return_type": "godot_transform", + "name": "godot_variant_as_transform3d", + "return_type": "godot_transform3d", "arguments": [ [ "const godot_variant *", @@ -3866,35 +3866,35 @@ ] }, { - "name": "godot_quat_new", + "name": "godot_quaternion_new", "return_type": "void", "arguments": [ [ - "godot_quat *", + "godot_quaternion *", "p_self" ] ] }, { - "name": "godot_quat_new_copy", + "name": "godot_quaternion_new_copy", "return_type": "void", "arguments": [ [ - "godot_quat *", + "godot_quaternion *", "r_dest" ], [ - "const godot_quat *", + "const godot_quaternion *", "p_src" ] ] }, { - "name": "godot_quat_operator_index", + "name": "godot_quaternion_operator_index", "return_type": "godot_real_t *", "arguments": [ [ - "godot_quat *", + "godot_quaternion *", "p_self" ], [ @@ -3904,11 +3904,11 @@ ] }, { - "name": "godot_quat_operator_index_const", + "name": "godot_quaternion_operator_index_const", "return_type": "const godot_real_t *", "arguments": [ [ - "const godot_quat *", + "const godot_quaternion *", "p_self" ], [ @@ -4344,25 +4344,25 @@ ] }, { - "name": "godot_transform_new", + "name": "godot_transform3d_new", "return_type": "void", "arguments": [ [ - "godot_transform *", + "godot_transform3d *", "r_dest" ] ] }, { - "name": "godot_transform_new_copy", + "name": "godot_transform3d_new_copy", "return_type": "void", "arguments": [ [ - "godot_transform *", + "godot_transform3d *", "r_dest" ], [ - "const godot_transform *", + "const godot_transform3d *", "p_src" ] ] @@ -5068,12 +5068,12 @@ }, { "name": "godot_xr_get_worldscale", - "return_type": "godot_float", + "return_type": "godot_real_t", "arguments": [] }, { "name": "godot_xr_get_reference_frame", - "return_type": "godot_transform", + "return_type": "godot_transform3d", "arguments": [] }, { @@ -5145,7 +5145,7 @@ "p_controller_id" ], [ - "godot_transform *", + "godot_transform3d *", "p_transform" ], [ @@ -5189,7 +5189,7 @@ "p_exis" ], [ - "godot_float", + "godot_real_t", "p_value" ], [ @@ -5200,7 +5200,7 @@ }, { "name": "godot_xr_get_controller_rumble", - "return_type": "godot_float", + "return_type": "godot_real_t", "arguments": [ [ "godot_int", @@ -5716,7 +5716,7 @@ ] }, { - "name": "godot_packed_glyph_array_invert", + "name": "godot_packed_glyph_array_reverse", "return_type": "void", "arguments": [ [ diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp index dfb26c13e3..bdbf151393 100644 --- a/modules/gdnative/gdnative_library_editor_plugin.cpp +++ b/modules/gdnative/gdnative_library_editor_plugin.cpp @@ -131,7 +131,7 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) { EditorFileDialog::FileMode mode = EditorFileDialog::FILE_MODE_OPEN_FILE; if (id == BUTTON_SELECT_DEPENDENCES) { mode = EditorFileDialog::FILE_MODE_OPEN_FILES; - } else if (treeItem->get_text(0) == "iOS") { + } else if (treeItem->get_text(0) == "iOS" || treeItem->get_text(0) == "macOS") { mode = EditorFileDialog::FILE_MODE_OPEN_ANY; } @@ -278,11 +278,10 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() { platforms["X11"] = platform_linux; NativePlatformConfig platform_osx; - platform_osx.name = "Mac OSX"; + platform_osx.name = "macOS"; platform_osx.entries.push_back("64"); - platform_osx.entries.push_back("32"); - platform_osx.library_extension = "*.dylib"; - platforms["OSX"] = platform_osx; + platform_osx.library_extension = "*.framework; Framework, *.dylib; Dynamic Library"; + platforms["macOS"] = platform_osx; NativePlatformConfig platform_haiku; platform_haiku.name = "Haiku"; @@ -357,12 +356,12 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() { tree->set_column_titles_visible(true); tree->set_columns(4); tree->set_column_expand(0, false); - tree->set_column_min_width(0, int(200 * EDSCALE)); + tree->set_column_custom_minimum_width(0, int(200 * EDSCALE)); tree->set_column_title(0, TTR("Platform")); tree->set_column_title(1, TTR("Dynamic Library")); tree->set_column_title(2, TTR("Dependencies")); tree->set_column_expand(3, false); - tree->set_column_min_width(3, int(110 * EDSCALE)); + tree->set_column_custom_minimum_width(3, int(110 * EDSCALE)); tree->connect("button_pressed", callable_mp(this, &GDNativeLibraryEditor::_on_item_button)); tree->connect("item_collapsed", callable_mp(this, &GDNativeLibraryEditor::_on_item_collapsed)); tree->connect("item_activated", callable_mp(this, &GDNativeLibraryEditor::_on_item_activated)); diff --git a/modules/gdnative/include/gdnative/callable.h b/modules/gdnative/include/gdnative/callable.h index b84b0c1f1f..1d52ca7a68 100644 --- a/modules/gdnative/include/gdnative/callable.h +++ b/modules/gdnative/include/gdnative/callable.h @@ -37,6 +37,7 @@ extern "C" { #include <stdint.h> +// Alignment hardcoded in `core/variant/callable.h`. #define GODOT_CALLABLE_SIZE (16) #ifndef GODOT_CORE_API_GODOT_CALLABLE_TYPE_DEFINED diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h index 9af9226a79..d8c290f6bd 100644 --- a/modules/gdnative/include/gdnative/gdnative.h +++ b/modules/gdnative/include/gdnative/gdnative.h @@ -149,9 +149,9 @@ typedef void godot_object; #include <gdnative/plane.h> -/////// Quat +/////// Quaternion -#include <gdnative/quat.h> +#include <gdnative/quaternion.h> /////// AABB @@ -161,9 +161,9 @@ typedef void godot_object; #include <gdnative/basis.h> -/////// Transform +/////// Transform3D -#include <gdnative/transform.h> +#include <gdnative/transform_3d.h> /////// Color diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/quaternion.h index 3861b5683a..75754e6ab5 100644 --- a/modules/gdnative/include/gdnative/transform.h +++ b/modules/gdnative/include/gdnative/quaternion.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.h */ +/* quaternion.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_TRANSFORM_H -#define GODOT_TRANSFORM_H +#ifndef GODOT_QUATERNION_H +#define GODOT_QUATERNION_H #ifdef __cplusplus extern "C" { @@ -37,22 +37,24 @@ extern "C" { #include <gdnative/math_defs.h> -#define GODOT_TRANSFORM_SIZE (sizeof(godot_real_t) * 12) +#define GODOT_QUATERNION_SIZE (sizeof(godot_real_t) * 4) -#ifndef GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED +#ifndef GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED +#define GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED typedef struct { - uint8_t _dont_touch_that[GODOT_TRANSFORM_SIZE]; -} godot_transform; + uint8_t _dont_touch_that[GODOT_QUATERNION_SIZE]; +} godot_quaternion; #endif #include <gdnative/gdnative.h> -void GDAPI godot_transform_new(godot_transform *p_self); -void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src); +void GDAPI godot_quaternion_new(godot_quaternion *p_self); +void GDAPI godot_quaternion_new_copy(godot_quaternion *r_dest, const godot_quaternion *p_src); +godot_real_t GDAPI *godot_quaternion_operator_index(godot_quaternion *p_self, godot_int p_index); +const godot_real_t GDAPI *godot_quaternion_operator_index_const(const godot_quaternion *p_self, godot_int p_index); #ifdef __cplusplus } #endif -#endif // GODOT_TRANSFORM_H +#endif // GODOT_QUATERNION_H diff --git a/modules/gdnative/include/gdnative/signal.h b/modules/gdnative/include/gdnative/signal.h index f4dc17e089..41a76d0510 100644 --- a/modules/gdnative/include/gdnative/signal.h +++ b/modules/gdnative/include/gdnative/signal.h @@ -37,6 +37,7 @@ extern "C" { #include <stdint.h> +// Alignment hardcoded in `core/variant/callable.h`. #define GODOT_SIGNAL_SIZE (16) #ifndef GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/transform_3d.h index 00abdb4404..97ad451e9b 100644 --- a/modules/gdnative/include/gdnative/quat.h +++ b/modules/gdnative/include/gdnative/transform_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.h */ +/* transform_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_QUAT_H -#define GODOT_QUAT_H +#ifndef GODOT_TRANSFORM3D_H +#define GODOT_TRANSFORM3D_H #ifdef __cplusplus extern "C" { @@ -37,24 +37,24 @@ extern "C" { #include <gdnative/math_defs.h> -#define GODOT_QUAT_SIZE (sizeof(godot_real_t) * 4) +#define GODOT_TRANSFORM3D_SIZE (sizeof(godot_real_t) * 12) -#ifndef GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED +#ifndef GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED +#define GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED typedef struct { - uint8_t _dont_touch_that[GODOT_QUAT_SIZE]; -} godot_quat; + uint8_t _dont_touch_that[GODOT_TRANSFORM3D_SIZE]; +} godot_transform3d; #endif #include <gdnative/gdnative.h> -void GDAPI godot_quat_new(godot_quat *p_self); -void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src); -godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index); -const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index); +void GDAPI godot_transform3d_new(godot_transform3d *p_self); +void GDAPI godot_transform3d_new_copy(godot_transform3d *r_dest, const godot_transform3d *p_src); +godot_vector3 GDAPI *godot_transform3d_operator_index(godot_transform3d *p_self, godot_int p_index); +const godot_vector3 GDAPI *godot_transform3d_operator_index_const(const godot_transform3d *p_self, godot_int p_index); #ifdef __cplusplus } #endif -#endif // GODOT_QUAT_H +#endif // GODOT_TRANSFORM3D_H diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h index 3e06ed9aa4..a88bd2878a 100644 --- a/modules/gdnative/include/gdnative/variant.h +++ b/modules/gdnative/include/gdnative/variant.h @@ -56,10 +56,10 @@ typedef enum godot_variant_type { GODOT_VARIANT_TYPE_VECTOR3I, GODOT_VARIANT_TYPE_TRANSFORM2D, GODOT_VARIANT_TYPE_PLANE, - GODOT_VARIANT_TYPE_QUAT, + GODOT_VARIANT_TYPE_QUATERNION, GODOT_VARIANT_TYPE_AABB, GODOT_VARIANT_TYPE_BASIS, - GODOT_VARIANT_TYPE_TRANSFORM, + GODOT_VARIANT_TYPE_TRANSFORM3D, // misc types GODOT_VARIANT_TYPE_COLOR, @@ -164,7 +164,7 @@ typedef void (*godot_validated_keyed_getter)(const godot_variant *p_base, const typedef bool (*godot_validated_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key, bool *r_valid); typedef void (*godot_ptr_keyed_setter)(void *p_base, const void *p_key, const void *p_value); typedef void (*godot_ptr_keyed_getter)(const void *p_base, const void *p_key, void *r_value); -typedef bool (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key); +typedef uint32_t (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key); typedef void (*godot_validated_utility_function)(godot_variant *r_return, const godot_variant **p_arguments, int p_argument_count); typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_arguments, int p_argument_count); @@ -177,14 +177,14 @@ typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_argume #include <gdnative/node_path.h> #include <gdnative/packed_arrays.h> #include <gdnative/plane.h> -#include <gdnative/quat.h> +#include <gdnative/quaternion.h> #include <gdnative/rect2.h> #include <gdnative/rid.h> #include <gdnative/signal.h> #include <gdnative/string.h> #include <gdnative/string_name.h> -#include <gdnative/transform.h> #include <gdnative/transform2d.h> +#include <gdnative/transform_3d.h> #include <gdnative/variant.h> #include <gdnative/vector2.h> #include <gdnative/vector3.h> @@ -208,10 +208,10 @@ void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3 void GDAPI godot_variant_new_vector3i(godot_variant *r_dest, const godot_vector3i *p_v3); void GDAPI godot_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d); void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_plane); -void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat); +void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion); void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb); void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis); -void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans); +void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans); void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color); void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s); void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np); @@ -243,10 +243,10 @@ godot_vector3 GDAPI godot_variant_as_vector3(const godot_variant *p_self); godot_vector3i GDAPI godot_variant_as_vector3i(const godot_variant *p_self); godot_transform2d GDAPI godot_variant_as_transform2d(const godot_variant *p_self); godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self); -godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self); +godot_quaternion GDAPI godot_variant_as_quaternion(const godot_variant *p_self); godot_aabb GDAPI godot_variant_as_aabb(const godot_variant *p_self); godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self); -godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self); +godot_transform3d GDAPI godot_variant_as_transform3d(const godot_variant *p_self); godot_color GDAPI godot_variant_as_color(const godot_variant *p_self); godot_string_name GDAPI godot_variant_as_string_name(const godot_variant *p_self); godot_node_path GDAPI godot_variant_as_node_path(const godot_variant *p_self); diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h index 2fa576a5bf..94e7739ef9 100644 --- a/modules/gdnative/include/net/godot_net.h +++ b/modules/gdnative/include/net/godot_net.h @@ -90,7 +90,7 @@ typedef struct { godot_int (*get_available_packet_count)(const void *); godot_int (*get_max_packet_size)(const void *); - /* This is NetworkedMultiplayerPeer */ + /* This is MultiplayerPeer */ void (*set_transfer_mode)(void *, godot_int); godot_int (*get_transfer_mode)(const void *); // 0 = broadcast, 1 = server, <0 = all but abs(value) diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h index cbd65e3772..02ee4066d0 100644 --- a/modules/gdnative/include/pluginscript/godot_pluginscript.h +++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h @@ -56,11 +56,12 @@ typedef struct { int p_argcount, godot_variant_call_error *r_error); void (*notification)(godot_pluginscript_instance_data *p_data, int p_notification); + godot_string (*to_string)(godot_pluginscript_instance_data *p_data, godot_bool *r_valid); //this is used by script languages that keep a reference counter of their own //you can make make Ref<> not die when it reaches zero, so deleting the reference //depends entirely from the script. - // Note: You can set those function pointer to nullptr if not needed. + // Note: You can set those function pointer to nullptr if not needed. void (*refcount_incremented)(godot_pluginscript_instance_data *p_data); bool (*refcount_decremented)(godot_pluginscript_instance_data *p_data); // return true if it can die } godot_pluginscript_instance_desc; @@ -120,18 +121,18 @@ typedef struct { const char *name; const char *type; const char *extension; - const char **recognized_extensions; // nullptr terminated array + const char **recognized_extensions; // nullptr terminated array godot_pluginscript_language_data *(*init)(); void (*finish)(godot_pluginscript_language_data *p_data); - const char **reserved_words; // nullptr terminated array - const char **comment_delimiters; // nullptr terminated array - const char **string_delimiters; // nullptr terminated array + const char **reserved_words; // nullptr terminated array + const char **comment_delimiters; // nullptr terminated array + const char **string_delimiters; // nullptr terminated array godot_bool has_named_classes; godot_bool supports_builtin_mode; godot_bool can_inherit_from_file; godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name); - godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions); + godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, const godot_string *p_path, godot_packed_string_array *r_functions, godot_array *r_errors); // errors = Array of Dictionary with "line", "column", "message" keys int (*find_function)(godot_pluginscript_language_data *p_data, const godot_string *p_function, const godot_string *p_code); // Can be nullptr godot_string (*make_function)(godot_pluginscript_language_data *p_data, const godot_string *p_class, const godot_string *p_name, const godot_packed_string_array *p_args); godot_error (*complete_code)(godot_pluginscript_language_data *p_data, const godot_string *p_code, const godot_string *p_path, godot_object *p_owner, godot_array *r_options, godot_bool *r_force, godot_string *r_call_hint); diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h index 86fc745134..6428f2f149 100644 --- a/modules/gdnative/include/text/godot_text.h +++ b/modules/gdnative/include/text/godot_text.h @@ -118,6 +118,7 @@ typedef struct { godot_vector2 (*font_get_glyph_kerning)(void *, godot_rid *, uint32_t, uint32_t, int); godot_vector2 (*font_draw_glyph)(void *, godot_rid *, godot_rid *, int, const godot_vector2 *, uint32_t, const godot_color *); godot_vector2 (*font_draw_glyph_outline)(void *, godot_rid *, godot_rid *, int, int, const godot_vector2 *, uint32_t, const godot_color *); + bool (*font_get_glyph_contours)(void *, godot_rid *, int, uint32_t, godot_packed_vector3_array *, godot_packed_int32_array *, bool *); float (*font_get_oversampling)(void *); void (*font_set_oversampling)(void *, float); godot_packed_string_array (*get_system_fonts)(void *); @@ -142,13 +143,14 @@ typedef struct { bool (*shaped_text_shape)(void *, godot_rid *); bool (*shaped_text_update_breaks)(void *, godot_rid *); bool (*shaped_text_update_justification_ops)(void *, godot_rid *); + void (*shaped_text_overrun_trim_to_width)(void *, godot_rid *, float, uint8_t); bool (*shaped_text_is_ready)(void *, godot_rid *); godot_packed_glyph_array (*shaped_text_get_glyphs)(void *, godot_rid *); godot_vector2i (*shaped_text_get_range)(void *, godot_rid *); godot_packed_glyph_array (*shaped_text_sort_logical)(void *, godot_rid *); godot_packed_vector2i_array (*shaped_text_get_line_breaks_adv)(void *, godot_rid *, godot_packed_float32_array *, int, bool, uint8_t); godot_packed_vector2i_array (*shaped_text_get_line_breaks)(void *, godot_rid *, float, int, uint8_t); - godot_packed_vector2i_array (*shaped_text_get_word_breaks)(void *, godot_rid *); + godot_packed_vector2i_array (*shaped_text_get_word_breaks)(void *, godot_rid *, int); godot_array (*shaped_text_get_objects)(void *, godot_rid *); godot_rect2 (*shaped_text_get_object_rect)(void *, godot_rid *, const godot_variant *); godot_vector2 (*shaped_text_get_size)(void *, godot_rid *); @@ -213,7 +215,7 @@ godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self); -void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self); +void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self); void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data); diff --git a/modules/gdnative/include/xr/godot_xr.h b/modules/gdnative/include/xr/godot_xr.h index 7eaf1c7ec3..53cb830cbb 100644 --- a/modules/gdnative/include/xr/godot_xr.h +++ b/modules/gdnative/include/xr/godot_xr.h @@ -41,8 +41,8 @@ extern "C" { // version info to detect whether a call is available // Use these to populate version in your plugin -#define GODOTVR_API_MAJOR 1 -#define GODOTVR_API_MINOR 1 +#define GODOTVR_API_MAJOR 4 +#define GODOTVR_API_MINOR 0 typedef struct { godot_gdnative_api_version version; /* version of our API */ @@ -52,25 +52,32 @@ typedef struct { godot_int (*get_capabilities)(const void *); godot_bool (*get_anchor_detection_is_enabled)(const void *); void (*set_anchor_detection_is_enabled)(void *, godot_bool); - godot_bool (*is_stereo)(const void *); + godot_int (*get_view_count)(const void *); godot_bool (*is_initialized)(const void *); godot_bool (*initialize)(void *); void (*uninitialize)(void *); godot_vector2 (*get_render_targetsize)(const void *); - godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *); - void (*fill_projection_for_eye)(void *, godot_float *, godot_int, godot_float, godot_float, godot_float); - void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *); + + godot_transform3d (*get_camera_transform)(void *); + godot_transform3d (*get_transform_for_view)(void *, godot_int, godot_transform3d *); + void (*fill_projection_for_view)(void *, godot_real_t *, godot_int, godot_real_t, godot_real_t, godot_real_t); + void (*commit_views)(void *, godot_rid *, godot_rect2 *); + void (*process)(void *); - godot_int (*get_external_texture_for_eye)(void *, godot_int); void (*notification)(void *, godot_int); godot_int (*get_camera_feed_id)(void *); + + // possibly deprecate but adding/keeping as a reminder these are in Godot 3 + void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *); + godot_int (*get_external_texture_for_eye)(void *, godot_int); + godot_int (*get_external_depth_for_eye)(void *, godot_int); } godot_xr_interface_gdnative; void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface); // helper functions to access XRServer data -godot_float GDAPI godot_xr_get_worldscale(); -godot_transform GDAPI godot_xr_get_reference_frame(); +godot_real_t GDAPI godot_xr_get_worldscale(); +godot_transform3d GDAPI godot_xr_get_reference_frame(); // helper functions for rendering void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect); @@ -79,10 +86,10 @@ godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target); // helper functions for updating XR controllers godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position); void GDAPI godot_xr_remove_controller(godot_int p_controller_id); -void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position); +void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position); void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed); -void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative); -godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id); +void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative); +godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id); #ifdef __cplusplus } diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index f184c84615..477bc9f74d 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -34,10 +34,11 @@ #include "core/config/engine.h" #include "core/core_constants.h" +#include "core/io/file_access.h" #include "core/object/class_db.h" -#include "core/os/file_access.h" #include "core/string/string_builder.h" #include "core/templates/pair.h" +#include "core/variant/variant_parser.h" // helper stuff @@ -121,7 +122,7 @@ struct ClassAPI { String singleton_name; bool is_instantiable = false; // @Unclear - bool is_reference = false; + bool is_ref_counted = false; bool has_indexing = false; // For builtin types. String indexed_type; // For builtin types. bool is_keyed = false; // For builtin types. @@ -250,14 +251,14 @@ List<ClassAPI> generate_c_api_classes() { class_api.singleton_name = name; } } - class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instance(class_name); + class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instantiate(class_name); { List<StringName> inheriters; - ClassDB::get_inheriters_from_class("Reference", &inheriters); - bool is_reference = !!inheriters.find(class_name) || class_name == "Reference"; + ClassDB::get_inheriters_from_class("RefCounted", &inheriters); + bool is_ref_counted = !!inheriters.find(class_name) || class_name == "RefCounted"; // @Unclear - class_api.is_reference = !class_api.is_singleton && is_reference; + class_api.is_ref_counted = !class_api.is_singleton && is_ref_counted; } // constants @@ -404,7 +405,7 @@ List<ClassAPI> generate_c_api_classes() { arg_type = Variant::get_type_name(arg_info.type); } } else { - arg_type = Variant::get_type_name(arg_info.type); + arg_type = get_type_name(arg_info); } method_api.argument_names.push_back(arg_name); @@ -509,10 +510,10 @@ List<ClassAPI> generate_c_builtin_api_types() { case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: case Variant::PACKED_COLOR_ARRAY: - class_api.is_reference = true; + class_api.is_ref_counted = true; break; default: - class_api.is_reference = false; + class_api.is_ref_counted = false; break; } @@ -638,6 +639,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { // I'm sorry for the \t mess List<String> source; + VariantWriter writer; source.push_back("[\n"); @@ -652,7 +654,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back(String("\t\t\"singleton\": ") + (api.is_singleton ? "true" : "false") + ",\n"); source.push_back("\t\t\"singleton_name\": \"" + api.singleton_name + "\",\n"); source.push_back(String("\t\t\"instantiable\": ") + (api.is_instantiable ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n"); + source.push_back(String("\t\t\"is_ref_counted\": ") + (api.is_ref_counted ? "true" : "false") + ",\n"); source.push_back("\t\t\"constants\": {\n"); for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) { @@ -682,7 +684,12 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n"); source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n"); source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n"); - source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n"); + String default_value; + if (e->get().default_arguments.has(i)) { + writer.write_to_string(e->get().default_arguments[i], default_value); + default_value = default_value.replace("\n", "").json_escape(); + } + source.push_back("\t\t\t\t\t\t\"default_value\": \"" + default_value + "\"\n"); source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n"); } source.push_back("\t\t\t\t]\n"); @@ -708,7 +715,12 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n"); source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n"); source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n"); - source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n"); + String default_value; + if (e->get().default_arguments.has(i)) { + writer.write_to_string(e->get().default_arguments[i], default_value); + default_value = default_value.replace("\n", "").json_escape(); + } + source.push_back("\t\t\t\t\t\t\"default_value\": \"" + default_value + "\"\n"); source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n"); } source.push_back("\t\t\t\t]\n"); @@ -756,6 +768,8 @@ static void append_indented(StringBuilder &p_source, const char *p_text) { } static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_method) { + VariantWriter writer; + append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name)); append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type)); append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false")); @@ -771,7 +785,12 @@ static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_met append_indented(p_source, vformat(R"("name": "%s",)", p_method.argument_names[i])); append_indented(p_source, vformat(R"("type": "%s",)", p_method.argument_types[i])); append_indented(p_source, vformat(R"("has_default_value": %s,)", p_method.default_arguments.has(i) ? "true" : "false")); - append_indented(p_source, vformat(R"("default_value": "%s")", p_method.default_arguments.has(i) ? p_method.default_arguments[i].operator String() : "")); + String default_value; + if (p_method.default_arguments.has(i)) { + writer.write_to_string(p_method.default_arguments[i], default_value); + default_value = default_value.replace("\n", "").json_escape(); + } + append_indented(p_source, vformat(R"("default_value": "%s")", default_value)); indent_level--; append_indented(p_source, i < p_method.argument_count - 1 ? "}," : "}"); @@ -794,7 +813,7 @@ static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) { append_indented(source, vformat(R"("name": "%s",)", class_api.class_name)); append_indented(source, vformat(R"("is_instantiable": %s,)", class_api.is_instantiable ? "true" : "false")); - append_indented(source, vformat(R"("is_reference": %s,)", class_api.is_reference ? "true" : "false")); + append_indented(source, vformat(R"("is_ref_counted": %s,)", class_api.is_ref_counted ? "true" : "false")); append_indented(source, vformat(R"("has_indexing": %s,)", class_api.has_indexing ? "true" : "false")); append_indented(source, vformat(R"("indexed_type": "%s",)", class_api.has_indexing && class_api.indexed_type == "Nil" ? "Variant" : class_api.indexed_type)); append_indented(source, vformat(R"("is_keyed": %s,)", class_api.is_keyed ? "true" : "false")); diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp index b2abf8b8ae..70b14836bf 100644 --- a/modules/gdnative/nativescript/godot_nativescript.cpp +++ b/modules/gdnative/nativescript/godot_nativescript.cpp @@ -70,8 +70,7 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char const NativeScriptDesc *b = desc.base_data; while (b) { - desc.rpc_count += b->rpc_count; - desc.rset_count += b->rset_count; + desc.rpc_methods.append_array(b->rpc_methods); b = b->base_data; } @@ -94,8 +93,6 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const desc.destroy_func = p_destroy_func; desc.is_tool = true; desc.base = p_base; - desc.rpc_count = 0; - desc.rset_count = 0; if (classes->has(p_base)) { desc.base_data = &(*classes)[p_base]; @@ -103,8 +100,7 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const const NativeScriptDesc *b = desc.base_data; while (b) { - desc.rpc_count += b->rpc_count; - desc.rset_count += b->rset_count; + desc.rpc_methods.append_array(b->rpc_methods); b = b->base_data; } @@ -126,13 +122,16 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha method.method = p_method; method.rpc_mode = p_attr.rpc_type; method.rpc_method_id = UINT16_MAX; - if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) { - method.rpc_method_id = E->get().rpc_count; - E->get().rpc_count += 1; - } method.info = MethodInfo(p_function_name); E->get().methods.insert(p_function_name, method); + + if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) { + MultiplayerAPI::RPCConfig nd; + nd.name = String(p_name); + nd.rpc_mode = MultiplayerAPI::RPCMode(p_attr.rpc_type); + E->get().rpc_methods.push_back(nd); + } } void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_nativescript_property_attributes *p_attr, godot_nativescript_property_set_func p_set_func, godot_nativescript_property_get_func p_get_func) { @@ -144,11 +143,6 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c NativeScriptDesc::Property property; property.default_value = *(Variant *)&p_attr->default_value; property.getter = p_get_func; - property.rset_mode = p_attr->rset_type; - if (p_attr->rset_type != GODOT_METHOD_RPC_MODE_DISABLED) { - property.rset_property_id = E->get().rset_count; - E->get().rset_count += 1; - } property.setter = p_set_func; property.info = PropertyInfo((Variant::Type)p_attr->type, p_path, @@ -338,7 +332,7 @@ void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_i } void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) { - return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object); + return nullptr; } void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time) { diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 0025f4bb06..d7943827c2 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -37,10 +37,12 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" -#include "core/os/file_access.h" #include "core/os/os.h" +#include "main/main.h" + #include "scene/main/scene_tree.h" #include "scene/resources/resource_format_text.h" @@ -168,7 +170,7 @@ String NativeScript::get_script_class_icon_path() const { return script_class_icon_path; } -bool NativeScript::can_instance() const { +bool NativeScript::can_instantiate() const { NativeScriptDesc *script_data = get_script_desc(); #ifdef TOOLS_ENABLED @@ -413,245 +415,11 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { } } -Vector<ScriptNetData> NativeScript::get_rpc_methods() const { - Vector<ScriptNetData> v; - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { - if (E->get().rpc_mode != GODOT_METHOD_RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E->key(); - nd.mode = MultiplayerAPI::RPCMode(E->get().rpc_mode); - v.push_back(nd); - } - } - - script_data = script_data->base_data; - } - - return v; -} - -uint16_t NativeScript::get_rpc_method_id(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - return E->get().rpc_method_id; - } - - script_data = script_data->base_data; - } - - return UINT16_MAX; -} - -StringName NativeScript::get_rpc_method(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName()); - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { - if (E->get().rpc_method_id == p_id) { - return E->key(); - } - } - - script_data = script_data->base_data; - } - - return StringName(); -} - -MultiplayerAPI::RPCMode NativeScript::get_rpc_mode_by_id(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED); - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { - if (E->get().rpc_method_id == p_id) { - switch (E->get().rpc_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -MultiplayerAPI::RPCMode NativeScript::get_rpc_mode(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - switch (E->get().rpc_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -Vector<ScriptNetData> NativeScript::get_rset_properties() const { - Vector<ScriptNetData> v; - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (E.get().rset_mode != GODOT_METHOD_RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E.key(); - nd.mode = MultiplayerAPI::RPCMode(E.get().rset_mode); - v.push_back(nd); - } - } - script_data = script_data->base_data; - } - - return v; -} - -uint16_t NativeScript::get_rset_property_id(const StringName &p_variable) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable); - if (E) { - return E.get().rset_property_id; - } - - script_data = script_data->base_data; - } - - return UINT16_MAX; -} - -StringName NativeScript::get_rset_property(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName()); - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (E.get().rset_property_id == p_id) { - return E.key(); - } - } - - script_data = script_data->base_data; - } - - return StringName(); -} - -MultiplayerAPI::RPCMode NativeScript::get_rset_mode_by_id(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED); - +const Vector<MultiplayerAPI::RPCConfig> NativeScript::get_rpc_methods() const { NativeScriptDesc *script_data = get_script_desc(); + ERR_FAIL_COND_V(!script_data, Vector<MultiplayerAPI::RPCConfig>()); - while (script_data) { - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (E.get().rset_property_id == p_id) { - switch (E.get().rset_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -MultiplayerAPI::RPCMode NativeScript::get_rset_mode(const StringName &p_variable) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable); - if (E) { - switch (E.get().rset_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; + return script_data->rpc_methods; } String NativeScript::get_class_documentation() const { @@ -735,9 +503,9 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal Object *owner = nullptr; if (!(script_data->base_native_type == "")) { - owner = ClassDB::instance(script_data->base_native_type); + owner = ClassDB::instantiate(script_data->base_native_type); } else { - owner = memnew(Reference); + owner = memnew(RefCounted); } if (!owner) { @@ -745,7 +513,7 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal return Variant(); } - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -1044,46 +812,10 @@ Ref<Script> NativeScriptInstance::get_script() const { return script; } -Vector<ScriptNetData> NativeScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> NativeScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t NativeScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName NativeScriptInstance::get_rpc_method(uint16_t p_id) const { - return script->get_rpc_method(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const { - return script->get_rpc_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> NativeScriptInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t NativeScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName NativeScriptInstance::get_rset_property(uint16_t p_id) const { - return script->get_rset_property(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode_by_id(uint16_t p_id) const { - return script->get_rset_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - ScriptLanguage *NativeScriptInstance::get_language() { return NativeScriptLanguage::get_singleton(); } @@ -1248,6 +980,7 @@ void NativeScriptLanguage::init() { if (generate_c_api(E->next()->get()) != OK) { ERR_PRINT("Failed to generate C API\n"); } + Main::cleanup(true); exit(0); } @@ -1257,6 +990,7 @@ void NativeScriptLanguage::init() { if (generate_c_builtin_api(E->next()->get()) != OK) { ERR_PRINT("Failed to generate C builtin API\n"); } + Main::cleanup(true); exit(0); } #endif @@ -1285,6 +1019,10 @@ void NativeScriptLanguage::finish() { void NativeScriptLanguage::get_reserved_words(List<String> *p_words) const { } +bool NativeScriptLanguage::is_control_flow_keyword(String p_keyword) const { + return false; +} + void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { } @@ -1297,7 +1035,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const return Ref<NativeScript>(s); } -bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool NativeScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { return true; } @@ -1520,6 +1258,8 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) { } void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) { + return nullptr; +#if 0 ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), nullptr); ERR_FAIL_COND_V_MSG(!binding_functions[p_idx].first, nullptr, "Tried to get binding data for a nativescript binding that does not exist."); @@ -1549,9 +1289,12 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec } return (*binding_data)[p_idx]; +#endif } void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { + return nullptr; +#if 0 Vector<void *> *binding_data = new Vector<void *>; binding_data->resize(binding_functions.size()); @@ -1563,9 +1306,11 @@ void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { binding_instances.insert(binding_data); return (void *)binding_data; +#endif } void NativeScriptLanguage::free_instance_binding_data(void *p_data) { +#if 0 if (!p_data) { return; } @@ -1585,9 +1330,11 @@ void NativeScriptLanguage::free_instance_binding_data(void *p_data) { binding_instances.erase(&binding_data); delete &binding_data; +#endif } void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_object) { +#if 0 void *data = p_object->get_script_instance_binding(lang_idx); if (!data) { @@ -1609,9 +1356,11 @@ void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_objec binding_functions[i].second.refcount_incremented_instance_binding(binding_data[i], p_object); } } +#endif } bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_object) { +#if 0 void *data = p_object->get_script_instance_binding(lang_idx); if (!data) { @@ -1637,6 +1386,8 @@ bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_objec } return can_die; +#endif + return false; } void NativeScriptLanguage::set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag) { @@ -1684,7 +1435,7 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { if (!E) { Ref<GDNative> gdn; - gdn.instance(); + gdn.instantiate(); gdn->set_library(lib); // TODO check the return value? @@ -1729,6 +1480,46 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) { Map<String, Ref<GDNative>>::Element *G = library_gdnatives.find(script->lib_path); if (G && G->get()->get_library()->is_reloadable()) { + // ONLY if the library is marked as reloadable, and no more instances of its scripts exist do we unload the library + + // First remove meta data related to the library + Map<String, Map<StringName, NativeScriptDesc>>::Element *L = library_classes.find(script->lib_path); + if (L) { + Map<StringName, NativeScriptDesc> classes = L->get(); + + for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) { + // free property stuff first + for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) { + if (P.get().getter.free_func) { + P.get().getter.free_func(P.get().getter.method_data); + } + + if (P.get().setter.free_func) { + P.get().setter.free_func(P.get().setter.method_data); + } + } + + // free method stuff + for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) { + if (M->get().method.free_func) { + M->get().method.free_func(M->get().method.method_data); + } + } + + // free constructor/destructor + if (C->get().create_func.free_func) { + C->get().create_func.free_func(C->get().create_func.method_data); + } + + if (C->get().destroy_func.free_func) { + C->get().destroy_func.free_func(C->get().destroy_func.method_data); + } + } + + library_classes.erase(script->lib_path); + } + + // now unload the library G->get()->terminate(); library_gdnatives.erase(G); } diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index d6ba2bbec1..777a878660 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -62,8 +62,6 @@ struct NativeScriptDesc { godot_nativescript_property_get_func getter; PropertyInfo info; Variant default_value; - int rset_mode = 0; - uint16_t rset_property_id; String documentation; }; @@ -72,9 +70,8 @@ struct NativeScriptDesc { String documentation; }; - uint16_t rpc_count = 0; Map<StringName, Method> methods; - uint16_t rset_count = 0; + Vector<MultiplayerAPI::RPCConfig> rpc_methods; OrderedHashMap<StringName, Property> properties; Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals StringName base; @@ -90,8 +87,8 @@ struct NativeScriptDesc { bool is_tool = false; inline NativeScriptDesc() { - zeromem(&create_func, sizeof(godot_nativescript_instance_create_func)); - zeromem(&destroy_func, sizeof(godot_nativescript_instance_destroy_func)); + memset(&create_func, 0, sizeof(godot_nativescript_instance_create_func)); + memset(&destroy_func, 0, sizeof(godot_nativescript_instance_destroy_func)); } }; @@ -140,7 +137,7 @@ public: void set_script_class_icon_path(String p_icon_path); String get_script_class_icon_path() const; - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; //for script inheritance @@ -178,17 +175,7 @@ public: virtual void get_script_method_list(List<MethodInfo> *p_list) const override; virtual void get_script_property_list(List<PropertyInfo> *p_list) const override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const override; - virtual StringName get_rset_property(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; String get_class_documentation() const; String get_method_documentation(const StringName &p_method) const; @@ -226,17 +213,7 @@ public: String to_string(bool *r_valid); virtual Ref<Script> get_script() const; - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; virtual ScriptLanguage *get_language(); @@ -336,10 +313,11 @@ public: virtual Error execute_file(const String &p_path); virtual void finish(); virtual void get_reserved_words(List<String> *p_words) const; + virtual bool is_control_flow_keyword(String p_keyword) const; virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp index 0353ab2092..82a3459517 100644 --- a/modules/gdnative/nativescript/register_types.cpp +++ b/modules/gdnative/nativescript/register_types.cpp @@ -45,15 +45,15 @@ Ref<ResourceFormatSaverNativeScript> resource_saver_gdns; void register_nativescript_types() { native_script_language = memnew(NativeScriptLanguage); - ClassDB::register_class<NativeScript>(); + GDREGISTER_CLASS(NativeScript); native_script_language->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(native_script_language); - resource_saver_gdns.instance(); + resource_saver_gdns.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gdns); - resource_loader_gdns.instance(); + resource_loader_gdns.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gdns); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp index 8b5fc8db5c..8ceba0f339 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -61,13 +61,13 @@ int MultiplayerPeerGDNative::get_available_packet_count() const { return interface->get_available_packet_count(interface->data); } -/* NetworkedMultiplayerPeer */ +/* MultiplayerPeer */ void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) { ERR_FAIL_COND(interface == nullptr); interface->set_transfer_mode(interface->data, (godot_int)p_mode); } -NetworkedMultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { +MultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { ERR_FAIL_COND_V(interface == nullptr, TRANSFER_MODE_UNRELIABLE); return (TransferMode)interface->get_transfer_mode(interface->data); } @@ -107,7 +107,7 @@ bool MultiplayerPeerGDNative::is_refusing_new_connections() const { return interface->is_refusing_new_connections(interface->data); } -NetworkedMultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const { +MultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const { ERR_FAIL_COND_V(interface == nullptr, CONNECTION_DISCONNECTED); return (ConnectionStatus)interface->get_connection_status(interface->data); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h index 593b2534dd..7c10ab77f7 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.h +++ b/modules/gdnative/net/multiplayer_peer_gdnative.h @@ -31,12 +31,12 @@ #ifndef MULTIPLAYER_PEER_GDNATIVE_H #define MULTIPLAYER_PEER_GDNATIVE_H -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "modules/gdnative/gdnative.h" #include "modules/gdnative/include/net/godot_net.h" -class MultiplayerPeerGDNative : public NetworkedMultiplayerPeer { - GDCLASS(MultiplayerPeerGDNative, NetworkedMultiplayerPeer); +class MultiplayerPeerGDNative : public MultiplayerPeer { + GDCLASS(MultiplayerPeerGDNative, MultiplayerPeer); protected: static void _bind_methods(); @@ -55,7 +55,7 @@ public: virtual int get_max_packet_size() const override; virtual int get_available_packet_count() const override; - /* Specific to NetworkedMultiplayerPeer */ + /* Specific to MultiplayerPeer */ virtual void set_transfer_mode(TransferMode p_mode) override; virtual TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer_id) override; diff --git a/modules/gdnative/net/register_types.cpp b/modules/gdnative/net/register_types.cpp index 645c43b7e3..46c383e5ae 100644 --- a/modules/gdnative/net/register_types.cpp +++ b/modules/gdnative/net/register_types.cpp @@ -34,9 +34,9 @@ #include "stream_peer_gdnative.h" void register_net_types() { - ClassDB::register_class<MultiplayerPeerGDNative>(); - ClassDB::register_class<PacketPeerGDNative>(); - ClassDB::register_class<StreamPeerGDNative>(); + GDREGISTER_CLASS(MultiplayerPeerGDNative); + GDREGISTER_CLASS(PacketPeerGDNative); + GDREGISTER_CLASS(StreamPeerGDNative); } void unregister_net_types() { diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp index 432aa80325..ed1c0af3ed 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.cpp +++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp @@ -93,44 +93,15 @@ void PluginScriptInstance::notification(int p_notification) { _desc->notification(_data, p_notification); } -Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const { - return _script->get_rpc_methods(); -} - -uint16_t PluginScriptInstance::get_rpc_method_id(const StringName &p_variable) const { - return _script->get_rpc_method_id(p_variable); -} - -StringName PluginScriptInstance::get_rpc_method(uint16_t p_id) const { - return _script->get_rpc_method(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const { - return _script->get_rpc_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const { - return _script->get_rpc_mode(p_method); +String PluginScriptInstance::to_string(bool *r_valid) { + godot_string ret = _desc->to_string(_data, r_valid); + String str_ret = *(String *)&ret; + godot_string_destroy(&ret); + return str_ret; } -Vector<ScriptNetData> PluginScriptInstance::get_rset_properties() const { - return _script->get_rset_properties(); -} - -uint16_t PluginScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return _script->get_rset_property_id(p_variable); -} - -StringName PluginScriptInstance::get_rset_property(uint16_t p_id) const { - return _script->get_rset_property(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode_by_id(uint16_t p_id) const { - return _script->get_rset_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const { - return _script->get_rset_mode(p_variable); +const Vector<MultiplayerAPI::RPCConfig> PluginScriptInstance::get_rpc_methods() const { + return _script->get_rpc_methods(); } void PluginScriptInstance::refcount_incremented() { diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h index 536eb550e0..25b62ae8ab 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -63,6 +63,7 @@ public: virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual void notification(int p_notification); + virtual String to_string(bool *r_valid); virtual Ref<Script> get_script() const; @@ -70,17 +71,7 @@ public: void set_path(const String &p_path); - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; virtual void refcount_incremented(); virtual bool refcount_decremented(); diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 3ed1dcaca9..79aba342c9 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -30,7 +30,7 @@ // Godot imports #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" // PluginScript imports #include "pluginscript_language.h" @@ -77,6 +77,10 @@ void PluginScriptLanguage::get_reserved_words(List<String> *p_words) const { } } +bool PluginScriptLanguage::is_control_flow_keyword(String p_keyword) const { + return false; +} + void PluginScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { if (_desc.comment_delimiters) { const char **w = _desc.comment_delimiters; @@ -108,20 +112,29 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const return script; } -bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool PluginScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { PackedStringArray functions; + Array errors; if (_desc.validate) { bool ret = _desc.validate( _data, (godot_string *)&p_script, - &r_line_error, - &r_col_error, - (godot_string *)&r_test_error, (godot_string *)&p_path, - (godot_packed_string_array *)&functions); + (godot_packed_string_array *)&functions, + (godot_array *)&errors); for (int i = 0; i < functions.size(); i++) { r_functions->push_back(functions[i]); } + if (r_errors) { + for (int i = 0; i < errors.size(); i++) { + Dictionary error = errors[i]; + ScriptLanguage::ScriptError e; + e.line = error["line"]; + e.column = error["column"]; + e.message = error["message"]; + r_errors->push_back(e); + } + } return ret; } return true; diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index 226b039265..26ab4a95e3 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -71,10 +71,11 @@ public: /* EDITOR FUNCTIONS */ virtual void get_reserved_words(List<String> *p_words) const; + virtual bool is_control_flow_keyword(String p_keyword) const; virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp index f2165cd225..462452a897 100644 --- a/modules/gdnative/pluginscript/pluginscript_loader.cpp +++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ // Godot imports -#include "core/os/file_access.h" +#include "core/io/file_access.h" // Pythonscript imports #include "pluginscript_language.h" #include "pluginscript_loader.h" diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index 31e6a81975..7fc8178e34 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ // Godot imports -#include "core/os/file_access.h" +#include "core/io/file_access.h" // PluginScript imports #include "pluginscript_instance.h" #include "pluginscript_script.h" @@ -38,13 +38,13 @@ #ifdef DEBUG_ENABLED #define __ASSERT_SCRIPT_REASON "Cannot retrieve PluginScript class for this script, is your code correct?" -#define ASSERT_SCRIPT_VALID() \ - { \ - ERR_FAIL_COND_MSG(!can_instance(), __ASSERT_SCRIPT_REASON); \ +#define ASSERT_SCRIPT_VALID() \ + { \ + ERR_FAIL_COND_MSG(!can_instantiate(), __ASSERT_SCRIPT_REASON); \ } -#define ASSERT_SCRIPT_VALID_V(ret) \ - { \ - ERR_FAIL_COND_V_MSG(!can_instance(), ret, __ASSERT_SCRIPT_REASON); \ +#define ASSERT_SCRIPT_VALID_V(ret) \ + { \ + ERR_FAIL_COND_V_MSG(!can_instantiate(), ret, __ASSERT_SCRIPT_REASON); \ } #else #define ASSERT_SCRIPT_VALID() @@ -94,9 +94,9 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal Object *owner = nullptr; if (get_instance_base_type() == "") { - owner = memnew(Reference); + owner = memnew(RefCounted); } else { - owner = ClassDB::instance(get_instance_base_type()); + owner = ClassDB::instantiate(get_instance_base_type()); } if (!owner) { @@ -104,7 +104,7 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal return Variant(); } - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -133,7 +133,7 @@ void PluginScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) #endif -bool PluginScript::can_instance() const { +bool PluginScript::can_instantiate() const { bool can = _valid || (!_tool && !ScriptServer::is_scripting_enabled()); return can; } @@ -198,7 +198,7 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) { StringName base_type = get_instance_base_type(); if (base_type) { if (!ClassDB::is_parent_class(p_this->get_class_name(), base_type)) { - String msg = "Script inherits from native type '" + String(base_type) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"; + String msg = "Script inherits from native type '" + String(base_type) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"; // TODO: implement PluginscriptLanguage::debug_break_parse // if (EngineDebugger::is_active()) { // _language->debug_break_parse(get_path(), 0, msg); @@ -212,6 +212,8 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) { } bool PluginScript::instance_has(const Object *p_this) const { + ERR_FAIL_COND_V(!_language, false); + _language->lock(); bool hasit = _instances.has((Object *)p_this); _language->unlock(); @@ -310,10 +312,9 @@ Error PluginScript::reload(bool p_keep_state) { } Array *methods = (Array *)&manifest.methods; _rpc_methods.clear(); - _rpc_variables.clear(); if (_ref_base_parent.is_valid()) { + /// XXX TODO Should this be _rpc_methods.append_array(...) _rpc_methods = _ref_base_parent->get_rpc_methods(); - _rpc_variables = _ref_base_parent->get_rset_properties(); } for (int i = 0; i < methods->size(); ++i) { Dictionary v = (*methods)[i]; @@ -322,9 +323,10 @@ Error PluginScript::reload(bool p_keep_state) { // rpc_mode is passed as an optional field and is not part of MethodInfo Variant var = v["rpc_mode"]; if (var != Variant()) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = mi.name; - nd.mode = MultiplayerAPI::RPCMode(int(var)); + nd.rpc_mode = MultiplayerAPI::RPCMode(int(var)); + // TODO Transfer Channel if (_rpc_methods.find(nd) == -1) { _rpc_methods.push_back(nd); } @@ -332,7 +334,7 @@ Error PluginScript::reload(bool p_keep_state) { } // Sort so we are 100% that they are always the same. - _rpc_methods.sort_custom<SortNetData>(); + _rpc_methods.sort_custom<MultiplayerAPI::SortRPCConfig>(); Array *signals = (Array *)&manifest.signals; for (int i = 0; i < signals->size(); ++i) { @@ -346,21 +348,8 @@ Error PluginScript::reload(bool p_keep_state) { PropertyInfo pi = PropertyInfo::from_dict(v); _properties_info[pi.name] = pi; _properties_default_values[pi.name] = v["default_value"]; - // rset_mode is passed as an optional field and is not part of PropertyInfo - Variant var = v["rset_mode"]; - if (var != Variant()) { - ScriptNetData nd; - nd.name = pi.name; - nd.mode = MultiplayerAPI::RPCMode(int(var)); - if (_rpc_variables.find(nd) == -1) { - _rpc_variables.push_back(nd); - } - } } - // Sort so we are 100% that they are always the same. - _rpc_variables.sort_custom<SortNetData>(); - #ifdef TOOLS_ENABLED /*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { @@ -441,10 +430,10 @@ Error PluginScript::load_source_code(const String &p_path) { FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + p_path + "'."); - int len = f->get_len(); + uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); - int r = f->get_buffer(w, len); + uint64_t r = f->get_buffer(w, len); f->close(); memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); @@ -484,76 +473,10 @@ int PluginScript::get_member_line(const StringName &p_member) const { return -1; } -Vector<ScriptNetData> PluginScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> PluginScript::get_rpc_methods() const { return _rpc_methods; } -uint16_t PluginScript::get_rpc_method_id(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(UINT16_MAX); - for (int i = 0; i < _rpc_methods.size(); i++) { - if (_rpc_methods[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName PluginScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ASSERT_SCRIPT_VALID_V(StringName()); - if (p_rpc_method_id >= _rpc_methods.size()) { - return StringName(); - } - return _rpc_methods[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode PluginScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - if (p_rpc_method_id >= _rpc_methods.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return _rpc_methods[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> PluginScript::get_rset_properties() const { - return _rpc_variables; -} - -uint16_t PluginScript::get_rset_property_id(const StringName &p_property) const { - ASSERT_SCRIPT_VALID_V(UINT16_MAX); - for (int i = 0; i < _rpc_variables.size(); i++) { - if (_rpc_variables[i].name == p_property) { - return i; - } - } - return UINT16_MAX; -} - -StringName PluginScript::get_rset_property(const uint16_t p_rset_property_id) const { - ASSERT_SCRIPT_VALID_V(StringName()); - if (p_rset_property_id >= _rpc_variables.size()) { - return StringName(); - } - return _rpc_variables[p_rset_property_id].name; -} - -MultiplayerAPI::RPCMode PluginScript::get_rset_mode_by_id(const uint16_t p_rset_property_id) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - if (p_rset_property_id >= _rpc_variables.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return _rpc_variables[p_rset_property_id].mode; -} - -MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - PluginScript::PluginScript() : _script_list(this) { } diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h index 1c86f2056d..838195147f 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.h +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -61,8 +61,7 @@ private: Map<StringName, PropertyInfo> _properties_info; Map<StringName, MethodInfo> _signals_info; Map<StringName, MethodInfo> _methods_info; - Vector<ScriptNetData> _rpc_methods; - Vector<ScriptNetData> _rpc_variables; + Vector<MultiplayerAPI::RPCConfig> _rpc_methods; Set<Object *> _instances; //exported members @@ -93,7 +92,7 @@ public: return _icon_path; } - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; //for script inheritance @@ -137,17 +136,7 @@ public: virtual int get_member_line(const StringName &p_member) const override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_property) const override; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; PluginScript(); void init(PluginScriptLanguage *language); diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp index b94538b2f7..7faacfdcb9 100644 --- a/modules/gdnative/pluginscript/register_types.cpp +++ b/modules/gdnative/pluginscript/register_types.cpp @@ -31,9 +31,9 @@ #include "register_types.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/dir_access.h" #include "core/os/os.h" #include "scene/main/scene_tree.h" @@ -107,7 +107,7 @@ void GDAPI godot_pluginscript_register_language(const godot_pluginscript_languag } void register_pluginscript_types() { - ClassDB::register_class<PluginScript>(); + GDREGISTER_CLASS(PluginScript); } void unregister_pluginscript_types() { diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index d08bde9e23..8e5ae29ed9 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -230,7 +230,7 @@ static void editor_init_callback() { ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(library_editor); Ref<GDNativeExportPlugin> export_plugin; - export_plugin.instance(); + export_plugin.instantiate(); EditorExport::get_singleton()->add_export_plugin(export_plugin); @@ -259,13 +259,13 @@ void register_gdnative_types() { EditorNode::add_init_callback(editor_init_callback); #endif - ClassDB::register_class<GDNativeLibrary>(); - ClassDB::register_class<GDNative>(); + GDREGISTER_CLASS(GDNativeLibrary); + GDREGISTER_CLASS(GDNative); - resource_loader_gdnlib.instance(); + resource_loader_gdnlib.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gdnlib); - resource_saver_gdnlib.instance(); + resource_saver_gdnlib.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gdnlib); GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry); @@ -298,7 +298,7 @@ void register_gdnative_types() { Ref<GDNativeLibrary> lib = ResourceLoader::load(path); Ref<GDNative> singleton; - singleton.instance(); + singleton.instantiate(); singleton->set_library(lib); if (!singleton->initialize()) { @@ -363,7 +363,7 @@ void unregister_gdnative_types() { print_line(String("aabb:\t") + itos(sizeof(AABB))); print_line(String("rid:\t") + itos(sizeof(RID))); print_line(String("string:\t") + itos(sizeof(String))); - print_line(String("transform:\t") + itos(sizeof(Transform))); + print_line(String("transform:\t") + itos(sizeof(Transform3D))); print_line(String("transfo2D:\t") + itos(sizeof(Transform2D))); print_line(String("variant:\t") + itos(sizeof(Variant))); print_line(String("vector2:\t") + itos(sizeof(Vector2))); diff --git a/modules/gdnative/tests/test_variant.h b/modules/gdnative/tests/test_variant.h index aeceb6e68f..2850036604 100644 --- a/modules/gdnative/tests/test_variant.h +++ b/modules/gdnative/tests/test_variant.h @@ -107,7 +107,7 @@ TEST_CASE("[GDNative Variant] Variant call") { godot_string_name_new_with_latin1_chars(&method, "is_valid_identifier"); godot_variant_call_error error; - godot_variant_call(&self, &method, NULL, 0, &ret, &error); + godot_variant_call(&self, &method, nullptr, 0, &ret, &error); CHECK(godot_variant_get_type(&ret) == GODOT_VARIANT_TYPE_BOOL); CHECK(godot_variant_as_bool(&ret)); diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp index 7cd8de5f2e..81dd570bcb 100644 --- a/modules/gdnative/text/text_server_gdnative.cpp +++ b/modules/gdnative/text/text_server_gdnative.cpp @@ -359,6 +359,12 @@ Vector2 TextServerGDNative::font_draw_glyph_outline(RID p_font, RID p_canvas, in return advance; } +bool TextServerGDNative::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { + ERR_FAIL_COND_V(interface == nullptr, false); + ERR_FAIL_COND_V(interface->font_get_glyph_contours == nullptr, false); + return interface->font_get_glyph_contours(data, (godot_rid *)&p_font, p_size, p_index, (godot_packed_vector3_array *)&r_points, (godot_packed_int32_array *)&r_contours, (bool *)&r_orientation); +} + float TextServerGDNative::font_get_oversampling() const { ERR_FAIL_COND_V(interface == nullptr, 1.f); return interface->font_get_oversampling(data); @@ -492,6 +498,11 @@ bool TextServerGDNative::shaped_text_update_justification_ops(RID p_shaped) { return interface->shaped_text_update_justification_ops(data, (godot_rid *)&p_shaped); } +void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) { + ERR_FAIL_COND(interface == nullptr); + interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_clip_flags); +}; + bool TextServerGDNative::shaped_text_is_ready(RID p_shaped) const { ERR_FAIL_COND_V(interface == nullptr, false); return interface->shaped_text_is_ready(data, (godot_rid *)&p_shaped); @@ -544,15 +555,15 @@ Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks(RID p_shaped, f } } -Vector<Vector2i> TextServerGDNative::shaped_text_get_word_breaks(RID p_shaped) const { +Vector<Vector2i> TextServerGDNative::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const { ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>()); if (interface->shaped_text_get_word_breaks != nullptr) { - godot_packed_vector2i_array result = interface->shaped_text_get_word_breaks(data, (godot_rid *)&p_shaped); + godot_packed_vector2i_array result = interface->shaped_text_get_word_breaks(data, (godot_rid *)&p_shaped, p_grapheme_flags); Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result; godot_packed_vector2i_array_destroy(&result); return breaks; } else { - return TextServer::shaped_text_get_word_breaks(p_shaped); + return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags); } } @@ -841,9 +852,9 @@ void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self) { self->sort(); } -void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self) { +void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self) { Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self; - self->invert(); + self->reverse(); } void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data) { diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h index 931bb44885..7a0725f3d9 100644 --- a/modules/gdnative/text/text_server_gdnative.h +++ b/modules/gdnative/text/text_server_gdnative.h @@ -126,6 +126,8 @@ public: virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override; + virtual float font_get_oversampling() const override; virtual void font_set_oversampling(float p_oversampling) override; @@ -165,6 +167,8 @@ public: virtual bool shaped_text_update_breaks(RID p_shaped) override; virtual bool shaped_text_update_justification_ops(RID p_shaped) override; + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override; + virtual bool shaped_text_is_ready(RID p_shaped) const override; virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override; @@ -174,7 +178,7 @@ public: virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override; virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override; virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint8_t p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override; - virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped) const override; + virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const override; virtual Array shaped_text_get_objects(RID p_shaped) const override; virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override; diff --git a/modules/gdnative/videodecoder/register_types.cpp b/modules/gdnative/videodecoder/register_types.cpp index 394831daeb..54a577a2b6 100644 --- a/modules/gdnative/videodecoder/register_types.cpp +++ b/modules/gdnative/videodecoder/register_types.cpp @@ -36,10 +36,10 @@ static Ref<ResourceFormatLoaderVideoStreamGDNative> resource_loader_vsgdnative; void register_videodecoder_types() { - resource_loader_vsgdnative.instance(); + resource_loader_vsgdnative.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_vsgdnative, true); - ClassDB::register_class<VideoStreamGDNative>(); + GDREGISTER_CLASS(VideoStreamGDNative); } void unregister_videodecoder_types() { diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp index f2fb0a2fdc..4c9bfb395d 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp @@ -47,11 +47,7 @@ godot_int GDAPI godot_videodecoder_file_read(void *ptr, uint8_t *buf, int buf_si // if file exists if (file) { - long bytes_read = file->get_buffer(buf, buf_size); - // No bytes to read => EOF - if (bytes_read == 0) { - return 0; - } + int64_t bytes_read = file->get_buffer(buf, buf_size); return bytes_read; } return -1; @@ -62,41 +58,35 @@ int64_t GDAPI godot_videodecoder_file_seek(void *ptr, int64_t pos, int whence) { FileAccess *file = reinterpret_cast<FileAccess *>(ptr); if (file) { - size_t len = file->get_len(); + int64_t len = file->get_length(); switch (whence) { case SEEK_SET: { - // Just for explicitness - size_t new_pos = static_cast<size_t>(pos); - if (new_pos > len) { + if (pos > len) { return -1; } - file->seek(new_pos); - pos = static_cast<int64_t>(file->get_position()); - return pos; + file->seek(pos); + return file->get_position(); } break; case SEEK_CUR: { // Just in case it doesn't exist - if (pos < 0 && (size_t)-pos > file->get_position()) { + if (pos < 0 && -pos > (int64_t)file->get_position()) { return -1; } - pos = pos + static_cast<int>(file->get_position()); - file->seek(pos); - pos = static_cast<int64_t>(file->get_position()); - return pos; + file->seek(file->get_position() + pos); + return file->get_position(); } break; case SEEK_END: { // Just in case something goes wrong - if ((size_t)-pos > len) { + if (-pos > len) { return -1; } file->seek_end(pos); - pos = static_cast<int64_t>(file->get_position()); - return pos; + return file->get_position(); } break; default: { // Only 4 possible options, hence default = AVSEEK_SIZE // Asks to return the length of file - return static_cast<int64_t>(len); + return len; } break; } } @@ -132,7 +122,7 @@ bool VideoStreamPlaybackGDNative::open_file(const String &p_file) { samples_decoded = 0; Ref<Image> img; - img.instance(); + img.instantiate(); img->create((int)texture_size.width, false, (int)texture_size.height, Image::FORMAT_RGBA8); texture->create_from_image(img); @@ -195,7 +185,7 @@ void VideoStreamPlaybackGDNative::update_texture() { Ref<Image> img = memnew(Image(texture_size.width, texture_size.height, 0, Image::FORMAT_RGBA8, *pba)); - texture->update(img, true); + texture->update(img); } // ctor and dtor diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h index 140888cd4b..c605dbb433 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.h +++ b/modules/gdnative/videodecoder/video_stream_gdnative.h @@ -32,7 +32,7 @@ #define VIDEO_STREAM_GDNATIVE_H #include "../gdnative.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "scene/resources/texture.h" #include "scene/resources/video_stream.h" diff --git a/modules/gdnative/xr/register_types.cpp b/modules/gdnative/xr/register_types.cpp index b60a04f470..cb043debc5 100644 --- a/modules/gdnative/xr/register_types.cpp +++ b/modules/gdnative/xr/register_types.cpp @@ -32,7 +32,7 @@ #include "xr_interface_gdnative.h" void register_xr_types() { - ClassDB::register_class<XRInterfaceGDNative>(); + GDREGISTER_CLASS(XRInterfaceGDNative); ClassDB::add_compatibility_class("ARVRInterfaceGDNative", "XRInterfaceGDNative"); } diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp index 1d5a9d98f8..e51542e23d 100644 --- a/modules/gdnative/xr/xr_interface_gdnative.cpp +++ b/modules/gdnative/xr/xr_interface_gdnative.cpp @@ -70,8 +70,13 @@ void XRInterfaceGDNative::set_interface(const godot_xr_interface_gdnative *p_int // this should only be called once, just being paranoid.. if (interface) { cleanup(); + interface = NULL; } + // validate + ERR_FAIL_NULL(p_interface); + ERR_FAIL_COND_MSG(p_interface->version.major < 4, "This is an incompatible GDNative XR plugin."); + // bind to our interface interface = p_interface; @@ -119,14 +124,14 @@ int XRInterfaceGDNative::get_camera_feed_id() { return (unsigned int)interface->get_camera_feed_id(data); } -bool XRInterfaceGDNative::is_stereo() { - bool stereo; +uint32_t XRInterfaceGDNative::get_view_count() { + uint32_t view_count; - ERR_FAIL_COND_V(interface == nullptr, false); + ERR_FAIL_COND_V(interface == nullptr, 1); - stereo = interface->is_stereo(data); + view_count = interface->get_view_count(data); - return stereo; + return view_count; } bool XRInterfaceGDNative::is_initialized() const { @@ -173,28 +178,52 @@ Size2 XRInterfaceGDNative::get_render_targetsize() { return *vec; } -Transform XRInterfaceGDNative::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { - Transform *ret; +Transform3D XRInterfaceGDNative::get_camera_transform() { + Transform3D *ret; + + ERR_FAIL_COND_V(interface == nullptr, Transform3D()); + + godot_transform3d t = interface->get_camera_transform(data); + + ret = (Transform3D *)&t; + + return *ret; +} + +Transform3D XRInterfaceGDNative::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + Transform3D *ret; - ERR_FAIL_COND_V(interface == nullptr, Transform()); + ERR_FAIL_COND_V(interface == nullptr, Transform3D()); - godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform); + godot_transform3d t = interface->get_transform_for_view(data, (int)p_view, (godot_transform3d *)&p_cam_transform); - ret = (Transform *)&t; + ret = (Transform3D *)&t; return *ret; } -CameraMatrix XRInterfaceGDNative::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix XRInterfaceGDNative::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { CameraMatrix cm; ERR_FAIL_COND_V(interface == nullptr, CameraMatrix()); - interface->fill_projection_for_eye(data, (godot_float *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far); + interface->fill_projection_for_view(data, (godot_real_t *)cm.matrix, (godot_int)p_view, p_aspect, p_z_near, p_z_far); return cm; } +Vector<BlitToScreen> XRInterfaceGDNative::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { + // possibly move this as a member variable and add a callback to populate? + Vector<BlitToScreen> blit_to_screen; + + ERR_FAIL_COND_V(interface == nullptr, blit_to_screen); + + // must implement + interface->commit_views(data, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect); + + return blit_to_screen; +} + unsigned int XRInterfaceGDNative::get_external_texture_for_eye(XRInterface::Eyes p_eye) { ERR_FAIL_COND_V(interface == nullptr, 0); @@ -229,27 +258,27 @@ void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_inte ERR_FAIL_COND_MSG(p_interface->version.major < 4, "GDNative XR interfaces build for Godot 3.x are not supported."); Ref<XRInterfaceGDNative> new_interface; - new_interface.instance(); + new_interface.instantiate(); new_interface->set_interface((const godot_xr_interface_gdnative *)p_interface); XRServer::get_singleton()->add_interface(new_interface); } -godot_float GDAPI godot_xr_get_worldscale() { +godot_real_t GDAPI godot_xr_get_worldscale() { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 1.0); return xr_server->get_world_scale(); } -godot_transform GDAPI godot_xr_get_reference_frame() { - godot_transform reference_frame; - Transform *reference_frame_ptr = (Transform *)&reference_frame; +godot_transform3d GDAPI godot_xr_get_reference_frame() { + godot_transform3d reference_frame; + Transform3D *reference_frame_ptr = (Transform3D *)&reference_frame; XRServer *xr_server = XRServer::get_singleton(); if (xr_server != nullptr) { *reference_frame_ptr = xr_server->get_reference_frame(); } else { - memnew_placement(&reference_frame, Transform); + memnew_placement(&reference_frame, Transform3D); } return reference_frame; @@ -301,7 +330,8 @@ godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, g Input *input = Input::get_singleton(); ERR_FAIL_NULL_V(input, 0); - XRPositionalTracker *new_tracker = memnew(XRPositionalTracker); + Ref<XRPositionalTracker> new_tracker; + new_tracker.instantiate(); new_tracker->set_tracker_name(p_device_name); new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); if (p_hand == 1) { @@ -340,8 +370,8 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) { Input *input = Input::get_singleton(); ERR_FAIL_NULL(input); - XRPositionalTracker *remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); - if (remove_tracker != nullptr) { + Ref<XRPositionalTracker> remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); + if (remove_tracker.is_valid()) { // unset our joystick if applicable int joyid = remove_tracker->get_joy_id(); if (joyid != -1) { @@ -351,17 +381,17 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) { // remove our tracker from our server xr_server->remove_tracker(remove_tracker); - memdelete(remove_tracker); + remove_tracker.unref(); } } -void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) { +void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); - if (tracker != nullptr) { - Transform *transform = (Transform *)p_transform; + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker.is_valid()) { + Transform3D *transform = (Transform3D *)p_transform; if (p_tracks_orientation) { tracker->set_orientation(transform->basis); } @@ -378,40 +408,40 @@ void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p Input *input = Input::get_singleton(); ERR_FAIL_NULL(input); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); - if (tracker != nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker.is_valid()) { int joyid = tracker->get_joy_id(); if (joyid != -1) { - input->joy_button(joyid, p_button, p_is_pressed); + input->joy_button(joyid, (JoyButton)p_button, p_is_pressed); } } } -void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative) { +void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); Input *input = Input::get_singleton(); ERR_FAIL_NULL(input); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); - if (tracker != nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker.is_valid()) { int joyid = tracker->get_joy_id(); if (joyid != -1) { Input::JoyAxisValue jx; jx.min = p_can_be_negative ? -1 : 0; jx.value = p_value; - input->joy_axis(joyid, p_axis, jx); + input->joy_axis(joyid, (JoyAxis)p_axis, jx); } } } -godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) { +godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 0.0); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); - if (tracker != nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); + if (tracker.is_valid()) { return tracker->get_rumble(); } diff --git a/modules/gdnative/xr/xr_interface_gdnative.h b/modules/gdnative/xr/xr_interface_gdnative.h index 84bd8fc731..42e9206c1f 100644 --- a/modules/gdnative/xr/xr_interface_gdnative.h +++ b/modules/gdnative/xr/xr_interface_gdnative.h @@ -72,20 +72,24 @@ public: /** rendering and internal **/ virtual Size2 get_render_targetsize() override; - virtual bool is_stereo() override; - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; // we expose a Vector<float> version of this function to GDNative Vector<float> _get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); // and a CameraMatrix version to XRServer - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; - virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override; - virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; + virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void process() override; virtual void notification(int p_what) override; + + // deprecated + virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; + virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override; }; #endif // XR_INTERFACE_GDNATIVE_H diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 9e974b6fdc..839aa6b3c6 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -177,7 +177,7 @@ [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. [codeblock] # Instance a scene. - var diamond = preload("res://diamond.tscn").instance() + var diamond = preload("res://diamond.tscn").instantiate() [/codeblock] </description> </method> @@ -240,10 +240,10 @@ </method> </methods> <constants> - <constant name="PI" value="3.141593"> + <constant name="PI" value="3.14159265358979"> Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code]. </constant> - <constant name="TAU" value="6.283185"> + <constant name="TAU" value="6.28318530717959"> The circle constant, the circumference of the unit circle in radians. </constant> <constant name="INF" value="inf"> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index ccc942d86b..79ec9eb65f 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -64,6 +64,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) bool in_function_args = false; bool in_member_variable = false; bool in_node_path = false; + bool in_annotation = false; bool is_hex_notation = false; bool is_bin_notation = false; bool expect_type = false; @@ -357,9 +358,18 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) in_node_path = false; } + if (!in_annotation && in_region == -1 && str[j] == '@') { + in_annotation = true; + } else if (in_region != -1 || is_a_symbol) { + in_annotation = false; + } + if (in_node_path) { next_type = NODE_PATH; color = node_path_color; + } else if (in_annotation) { + next_type = ANNOTATION; + color = annotation_color; } else if (in_keyword) { next_type = KEYWORD; color = keyword_color; @@ -485,10 +495,15 @@ void GDScriptSyntaxHighlighter::_update_cache() { /* Reserved words. */ const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color"); List<String> keyword_list; gdscript->get_reserved_words(&keyword_list); for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { - keywords[E->get()] = keyword_color; + if (gdscript->is_control_flow_keyword(E->get())) { + keywords[E->get()] = control_flow_keyword_color; + } else { + keywords[E->get()] = keyword_color; + } } /* Comments */ @@ -541,19 +556,22 @@ void GDScriptSyntaxHighlighter::_update_cache() { } const String text_edit_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme"); - const bool default_theme = text_edit_color_theme == "Default"; + const bool godot_2_theme = text_edit_color_theme == "Godot 2"; - if (default_theme || EditorSettings::get_singleton()->is_dark_theme()) { + if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) { function_definition_color = Color(0.4, 0.9, 1.0); node_path_color = Color(0.39, 0.76, 0.35); + annotation_color = Color(1.0, 0.7, 0.45); } else { function_definition_color = Color(0.0, 0.65, 0.73); node_path_color = Color(0.32, 0.55, 0.29); + annotation_color = Color(0.8, 0.5, 0.25); } EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color); EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color); - if (text_edit_color_theme == "Adaptive" || default_theme) { + EDITOR_DEF("text_editor/highlighting/gdscript/annotation_color", annotation_color); + if (text_edit_color_theme == "Default" || godot_2_theme) { EditorSettings::get_singleton()->set_initial_value( "text_editor/highlighting/gdscript/function_definition_color", function_definition_color, @@ -562,10 +580,15 @@ void GDScriptSyntaxHighlighter::_update_cache() { "text_editor/highlighting/gdscript/node_path_color", node_path_color, true); + EditorSettings::get_singleton()->set_initial_value( + "text_editor/highlighting/gdscript/annotation_color", + annotation_color, + true); } function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color"); node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color"); + annotation_color = EDITOR_GET("text_editor/highlighting/gdscript/annotation_color"); type_color = EDITOR_GET("text_editor/highlighting/base_type_color"); } @@ -599,6 +622,6 @@ void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, cons Ref<EditorSyntaxHighlighter> GDScriptSyntaxHighlighter::_create() const { Ref<GDScriptSyntaxHighlighter> syntax_highlighter; - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); return syntax_highlighter; } diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 1b57cb1923..d07c182aa6 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -54,6 +54,7 @@ private: NONE, REGION, NODE_PATH, + ANNOTATION, SYMBOL, NUMBER, FUNCTION, @@ -72,6 +73,7 @@ private: Color number_color; Color member_color; Color node_path_color; + Color annotation_color; Color type_color; void add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false); diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index fcf438422a..caa80fc24c 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -34,7 +34,6 @@ #include "core/templates/set.h" #include "editor/editor_translation_parser.h" #include "modules/gdscript/gdscript_parser.h" -#include "modules/regex/regex.h" class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlugin { GDCLASS(GDScriptEditorTranslationParserPlugin, EditorTranslationParserPlugin); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index a129b73c1a..8b12b1eae4 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -36,8 +36,8 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "gdscript_analyzer.h" #include "gdscript_cache.h" @@ -45,6 +45,10 @@ #include "gdscript_parser.h" #include "gdscript_warning.h" +#ifdef TESTS_ENABLED +#include "tests/gdscript_test_runner.h" +#endif + /////////////////////////// GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) { @@ -68,19 +72,19 @@ void GDScriptNativeClass::_bind_methods() { } Variant GDScriptNativeClass::_new() { - Object *o = instance(); + Object *o = instantiate(); ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable."); - Reference *ref = Object::cast_to<Reference>(o); - if (ref) { - return REF(ref); + RefCounted *rc = Object::cast_to<RefCounted>(o); + if (rc) { + return REF(rc); } else { return o; } } -Object *GDScriptNativeClass::instance() { - return ClassDB::instance(name); +Object *GDScriptNativeClass::instantiate() { + return ClassDB::instantiate(name); } void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) { @@ -94,11 +98,11 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error); } -GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) { +GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) { /* STEP 1, CREATE */ GDScriptInstance *instance = memnew(GDScriptInstance); - instance->base_ref = p_isref; + instance->base_ref_counted = p_is_ref_counted; instance->members.resize(member_indices.size()); instance->script = Ref<GDScript>(this); instance->owner = p_owner; @@ -166,13 +170,13 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant()); if (_baseptr->native.ptr()) { - owner = _baseptr->native->instance(); + owner = _baseptr->native->instantiate(); } else { - owner = memnew(Reference); //by default, no base means use reference + owner = memnew(RefCounted); //by default, no base means use reference } ERR_FAIL_COND_V_MSG(!owner, Variant(), "Can't inherit from a virtual class."); - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -192,7 +196,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr } } -bool GDScript::can_instance() const { +bool GDScript::can_instantiate() const { #ifdef TOOLS_ENABLED return valid && (tool || ScriptServer::is_scripting_enabled()); #else @@ -276,7 +280,7 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl } msort.sort(); - msort.invert(); + msort.reverse(); for (int i = 0; i < msort.size(); i++) { props.push_front(sptr->member_info[msort[i].name]); } @@ -342,21 +346,21 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { if (top->native.is_valid()) { if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) { if (EngineDebugger::is_active()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); + GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } - ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + "."); + ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type '" + p_this->get_class() + "'" + "."); } } Callable::CallError unchecked_error; - return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error); + return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error); } PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) { #ifdef TOOLS_ENABLED PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); placeholders.insert(si); - _update_exports(); + _update_exports(nullptr, false, si); return si; #else return nullptr; @@ -477,7 +481,7 @@ void GDScript::_update_doc() { methods[i].return_val.class_name = _get_gdscript_reference_class_name(Object::cast_to<GDScript>(return_type.script_type)); } - // Change class name if argumetn is script reference. + // Change class name if argument is script reference. for (int j = 0; j < fn->get_argument_count(); j++) { GDScriptDataType arg_type = fn->get_argument_type(j); if (arg_type.kind == GDScriptDataType::GDSCRIPT) { @@ -580,7 +584,7 @@ void GDScript::_update_doc() { } #endif -bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) { +bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderScriptInstance *p_instance_to_update) { #ifdef TOOLS_ENABLED static Vector<GDScript *> base_caches; @@ -717,15 +721,19 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) { } } - if (placeholders.size()) { //hm :( + if ((changed || p_instance_to_update) && placeholders.size()) { //hm :( // update placeholders if any Map<StringName, Variant> values; List<PropertyInfo> propnames; _update_exports_values(values, propnames); - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); + if (changed) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->update(propnames, values); + } + } else { + p_instance_to_update->update(propnames, values); } } @@ -893,68 +901,10 @@ void GDScript::get_members(Set<StringName> *p_members) { } } -Vector<ScriptNetData> GDScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> GDScript::get_rpc_methods() const { return rpc_functions; } -uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < rpc_functions.size(); i++) { - if (rpc_functions[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - if (p_rpc_method_id >= rpc_functions.size()) { - return StringName(); - } - return rpc_functions[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - if (p_rpc_method_id >= rpc_functions.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return rpc_functions[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode GDScript::get_rpc_mode(const StringName &p_method) const { - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> GDScript::get_rset_properties() const { - return rpc_variables; -} - -uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const { - for (int i = 0; i < rpc_variables.size(); i++) { - if (rpc_variables[i].name == p_variable) { - return i; - } - } - return UINT16_MAX; -} - -StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const { - if (p_rset_member_id >= rpc_variables.size()) { - return StringName(); - } - return rpc_variables[p_rset_member_id].name; -} - -MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - if (p_rset_member_id >= rpc_variables.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return rpc_variables[p_rset_member_id].mode; -} - -MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const { - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *top = this; while (top) { @@ -1041,10 +991,10 @@ Error GDScript::load_source_code(const String &p_path) { ERR_FAIL_COND_V(err, err); } - int len = f->get_len(); + uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); - int r = f->get_buffer(w, len); + uint64_t r = f->get_buffer(w, len); f->close(); memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); @@ -1206,10 +1156,8 @@ void GDScript::_save_orphaned_subclasses() { void GDScript::_init_rpc_methods_properties() { // Copy the base rpc methods so we don't mask their IDs. rpc_functions.clear(); - rpc_variables.clear(); if (base.is_valid()) { rpc_functions = base->rpc_functions; - rpc_variables = base->rpc_variables; } GDScript *cscript = this; @@ -1218,25 +1166,17 @@ void GDScript::_init_rpc_methods_properties() { // RPC Methods for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = E->key(); - nd.mode = E->get()->get_rpc_mode(); + nd.rpc_mode = E->get()->get_rpc_mode(); + // TODO + nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + nd.channel = 0; if (-1 == rpc_functions.find(nd)) { rpc_functions.push_back(nd); } } } - // RSet - for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) { - if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E->key(); - nd.mode = E->get().rpc_mode; - if (-1 == rpc_variables.find(nd)) { - rpc_variables.push_back(nd); - } - } - } if (cscript != this) { sub_E = sub_E->next(); @@ -1250,8 +1190,7 @@ void GDScript::_init_rpc_methods_properties() { } // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<SortNetData>(); - rpc_variables.sort_custom<SortNetData>(); + rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); } GDScript::~GDScript() { @@ -1310,21 +1249,29 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { return true; //function exists, call was successful } } else { - if (!member->data_type.is_type(p_value)) { - // Try conversion - Callable::CallError ce; - const Variant *value = &p_value; - Variant converted; - Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce); - if (ce.error == Callable::CallError::CALL_OK) { - members.write[member->index] = converted; - return true; - } else { - return false; + if (member->data_type.has_type) { + if (member->data_type.builtin_type == Variant::ARRAY && member->data_type.has_container_element_type()) { + // Typed array. + if (p_value.get_type() == Variant::ARRAY) { + return VariantInternal::get_array(&members.write[member->index])->typed_assign(p_value); + } else { + return false; + } + } else if (!member->data_type.is_type(p_value)) { + // Try conversion + Callable::CallError ce; + const Variant *value = &p_value; + Variant converted; + Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce); + if (ce.error == Callable::CallError::CALL_OK) { + members.write[member->index] = converted; + return true; + } else { + return false; + } } - } else { - members.write[member->index] = p_value; } + members.write[member->index] = p_value; } return true; } @@ -1494,7 +1441,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const } msort.sort(); - msort.invert(); + msort.reverse(); for (int i = 0; i < msort.size(); i++) { props.push_front(sptr->member_info[msort[i].name]); } @@ -1599,46 +1546,10 @@ ScriptLanguage *GDScriptInstance::get_language() { return GDScriptLanguage::get_singleton(); } -Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> GDScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t GDScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName GDScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { - return script->get_rpc_method(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - return script->get_rpc_mode_by_id(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> GDScriptInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t GDScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName GDScriptInstance::get_rset_property(const uint16_t p_rset_member_id) const { - return script->get_rset_property(p_rset_member_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - return script->get_rset_mode_by_id(p_rset_member_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - void GDScriptInstance::reload_members() { #ifdef DEBUG_ENABLED @@ -1669,7 +1580,7 @@ void GDScriptInstance::reload_members() { GDScriptInstance::GDScriptInstance() { owner = nullptr; - base_ref = false; + base_ref_counted = false; } GDScriptInstance::~GDScriptInstance() { @@ -1758,6 +1669,10 @@ void GDScriptLanguage::init() { for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { _add_global(E->get().name, E->get().ptr); } + +#ifdef TESTS_ENABLED + GDScriptTests::GDScriptTestRunner::handle_cmdline(); +#endif } String GDScriptLanguage::get_type() const { @@ -2119,6 +2034,19 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { } } +bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const { + return p_keyword == "break" || + p_keyword == "continue" || + p_keyword == "elif" || + p_keyword == "else" || + p_keyword == "if" || + p_keyword == "for" || + p_keyword == "match" || + p_keyword == "pass" || + p_keyword == "return" || + p_keyword == "while"; +} + bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { return p_type == "GDScript"; } @@ -2140,7 +2068,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b if (err == OK) { const GDScriptParser::ClassNode *c = parser.get_tree(); if (r_icon_path) { - if (c->icon_path.is_empty() || c->icon_path.is_abs_path()) { + if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) { *r_icon_path = c->icon_path; } else if (c->icon_path.is_rel_path()) { *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path(); @@ -2208,7 +2136,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b break; } } else { - *r_base_type = "Reference"; + *r_base_type = "RefCounted"; subclass = nullptr; } } @@ -2293,7 +2221,7 @@ GDScriptLanguage::~GDScriptLanguage() { script->unreference(); } - singleton = NULL; + singleton = nullptr; } void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) { @@ -2328,7 +2256,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori if (script.is_null()) { // Don't fail loading because of parsing error. - script.instance(); + script.instantiate(); } if (r_error) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 12c909fd4f..078b7a2fd0 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -39,8 +39,8 @@ #include "core/object/script_language.h" #include "gdscript_function.h" -class GDScriptNativeClass : public Reference { - GDCLASS(GDScriptNativeClass, Reference); +class GDScriptNativeClass : public RefCounted { + GDCLASS(GDScriptNativeClass, RefCounted); StringName name; @@ -51,7 +51,7 @@ protected: public: _FORCE_INLINE_ const StringName &get_name() const { return name; } Variant _new(); - Object *instance(); + Object *instantiate(); GDScriptNativeClass(const StringName &p_name); }; @@ -80,14 +80,13 @@ class GDScript : public Script { GDScript *_base = nullptr; //fast pointer access GDScript *_owner = nullptr; //for subclasses - Set<StringName> members; //members are just indices to the instanced script. + Set<StringName> members; //members are just indices to the instantiated script. Map<StringName, Variant> constants; Map<StringName, GDScriptFunction *> member_functions; - Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script. + Map<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. Map<StringName, Ref<GDScript>> subclasses; Map<StringName, Vector<StringName>> _signals; - Vector<ScriptNetData> rpc_functions; - Vector<ScriptNetData> rpc_variables; + Vector<MultiplayerAPI::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED @@ -133,7 +132,7 @@ class GDScript : public Script { SelfList<GDScriptFunctionState>::List pending_func_states; void _super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error); - GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error); + GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error); void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path); @@ -149,7 +148,7 @@ class GDScript : public Script { #endif - bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false); + bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false, PlaceHolderScriptInstance *p_instance_to_update = nullptr); void _save_orphaned_subclasses(); void _init_rpc_methods_properties(); @@ -158,7 +157,7 @@ class GDScript : public Script { void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const; void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const; - // This method will map the class name from "Reference" to "MyClass.InnerClass". + // This method will map the class name from "RefCounted" to "MyClass.InnerClass". static String _get_gdscript_reference_class_name(const GDScript *p_gdscript); protected: @@ -197,7 +196,7 @@ public: StringName debug_get_member_by_index(int p_idx) const; Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; @@ -247,17 +246,7 @@ public: virtual void get_constants(Map<StringName, Variant> *p_constants) override; virtual void get_members(Set<StringName> *p_members) override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const override; - virtual StringName get_rset_property(const uint16_t p_variable_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED virtual bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; } @@ -270,6 +259,7 @@ public: class GDScriptInstance : public ScriptInstance { friend class GDScript; friend class GDScriptFunction; + friend class GDScriptLambdaCallable; friend class GDScriptCompiler; friend struct GDScriptUtilityFunctionsDefinitions; @@ -280,7 +270,7 @@ class GDScriptInstance : public ScriptInstance { Map<StringName, int> member_indices_cache; //used only for hot script reloading #endif Vector<Variant> members; - bool base_ref; + bool base_ref_counted; SelfList<GDScriptFunctionState>::List pending_func_states; @@ -309,17 +299,7 @@ public: void reload_members(); - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(const uint16_t p_variable_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; GDScriptInstance(); ~GDScriptInstance(); @@ -460,13 +440,14 @@ public: /* EDITOR FUNCTIONS */ virtual void get_reserved_words(List<String> *p_words) const; + virtual bool is_control_flow_keyword(String p_keywords) const; virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a6138cc564..e7fb33a6a7 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -31,48 +31,14 @@ #include "gdscript_analyzer.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/class_db.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/templates/hash_map.h" #include "gdscript.h" #include "gdscript_utility_functions.h" -// TODO: Move this to a central location (maybe core?). -static HashMap<StringName, StringName> underscore_map; -static const char *underscore_classes[] = { - "ClassDB", - "Directory", - "Engine", - "File", - "Geometry", - "GodotSharp", - "JSON", - "Marshalls", - "Mutex", - "OS", - "ResourceLoader", - "ResourceSaver", - "Semaphore", - "Thread", - "VisualScriptEditor", - nullptr, -}; -static StringName get_real_class_name(const StringName &p_source) { - if (underscore_map.is_empty()) { - const char **class_name = underscore_classes; - while (*class_name != nullptr) { - underscore_map[*class_name] = String("_") + *class_name; - class_name++; - } - } - if (underscore_map.has(p_source)) { - return underscore_map[p_source]; - } - return p_source; -} - static MethodInfo info_from_utility_func(const StringName &p_function) { ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo()); @@ -106,10 +72,6 @@ static MethodInfo info_from_utility_func(const StringName &p_function) { return info; } -void GDScriptAnalyzer::cleanup() { - underscore_map.clear(); -} - static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) { GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -150,7 +112,7 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native type.is_meta_type = true; List<StringName> enum_values; - StringName real_native_name = get_real_class_name(p_native_class); + StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class); ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values); for (const List<StringName>::Element *E = enum_values.front(); E != nullptr; E = E->next()) { @@ -201,7 +163,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, if (!p_class->extends_used) { result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; result.kind = GDScriptParser::DataType::NATIVE; - result.native_type = "Reference"; + result.native_type = "RefCounted"; } else { result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -267,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class); return err; } - } else if (class_exists(name) && ClassDB::can_instance(get_real_class_name(name))) { + } else if (class_exists(name) && ClassDB::can_instantiate(GDScriptParser::get_real_class_name(name))) { base.kind = GDScriptParser::DataType::NATIVE; base.native_type = name; } else { @@ -413,6 +375,14 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } result.kind = GDScriptParser::DataType::BUILTIN; result.builtin_type = GDScriptParser::get_builtin_type(first); + + if (result.builtin_type == Variant::ARRAY) { + GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type); + + if (container_type.kind != GDScriptParser::DataType::VARIANT) { + result.set_container_element_type(container_type); + } + } } else if (class_exists(first)) { // Native engine classes. result.kind = GDScriptParser::DataType::NATIVE; @@ -436,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type return GDScriptParser::DataType(); } result = ref->get_parser()->head->get_datatype(); - } else if (ClassDB::has_enum(get_real_class_name(parser->current_class->base_type.native_type), first)) { + } else if (ClassDB::has_enum(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), first)) { // Native enum in current class. result = make_native_enum_type(parser->current_class->base_type.native_type, first); } else { @@ -499,7 +469,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } else if (result.kind == GDScriptParser::DataType::NATIVE) { // Only enums allowed for native. - if (ClassDB::has_enum(get_real_class_name(result.native_type), p_type->type_chain[1]->name)) { + if (ClassDB::has_enum(GDScriptParser::get_real_class_name(result.native_type), p_type->type_chain[1]->name)) { if (p_type->type_chain.size() > 2) { push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]); } else { @@ -513,6 +483,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } + if (result.builtin_type != Variant::ARRAY && p_type->container_type != nullptr) { + push_error("Only arrays can specify the collection element type.", p_type); + } + p_type->set_datatype(result); return result; } @@ -535,9 +509,23 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas datatype.kind = GDScriptParser::DataType::VARIANT; datatype.type_source = GDScriptParser::DataType::UNDETECTED; + GDScriptParser::DataType specified_type; + if (member.variable->datatype_specifier != nullptr) { + specified_type = resolve_datatype(member.variable->datatype_specifier); + specified_type.is_meta_type = false; + } + if (member.variable->initializer != nullptr) { member.variable->set_datatype(datatype); // Allow recursive usage. reduce_expression(member.variable->initializer); + if ((member.variable->infer_datatype || (member.variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && member.variable->initializer->type == GDScriptParser::Node::ARRAY) { + // Typed array. + GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.variable->initializer); + // Can only infer typed array if it has elements. + if ((member.variable->infer_datatype && array->elements.size() > 0) || member.variable->datatype_specifier != nullptr) { + update_array_literal_element_type(specified_type, array); + } + } datatype = member.variable->initializer->get_datatype(); if (datatype.type_source != GDScriptParser::DataType::UNDETECTED) { datatype.type_source = GDScriptParser::DataType::INFERRED; @@ -545,8 +533,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas } if (member.variable->datatype_specifier != nullptr) { - datatype = resolve_datatype(member.variable->datatype_specifier); - datatype.is_meta_type = false; + datatype = specified_type; if (member.variable->initializer != nullptr) { if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) { @@ -556,6 +543,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas } else { // TODO: Add warning. mark_node_unsafe(member.variable->initializer); + member.variable->use_conversion_assign = true; } } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { #ifdef DEBUG_ENABLED @@ -565,6 +553,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas if (member.variable->initializer->get_datatype().is_variant()) { // TODO: Warn unsafe assign. mark_node_unsafe(member.variable->initializer); + member.variable->use_conversion_assign = true; } } } else if (member.variable->infer_datatype) { @@ -582,37 +571,32 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas datatype.is_constant = false; member.variable->set_datatype(datatype); - if (!datatype.has_no_type()) { - // TODO: Move this out into a routine specific to validate annotations. - if (member.variable->export_info.hint == PROPERTY_HINT_TYPE_STRING) { - // @export annotation. - switch (datatype.kind) { - case GDScriptParser::DataType::BUILTIN: - member.variable->export_info.hint_string = Variant::get_type_name(datatype.builtin_type); - break; - case GDScriptParser::DataType::NATIVE: - if (ClassDB::is_parent_class(get_real_class_name(datatype.native_type), "Resource")) { - member.variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; - member.variable->export_info.hint_string = get_real_class_name(datatype.native_type); - } else { - push_error(R"(Export type can only be built-in or a resource.)", member.variable); - } - break; - default: - // TODO: Allow custom user resources. - push_error(R"(Export type can only be built-in or a resource.)", member.variable); - break; - } - } + + // Apply annotations. + for (List<GDScriptParser::AnnotationNode *>::Element *E = member.variable->annotations.front(); E; E = E->next()) { + E->get()->apply(parser, member.variable); } } break; case GDScriptParser::ClassNode::Member::CONSTANT: { reduce_expression(member.constant->initializer); + GDScriptParser::DataType specified_type; + + if (member.constant->datatype_specifier != nullptr) { + specified_type = resolve_datatype(member.constant->datatype_specifier); + specified_type.is_meta_type = false; + } + GDScriptParser::DataType datatype = member.constant->get_datatype(); if (member.constant->initializer) { if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) { - const_fold_array(static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer)); + GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer); + const_fold_array(array); + + // Can only infer typed array if it has elements. + if (array->elements.size() > 0 || (member.constant->datatype_specifier != nullptr && specified_type.has_container_element_type())) { + update_array_literal_element_type(specified_type, array); + } } else if (member.constant->initializer->type == GDScriptParser::Node::DICTIONARY) { const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer)); } @@ -622,8 +606,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas } if (member.constant->datatype_specifier != nullptr) { - datatype = resolve_datatype(member.constant->datatype_specifier); - datatype.is_meta_type = false; + datatype = specified_type; if (!is_type_compatible(datatype, member.constant->initializer->get_datatype(), true)) { push_error(vformat(R"(Value of type "%s" cannot be initialized to constant of type "%s".)", member.constant->initializer->get_datatype().to_string(), datatype.to_string()), member.constant->initializer); @@ -637,6 +620,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas datatype.is_constant = true; member.constant->set_datatype(datatype); + + // Apply annotations. + for (List<GDScriptParser::AnnotationNode *>::Element *E = member.constant->annotations.front(); E; E = E->next()) { + E->get()->apply(parser, member.constant); + } } break; case GDScriptParser::ClassNode::Member::SIGNAL: { for (int j = 0; j < member.signal->parameters.size(); j++) { @@ -651,6 +639,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas signal_type.builtin_type = Variant::SIGNAL; member.signal->set_datatype(signal_type); + + // Apply annotations. + for (List<GDScriptParser::AnnotationNode *>::Element *E = member.signal->annotations.front(); E; E = E->next()) { + E->get()->apply(parser, member.signal); + } } break; case GDScriptParser::ClassNode::Member::ENUM: { GDScriptParser::DataType enum_type; @@ -693,6 +686,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas current_enum = nullptr; member.m_enum->set_datatype(enum_type); + + // Apply annotations. + for (List<GDScriptParser::AnnotationNode *>::Element *E = member.m_enum->annotations.front(); E; E = E->next()) { + E->get()->apply(parser, member.m_enum); + } } break; case GDScriptParser::ClassNode::Member::FUNCTION: resolve_function_signature(member.function); @@ -761,6 +759,11 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { } resolve_function_body(member.function); + + // Apply annotations. + for (List<GDScriptParser::AnnotationNode *>::Element *E = member.function->annotations.front(); E; E = E->next()) { + E->get()->apply(parser, member.function); + } } parser->current_class = previous_class; @@ -855,6 +858,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) { case GDScriptParser::Node::DICTIONARY: case GDScriptParser::Node::GET_NODE: case GDScriptParser::Node::IDENTIFIER: + case GDScriptParser::Node::LAMBDA: case GDScriptParser::Node::LITERAL: case GDScriptParser::Node::PRELOAD: case GDScriptParser::Node::SELF: @@ -1092,8 +1096,23 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable GDScriptParser::DataType type; type.kind = GDScriptParser::DataType::VARIANT; // By default. + GDScriptParser::DataType specified_type; + if (p_variable->datatype_specifier != nullptr) { + specified_type = resolve_datatype(p_variable->datatype_specifier); + specified_type.is_meta_type = false; + } + if (p_variable->initializer != nullptr) { reduce_expression(p_variable->initializer); + if ((p_variable->infer_datatype || (p_variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && p_variable->initializer->type == GDScriptParser::Node::ARRAY) { + // Typed array. + GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_variable->initializer); + // Can only infer typed array if it has elements. + if ((p_variable->infer_datatype && array->elements.size() > 0) || p_variable->datatype_specifier != nullptr) { + update_array_literal_element_type(specified_type, array); + } + } + type = p_variable->initializer->get_datatype(); if (p_variable->infer_datatype) { @@ -1117,7 +1136,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable } if (p_variable->datatype_specifier != nullptr) { - type = resolve_datatype(p_variable->datatype_specifier); + type = specified_type; type.is_meta_type = false; if (p_variable->initializer != nullptr) { @@ -1128,6 +1147,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable } else { // TODO: Add warning. mark_node_unsafe(p_variable->initializer); + p_variable->use_conversion_assign = true; } #ifdef DEBUG_ENABLED } else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { @@ -1137,6 +1157,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable if (p_variable->initializer->get_datatype().is_variant()) { // TODO: Warn unsafe assign. mark_node_unsafe(p_variable->initializer); + p_variable->use_conversion_assign = true; } } } else if (p_variable->infer_datatype) { @@ -1362,6 +1383,12 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { 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)); + } + } result = p_return->return_value->get_datatype(); } else { // Return type is null by default. @@ -1436,6 +1463,9 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre case GDScriptParser::Node::IDENTIFIER: reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_expression)); break; + case GDScriptParser::Node::LAMBDA: + reduce_lambda(static_cast<GDScriptParser::LambdaNode *>(p_expression)); + break; case GDScriptParser::Node::LITERAL: reduce_literal(static_cast<GDScriptParser::LiteralNode *>(p_expression)); break; @@ -1498,6 +1528,52 @@ void GDScriptAnalyzer::reduce_array(GDScriptParser::ArrayNode *p_array) { p_array->set_datatype(arr_type); } +// When an array literal is stored (or passed as function argument) to a typed context, we then assume the array is typed. +// This function determines which type is that (if any). +void GDScriptAnalyzer::update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal) { + GDScriptParser::DataType array_type = p_array_literal->get_datatype(); + if (p_array_literal->elements.size() == 0) { + // Empty array literal, just make the same type as the storage. + array_type.set_container_element_type(p_base_type.get_container_element_type()); + } else { + // Check if elements match. + bool all_same_type = true; + bool all_have_type = true; + + GDScriptParser::DataType element_type; + for (int i = 0; i < p_array_literal->elements.size(); i++) { + if (i == 0) { + element_type = p_array_literal->elements[0]->get_datatype(); + } else { + GDScriptParser::DataType this_element_type = p_array_literal->elements[i]->get_datatype(); + if (this_element_type.has_no_type()) { + all_same_type = false; + all_have_type = false; + break; + } else if (element_type != this_element_type) { + if (!is_type_compatible(element_type, this_element_type, false)) { + if (is_type_compatible(this_element_type, element_type, false)) { + // This element is a super-type to the previous type, so we use the super-type. + element_type = this_element_type; + } else { + // It's incompatible. + all_same_type = false; + break; + } + } + } + } + } + if (all_same_type) { + 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); + } + } + // Update the type on the value itself. + p_array_literal->set_datatype(array_type); +} + void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assignment) { reduce_expression(p_assignment->assignee); reduce_expression(p_assignment->assigned_value); @@ -1506,40 +1582,54 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig return; } - if (p_assignment->assignee->get_datatype().is_constant) { + GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype(); + + // Check if assigned value is an array literal, so we can make it a typed array too if appropriate. + if (assignee_type.has_container_element_type() && p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY) { + update_array_literal_element_type(assignee_type, static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value)); + } + + GDScriptParser::DataType assigned_value_type = p_assignment->assigned_value->get_datatype(); + + if (assignee_type.is_constant) { push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) { + if (!assignee_type.is_variant() && !assigned_value_type.is_variant()) { bool compatible = true; - GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype(); + GDScriptParser::DataType op_type = assigned_value_type; if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { - op_type = get_operation_type(p_assignment->variant_op, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible, p_assignment->assigned_value); + op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); } if (compatible) { - compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true); + compatible = is_type_compatible(assignee_type, op_type, true); if (!compatible) { - if (p_assignment->assignee->get_datatype().is_hard_type()) { + if (assignee_type.is_hard_type()) { // Try reverse test since it can be a masked subtype. - if (!is_type_compatible(op_type, p_assignment->assignee->get_datatype(), true)) { - push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + if (!is_type_compatible(op_type, assignee_type, true)) { + push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value); } else { // TODO: Add warning. mark_node_unsafe(p_assignment); + p_assignment->use_conversion_assign = true; } } else { // TODO: Warning in this case. mark_node_unsafe(p_assignment); + p_assignment->use_conversion_assign = true; } } } else { - push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment); + push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", assignee_type.to_string(), assigned_value_type.to_string()), p_assignment); } } - if (p_assignment->assignee->get_datatype().has_no_type() || p_assignment->assigned_value->get_datatype().is_variant()) { + if (assignee_type.has_no_type() || assigned_value_type.is_variant()) { mark_node_unsafe(p_assignment); + if (assignee_type.is_hard_type()) { + p_assignment->use_conversion_assign = true; + } } if (p_assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) { @@ -1558,7 +1648,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: { GDScriptParser::DataType id_type = identifier->variable_source->get_datatype(); if (!id_type.is_hard_type()) { - id_type = p_assignment->assigned_value->get_datatype(); + id_type = assigned_value_type; id_type.type_source = GDScriptParser::DataType::INFERRED; id_type.is_constant = false; identifier->variable_source->set_datatype(id_type); @@ -1567,7 +1657,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: { GDScriptParser::DataType id_type = identifier->bind_source->get_datatype(); if (!id_type.is_hard_type()) { - id_type = p_assignment->assigned_value->get_datatype(); + id_type = assigned_value_type; id_type.type_source = GDScriptParser::DataType::INFERRED; id_type.is_constant = false; identifier->variable_source->set_datatype(id_type); @@ -1579,12 +1669,10 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } } - GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype(); - GDScriptParser::DataType assigned_type = p_assignment->assigned_value->get_datatype(); #ifdef DEBUG_ENABLED - if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_type.kind == GDScriptParser::DataType::BUILTIN && assigned_type.builtin_type == Variant::NIL) { + if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name); - } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_type.builtin_type == Variant::FLOAT) { + } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION); } #endif @@ -1691,10 +1779,10 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o } else { if (p_binary_op->variant_op < Variant::OP_MAX) { bool valid = false; - result = get_operation_type(p_binary_op->variant_op, p_binary_op->left_operand->get_datatype(), right_type, valid, p_binary_op); + result = get_operation_type(p_binary_op->variant_op, left_type, right_type, valid, p_binary_op); if (!valid) { - push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", p_binary_op->left_operand->get_datatype().to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", left_type.to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); } } else { if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { @@ -1728,8 +1816,12 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_await) { 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++) { reduce_expression(p_call->arguments[i]); + if (p_call->arguments[i]->type == GDScriptParser::Node::ARRAY) { + arrays[i] = static_cast<GDScriptParser::ArrayNode *>(p_call->arguments[i]); + } all_is_constant = all_is_constant && p_call->arguments[i]->is_constant; } @@ -1976,12 +2068,20 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa if (p_call->is_super) { base_type = parser->current_class->base_type; + base_type.is_meta_type = false; is_self = true; } else if (callee_type == GDScriptParser::Node::IDENTIFIER) { base_type = parser->current_class->get_datatype(); + base_type.is_meta_type = false; is_self = true; } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) { GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(p_call->callee); + if (subscript->base == nullptr) { + // Invalid syntax, error already set on parser. + p_call->set_datatype(call_type); + mark_node_unsafe(p_call); + return; + } if (!subscript->is_attribute) { // Invalid call. Error already sent in parser. // TODO: Could check if Callable here. @@ -1989,9 +2089,23 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa mark_node_unsafe(p_call); return; } - reduce_expression(subscript->base); + if (subscript->attribute == nullptr) { + // Invalid call. Error already sent in parser. + p_call->set_datatype(call_type); + mark_node_unsafe(p_call); + return; + } - base_type = subscript->base->get_datatype(); + GDScriptParser::IdentifierNode *base_id = nullptr; + if (subscript->base->type == GDScriptParser::Node::IDENTIFIER) { + base_id = static_cast<GDScriptParser::IdentifierNode *>(subscript->base); + } + if (base_id && GDScriptParser::get_builtin_type(base_id->name) < Variant::VARIANT_MAX) { + base_type = make_builtin_meta_type(GDScriptParser::get_builtin_type(base_id->name)); + } else { + reduce_expression(subscript->base); + base_type = subscript->base->get_datatype(); + } } else { // Invalid call. Error already sent in parser. // TODO: Could check if Callable here too. @@ -2007,10 +2121,19 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa List<GDScriptParser::DataType> par_types; if (get_function_signature(p_call, base_type, p_call->function_name, return_type, par_types, default_arg_count, is_static, is_vararg)) { + // If the function require typed arrays we must make literals be typed. + for (Map<int, GDScriptParser::ArrayNode *>::Element *E = arrays.front(); E; E = E->next()) { + int index = E->key(); + if (index < par_types.size() && par_types[index].has_container_element_type()) { + update_array_literal_element_type(par_types[index], E->get()); + } + } validate_call_arg(par_types, default_arg_count, is_vararg, p_call); if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) { push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee); + } else if (is_self && !is_static && !lambda_stack.is_empty()) { + push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee); } call_type = return_type; @@ -2131,8 +2254,10 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node) result.native_type = "Node"; result.builtin_type = Variant::OBJECT; - if (!ClassDB::is_parent_class(get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) { + if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) { push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node); + } else if (!lambda_stack.is_empty()) { + push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node); } p_get_node->set_datatype(result); @@ -2224,6 +2349,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod GDScriptParser::DataType result; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; result.kind = GDScriptParser::DataType::ENUM_VALUE; + result.builtin_type = base.builtin_type; result.native_type = base.native_type; result.enum_type = name; p_identifier->set_datatype(result); @@ -2260,6 +2386,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod case GDScriptParser::ClassNode::Member::ENUM_VALUE: p_identifier->is_constant = true; p_identifier->reduced_value = member.enum_value.value; + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; break; case GDScriptParser::ClassNode::Member::VARIABLE: p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE; @@ -2297,7 +2424,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod } // Check native members. - const StringName &native = get_real_class_name(base.native_type); + const StringName &native = GDScriptParser::get_real_class_name(base.native_type); if (class_exists(native)) { PropertyInfo prop_info; @@ -2360,42 +2487,65 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident } } + bool found_source = false; // Check if identifier is local. // If that's the case, the declaration already was solved before. switch (p_identifier->source) { case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER: p_identifier->set_datatype(p_identifier->parameter_source->get_datatype()); - return; + found_source = true; + break; case GDScriptParser::IdentifierNode::LOCAL_CONSTANT: case GDScriptParser::IdentifierNode::MEMBER_CONSTANT: p_identifier->set_datatype(p_identifier->constant_source->get_datatype()); p_identifier->is_constant = true; // TODO: Constant should have a value on the node itself. p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value; - return; + found_source = true; + break; case GDScriptParser::IdentifierNode::MEMBER_VARIABLE: p_identifier->variable_source->usages++; [[fallthrough]]; case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: p_identifier->set_datatype(p_identifier->variable_source->get_datatype()); - return; + found_source = true; + break; case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: p_identifier->set_datatype(p_identifier->bind_source->get_datatype()); - return; + found_source = true; + break; case GDScriptParser::IdentifierNode::LOCAL_BIND: { GDScriptParser::DataType result = p_identifier->bind_source->get_datatype(); result.is_constant = true; p_identifier->set_datatype(result); - return; - } + found_source = true; + } break; case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: break; } // Not a local, so check members. - reduce_identifier_from_base(p_identifier); - if (p_identifier->get_datatype().is_set()) { - // Found. + if (!found_source) { + reduce_identifier_from_base(p_identifier); + if (p_identifier->source != GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->get_datatype().is_set()) { + // Found. + found_source = true; + } + } + + if (found_source) { + // If the identifier is local, check if it's any kind of capture by comparing their source function. + // Only capture locals and members and enum values. Constants are still accessible from the lambda using the script reference. + if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT || lambda_stack.is_empty()) { + return; + } + + GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function; + while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) { + function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size(); + function_test->source_lambda->captures.push_back(p_identifier); + function_test = function_test->source_lambda->parent_function; + } return; } @@ -2477,6 +2627,57 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident p_identifier->set_datatype(dummy); // Just so type is set to something. } +void GDScriptAnalyzer::reduce_lambda(GDScriptParser::LambdaNode *p_lambda) { + // Lambda is always a Callable. + GDScriptParser::DataType lambda_type; + lambda_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; + lambda_type.kind = GDScriptParser::DataType::BUILTIN; + lambda_type.builtin_type = Variant::CALLABLE; + p_lambda->set_datatype(lambda_type); + + if (p_lambda->function == nullptr) { + return; + } + + GDScriptParser::FunctionNode *previous_function = parser->current_function; + parser->current_function = p_lambda->function; + + lambda_stack.push_back(p_lambda); + + for (int i = 0; i < p_lambda->function->parameters.size(); i++) { + resolve_parameter(p_lambda->function->parameters[i]); + } + + resolve_suite(p_lambda->function->body); + + int captures_amount = p_lambda->captures.size(); + if (captures_amount > 0) { + // Create space for lambda parameters. + // At the beginning to not mess with optional parameters. + int param_count = p_lambda->function->parameters.size(); + p_lambda->function->parameters.resize(param_count + captures_amount); + for (int i = param_count - 1; i >= 0; i--) { + p_lambda->function->parameters.write[i + captures_amount] = p_lambda->function->parameters[i]; + p_lambda->function->parameters_indices[p_lambda->function->parameters[i]->identifier->name] = i + captures_amount; + } + + // Add captures as extra parameters at the beginning. + for (int i = 0; i < p_lambda->captures.size(); i++) { + GDScriptParser::IdentifierNode *capture = p_lambda->captures[i]; + GDScriptParser::ParameterNode *capture_param = parser->alloc_node<GDScriptParser::ParameterNode>(); + capture_param->identifier = capture; + capture_param->usages = capture->usages; + capture_param->set_datatype(capture->get_datatype()); + + p_lambda->function->parameters.write[i] = capture_param; + p_lambda->function->parameters_indices[capture->name] = i; + } + } + + lambda_stack.pop_back(); + parser->current_function = previous_function; +} + void GDScriptAnalyzer::reduce_literal(GDScriptParser::LiteralNode *p_literal) { p_literal->reduced_value = p_literal->value; p_literal->is_constant = true; @@ -2535,25 +2736,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri GDScriptParser::DataType result_type; - // Reduce index first. If it's a constant StringName, use attribute instead. - if (!p_subscript->is_attribute) { - if (p_subscript->index == nullptr) { - return; - } - reduce_expression(p_subscript->index); - - if (p_subscript->index->is_constant && p_subscript->index->reduced_value.get_type() == Variant::STRING_NAME) { - GDScriptParser::IdentifierNode *attribute = parser->alloc_node<GDScriptParser::IdentifierNode>(); - // Copy location for better error message. - attribute->start_line = p_subscript->index->start_line; - attribute->end_line = p_subscript->index->end_line; - attribute->leftmost_column = p_subscript->index->leftmost_column; - attribute->rightmost_column = p_subscript->index->rightmost_column; - p_subscript->is_attribute = true; - p_subscript->attribute = attribute; - } - } - if (p_subscript->is_attribute) { if (p_subscript->attribute == nullptr) { return; @@ -2596,7 +2778,10 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri } } } else { - // Index was already reduced before. + if (p_subscript->index == nullptr) { + return; + } + reduce_expression(p_subscript->index); if (p_subscript->base->is_constant && p_subscript->index->is_constant) { // Just try to get it. @@ -2641,7 +2826,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::RECT2: case Variant::RECT2I: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::OBJECT: error = index_type.builtin_type != Variant::STRING; @@ -2652,8 +2837,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::VECTOR2I: case Variant::VECTOR3: case Variant::VECTOR3I: - case Variant::TRANSFORM: case Variant::TRANSFORM2D: + case Variant::TRANSFORM3D: error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::FLOAT && index_type.builtin_type != Variant::STRING; break; @@ -2720,7 +2905,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::PACKED_FLOAT64_ARRAY: case Variant::VECTOR2: case Variant::VECTOR3: - case Variant::QUAT: + case Variant::QUATERNION: result_type.builtin_type = Variant::FLOAT; break; // Return Color. @@ -2749,14 +2934,23 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri result_type.builtin_type = Variant::VECTOR3; break; // Depends on the index. - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::PLANE: case Variant::COLOR: - case Variant::ARRAY: case Variant::DICTIONARY: result_type.kind = GDScriptParser::DataType::VARIANT; result_type.type_source = GDScriptParser::DataType::UNDETECTED; break; + // Can have an element type. + case Variant::ARRAY: + if (base_type.has_container_element_type()) { + result_type = base_type.get_container_element_type(); + result_type.type_source = base_type.type_source; + } else { + result_type.kind = GDScriptParser::DataType::VARIANT; + result_type.type_source = GDScriptParser::DataType::UNDETECTED; + } + break; // Here for completeness. case Variant::OBJECT: case Variant::VARIANT_MAX: @@ -2979,6 +3173,34 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo result.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name; } else { result.kind = GDScriptParser::DataType::BUILTIN; + result.builtin_type = p_property.type; + if (p_property.type == Variant::ARRAY && p_property.hint == PROPERTY_HINT_ARRAY_TYPE) { + // Check element type. + StringName elem_type_name = p_property.hint_string; + GDScriptParser::DataType elem_type; + elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + + Variant::Type elem_builtin_type = GDScriptParser::get_builtin_type(elem_type_name); + if (elem_builtin_type < Variant::VARIANT_MAX) { + // Builtin type. + elem_type.kind = GDScriptParser::DataType::BUILTIN; + elem_type.builtin_type = elem_builtin_type; + } else if (class_exists(elem_type_name)) { + elem_type.kind = GDScriptParser::DataType::NATIVE; + elem_type.builtin_type = Variant::OBJECT; + elem_type.native_type = p_property.hint_string; + } else if (ScriptServer::is_global_class(elem_type_name)) { + // Just load this as it shouldn't be a GDScript. + Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(elem_type_name)); + elem_type.kind = GDScriptParser::DataType::SCRIPT; + elem_type.builtin_type = Variant::OBJECT; + elem_type.native_type = script->get_instance_base_type(); + elem_type.script_type = script; + } else { + ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array."); + } + result.set_container_element_type(elem_type); + } } return result; } @@ -3084,7 +3306,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD return true; } - StringName real_native = get_real_class_name(base_native); + StringName real_native = GDScriptParser::get_real_class_name(base_native); MethodInfo info; if (ClassDB::get_method_info(real_native, function_name, &info)) { @@ -3179,7 +3401,7 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con StringName parent = base_native; while (parent != StringName()) { - StringName real_class_name = get_real_class_name(parent); + StringName real_class_name = GDScriptParser::get_real_class_name(parent); if (ClassDB::has_method(real_class_name, name, true)) { parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent); return true; @@ -3225,6 +3447,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator } r_valid = true; + result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; result.kind = GDScriptParser::DataType::BUILTIN; result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); @@ -3257,6 +3480,18 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ // Enum value is also integer. valid = true; } + if (valid && p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) { + // Check the element type. + if (p_target.has_container_element_type()) { + if (!p_source.has_container_element_type()) { + // TODO: Maybe this is valid but unsafe? + // Variant array can't be appended to typed array. + valid = false; + } else { + valid = is_type_compatible(p_target.get_container_element_type(), p_source.get_container_element_type(), false); + } + } + } return valid; } @@ -3329,14 +3564,14 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ } // Get underscore-prefixed version for some classes. - src_native = get_real_class_name(src_native); + src_native = GDScriptParser::get_real_class_name(src_native); switch (p_target.kind) { case GDScriptParser::DataType::NATIVE: { if (p_target.is_meta_type) { return ClassDB::is_parent_class(src_native, GDScriptNativeClass::get_class_static()); } - StringName tgt_native = get_real_class_name(p_target.native_type); + StringName tgt_native = GDScriptParser::get_real_class_name(p_target.native_type); return ClassDB::is_parent_class(src_native, tgt_native); } case GDScriptParser::DataType::SCRIPT: @@ -3385,8 +3620,8 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) { #endif } -bool GDScriptAnalyzer::class_exists(const StringName &p_class) { - StringName real_name = get_real_class_name(p_class); +bool GDScriptAnalyzer::class_exists(const StringName &p_class) const { + StringName real_name = GDScriptParser::get_real_class_name(p_class); return ClassDB::class_exists(real_name) && ClassDB::is_class_exposed(real_name); } diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index dab5b032a3..8cd3fcf837 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -32,7 +32,7 @@ #define GDSCRIPT_ANALYZER_H #include "core/object/object.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/set.h" #include "gdscript_cache.h" #include "gdscript_parser.h" @@ -42,6 +42,7 @@ class GDScriptAnalyzer { HashMap<String, Ref<GDScriptParserRef>> depended_parsers; const GDScriptParser::EnumNode *current_enum = nullptr; + List<const GDScriptParser::LambdaNode *> lambda_stack; Error resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive = true); GDScriptParser::DataType resolve_datatype(GDScriptParser::TypeNode *p_type); @@ -82,6 +83,7 @@ class GDScriptAnalyzer { void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node); void reduce_identifier(GDScriptParser::IdentifierNode *p_identifier, bool can_be_builtin = false); void reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base = nullptr); + void reduce_lambda(GDScriptParser::LambdaNode *p_lambda); void reduce_literal(GDScriptParser::LiteralNode *p_literal); void reduce_preload(GDScriptParser::PreloadNode *p_preload); void reduce_self(GDScriptParser::SelfNode *p_self); @@ -103,10 +105,11 @@ class GDScriptAnalyzer { bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call); GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source); GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source); + void update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal); bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false) const; void push_error(const String &p_message, const GDScriptParser::Node *p_origin); void mark_node_unsafe(const GDScriptParser::Node *p_node); - bool class_exists(const StringName &p_class); + bool class_exists(const StringName &p_class) const; Ref<GDScriptParserRef> get_parser_for(const String &p_path); #ifdef DEBUG_ENABLED bool is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context); @@ -119,8 +122,6 @@ public: Error analyze(); GDScriptAnalyzer(GDScriptParser *p_parser); - - static void cleanup(); }; #endif // GDSCRIPT_ANALYZER_H diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 58c6b31a77..5a297cc50a 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -47,7 +47,8 @@ uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool } uint32_t GDScriptByteCodeGenerator::add_local(const StringName &p_name, const GDScriptDataType &p_type) { - int stack_pos = increase_stack(); + int stack_pos = locals.size() + RESERVED_STACK; + locals.push_back(StackSlot(p_type.builtin_type)); add_stack_identifier(p_name, stack_pos); return stack_pos; } @@ -59,37 +60,88 @@ uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name, } uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) { - if (constant_map.has(p_constant)) { - return constant_map[p_constant]; - } - int index = constant_map.size(); - constant_map[p_constant] = index; - return index; + return get_constant_pos(p_constant); } uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) { return get_name_map_pos(p_name); } -uint32_t GDScriptByteCodeGenerator::add_temporary() { - current_temporaries++; - int idx = increase_stack(); -#ifdef DEBUG_ENABLED - temp_stack.push_back(idx); -#endif - return idx; +uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type) { + Variant::Type temp_type = Variant::NIL; + if (p_type.has_type) { + if (p_type.kind == GDScriptDataType::BUILTIN) { + switch (p_type.builtin_type) { + case Variant::NIL: + case Variant::BOOL: + case Variant::INT: + case Variant::FLOAT: + case Variant::STRING: + case Variant::VECTOR2: + case Variant::VECTOR2I: + case Variant::RECT2: + case Variant::RECT2I: + case Variant::VECTOR3: + case Variant::VECTOR3I: + case Variant::TRANSFORM2D: + case Variant::PLANE: + case Variant::QUATERNION: + case Variant::AABB: + case Variant::BASIS: + case Variant::TRANSFORM3D: + case Variant::COLOR: + case Variant::STRING_NAME: + case Variant::NODE_PATH: + case Variant::RID: + case Variant::OBJECT: + case Variant::CALLABLE: + case Variant::SIGNAL: + case Variant::DICTIONARY: + case Variant::ARRAY: + temp_type = p_type.builtin_type; + break; + case Variant::PACKED_BYTE_ARRAY: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_STRING_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + case Variant::VARIANT_MAX: + // Packed arrays are reference counted, so we don't use the pool for them. + temp_type = Variant::NIL; + break; + } + } else { + temp_type = Variant::OBJECT; + } + } + + if (!temporaries_pool.has(temp_type)) { + temporaries_pool[temp_type] = List<int>(); + } + + List<int> &pool = temporaries_pool[temp_type]; + if (pool.is_empty()) { + StackSlot new_temp(temp_type); + int idx = temporaries.size(); + pool.push_back(idx); + temporaries.push_back(new_temp); + } + int slot = pool.front()->get(); + pool.pop_front(); + used_temporaries.push_back(slot); + return slot; } void GDScriptByteCodeGenerator::pop_temporary() { - ERR_FAIL_COND(current_temporaries == 0); - current_stack_size--; -#ifdef DEBUG_ENABLED - if (temp_stack.back()->get() != current_stack_size) { - ERR_PRINT("Mismatched popping of temporary value"); - } - temp_stack.pop_back(); -#endif - current_temporaries--; + ERR_FAIL_COND(used_temporaries.is_empty()); + int slot_idx = used_temporaries.back()->get(); + const StackSlot &slot = temporaries[slot_idx]; + temporaries_pool[slot.type].push_back(slot_idx); + used_temporaries.pop_back(); } void GDScriptByteCodeGenerator::start_parameters() { @@ -100,7 +152,7 @@ void GDScriptByteCodeGenerator::start_parameters() { } void GDScriptByteCodeGenerator::end_parameters() { - function->default_arguments.invert(); + function->default_arguments.reverse(); } void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) { @@ -124,12 +176,22 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName GDScriptFunction *GDScriptByteCodeGenerator::write_end() { #ifdef DEBUG_ENABLED - if (current_temporaries != 0) { - ERR_PRINT("Non-zero temporary variables at end of function: " + itos(current_temporaries)); + if (!used_temporaries.is_empty()) { + ERR_PRINT("Non-zero temporary variables at end of function: " + itos(used_temporaries.size())); } #endif append(GDScriptFunction::OPCODE_END, 0); + for (int i = 0; i < temporaries.size(); i++) { + int stack_index = i + max_locals + RESERVED_STACK; + for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) { + opcodes.write[temporaries[i].bytecode_indices[j]] = stack_index | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + } + if (temporaries[i].type != Variant::NIL) { + function->temporary_slots[stack_index] = temporaries[i].type; + } + } + if (constant_map.size()) { function->_constant_count = constant_map.size(); function->constants.resize(constant_map.size()); @@ -319,10 +381,22 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { function->_methods_count = 0; } + if (lambdas_map.size()) { + function->lambdas.resize(lambdas_map.size()); + function->_lambdas_ptr = function->lambdas.ptrw(); + function->_lambdas_count = lambdas_map.size(); + for (const Map<GDScriptFunction *, int>::Element *E = lambdas_map.front(); E; E = E->next()) { + function->lambdas.write[E->get()] = E->key(); + } + } else { + function->_lambdas_ptr = nullptr; + function->_lambdas_count = 0; + } + if (debug_stack) { function->stack_debug = stack_debug; } - function->_stack_size = stack_max; + function->_stack_size = RESERVED_STACK + max_locals + temporaries.size(); function->_instruction_args_size = instr_args_max; function->_ptrcall_args_size = ptrcall_max; @@ -346,6 +420,117 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) { #define IS_BUILTIN_TYPE(m_var, m_type) \ (m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type) +void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Variant::Type p_new_type) { + switch (p_new_type) { + case Variant::BOOL: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_BOOL, 1); + break; + case Variant::INT: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_INT, 1); + break; + case Variant::FLOAT: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_FLOAT, 1); + break; + case Variant::STRING: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING, 1); + break; + case Variant::VECTOR2: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2, 1); + break; + case Variant::VECTOR2I: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2I, 1); + break; + case Variant::RECT2: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2, 1); + break; + case Variant::RECT2I: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2I, 1); + break; + case Variant::VECTOR3: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3, 1); + break; + case Variant::VECTOR3I: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I, 1); + break; + case Variant::TRANSFORM2D: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM2D, 1); + break; + case Variant::PLANE: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE, 1); + break; + case Variant::QUATERNION: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUATERNION, 1); + break; + case Variant::AABB: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB, 1); + break; + case Variant::BASIS: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1); + break; + case Variant::TRANSFORM3D: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1); + break; + case Variant::COLOR: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR, 1); + break; + case Variant::STRING_NAME: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING_NAME, 1); + break; + case Variant::NODE_PATH: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_NODE_PATH, 1); + break; + case Variant::RID: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_RID, 1); + break; + case Variant::OBJECT: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_OBJECT, 1); + break; + case Variant::CALLABLE: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_CALLABLE, 1); + break; + case Variant::SIGNAL: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_SIGNAL, 1); + break; + case Variant::DICTIONARY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_DICTIONARY, 1); + break; + case Variant::ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_ARRAY, 1); + break; + case Variant::PACKED_BYTE_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, 1); + break; + case Variant::PACKED_INT32_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, 1); + break; + case Variant::PACKED_INT64_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, 1); + break; + case Variant::PACKED_FLOAT32_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, 1); + break; + case Variant::PACKED_FLOAT64_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, 1); + break; + case Variant::PACKED_STRING_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, 1); + break; + case Variant::PACKED_VECTOR2_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, 1); + break; + case Variant::PACKED_VECTOR3_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, 1); + break; + case Variant::PACKED_COLOR_ARRAY: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, 1); + break; + case Variant::NIL: + case Variant::VARIANT_MAX: + return; + } + append(p_target); +} + void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) { if (HAS_BUILTIN_TYPE(p_left_operand)) { // Gather specific operator. @@ -369,6 +554,14 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) { + if (p_target.mode == Address::TEMPORARY) { + Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); + Variant::Type temp_type = temporaries[p_target.address].type; + if (result_type != temp_type) { + write_type_adjust(p_target, result_type); + } + } + // Gather specific operator. Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); @@ -396,7 +589,7 @@ void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const A } void GDScriptByteCodeGenerator::write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) { - append(GDScriptFunction::OPCODE_IS_BUILTIN, 3); + append(GDScriptFunction::OPCODE_IS_BUILTIN, 2); append(p_source); append(p_target); append(p_type); @@ -594,53 +787,43 @@ void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const append(p_name); } -void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) { - if (p_target.type.has_type && !p_source.type.has_type) { - // Typed assignment. - switch (p_target.type.kind) { - case GDScriptDataType::BUILTIN: { - append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2); - append(p_target); - append(p_source); - append(p_target.type.builtin_type); - } break; - case GDScriptDataType::NATIVE: { - int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type]; - class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); - append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3); - append(p_target); - append(p_source); - append(class_idx); - } break; - case GDScriptDataType::SCRIPT: - case GDScriptDataType::GDSCRIPT: { - Variant script = p_target.type.script_type; - int idx = get_constant_pos(script); - idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); - - append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3); +void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) { + switch (p_target.type.kind) { + case GDScriptDataType::BUILTIN: { + if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { + append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2); append(p_target); append(p_source); - append(idx); - } break; - default: { - ERR_PRINT("Compiler bug: unresolved assign."); - - // Shouldn't get here, but fail-safe to a regular assignment - append(GDScriptFunction::OPCODE_ASSIGN, 2); + } else { + append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2); append(p_target); append(p_source); + append(p_target.type.builtin_type); } - } - } else { - if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) { - // Need conversion.. - append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2); + } break; + case GDScriptDataType::NATIVE: { + int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type]; + Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx]; + class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); + append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3); append(p_target); append(p_source); - append(p_target.type.builtin_type); - } else { - // Either untyped assignment or already type-checked by the parser + append(class_idx); + } break; + case GDScriptDataType::SCRIPT: + case GDScriptDataType::GDSCRIPT: { + Variant script = p_target.type.script_type; + int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); + + append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3); + append(p_target); + append(p_source); + append(idx); + } break; + default: { + ERR_PRINT("Compiler bug: unresolved assign."); + + // Shouldn't get here, but fail-safe to a regular assignment append(GDScriptFunction::OPCODE_ASSIGN, 2); append(p_target); append(p_source); @@ -648,6 +831,24 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr } } +void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) { + if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { + append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2); + append(p_target); + append(p_source); + } else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) { + // Need conversion. + append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2); + append(p_target); + append(p_source); + append(p_target.type.builtin_type); + } else { + append(GDScriptFunction::OPCODE_ASSIGN, 2); + append(p_target); + append(p_source); + } +} + void GDScriptByteCodeGenerator::write_assign_true(const Address &p_target) { append(GDScriptFunction::OPCODE_ASSIGN_TRUE, 1); append(p_target); @@ -663,6 +864,12 @@ void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_ function->default_arguments.push_back(opcodes.size()); } +void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) { + append(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL, 1); + append(p_dst); + append(p_global); +} + void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) { int index = 0; @@ -673,16 +880,14 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres } break; case GDScriptDataType::NATIVE: { int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type]; - class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); + Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx]; append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3); - index = class_idx; + index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); } break; case GDScriptDataType::SCRIPT: case GDScriptDataType::GDSCRIPT: { Variant script = p_type.script_type; - int idx = get_constant_pos(script); - idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); - + int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3); index = idx; } break; @@ -797,6 +1002,14 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, return; } + if (p_target.mode == Address::TEMPORARY) { + Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method); + Variant::Type temp_type = temporaries[p_target.address].type; + if (result_type != temp_type) { + write_type_adjust(p_target, result_type); + } + } + append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { @@ -808,6 +1021,56 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, append(Variant::get_validated_builtin_method(p_type, p_method)); } +void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) { + bool is_validated = false; + + // Check if all types are correct. + if (Variant::is_builtin_method_vararg(p_type, p_method)) { + is_validated = true; // Vararg works fine with any argument, since they can be any type. + } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) { + bool all_types_exact = true; + for (int i = 0; i < p_arguments.size(); i++) { + if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) { + all_types_exact = false; + break; + } + } + + is_validated = all_types_exact; + } + + if (!is_validated) { + // Perform regular call. + append(GDScriptFunction::OPCODE_CALL_BUILTIN_STATIC, p_arguments.size() + 1); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_target); + append(p_type); + append(p_method); + append(p_arguments.size()); + return; + } + + if (p_target.mode == Address::TEMPORARY) { + Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method); + Variant::Type temp_type = temporaries[p_target.address].type; + if (result_type != temp_type) { + write_type_adjust(p_target, result_type); + } + } + + append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size()); + + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(Address()); // No base since it's static. + append(p_target); + append(p_arguments.size()); + append(Variant::get_validated_builtin_method(p_type, p_method)); +} + void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) { append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { @@ -845,12 +1108,12 @@ void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, cons CASE_TYPE(PLANE); CASE_TYPE(AABB); CASE_TYPE(BASIS); - CASE_TYPE(TRANSFORM); + CASE_TYPE(TRANSFORM3D); CASE_TYPE(COLOR); CASE_TYPE(STRING_NAME); CASE_TYPE(NODE_PATH); CASE_TYPE(RID); - CASE_TYPE(QUAT); + CASE_TYPE(QUATERNION); CASE_TYPE(OBJECT); CASE_TYPE(CALLABLE); CASE_TYPE(SIGNAL); @@ -893,7 +1156,7 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); + append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); append(p_target); append(p_arguments.size()); append(p_function_name); @@ -904,7 +1167,7 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); + append(GDScriptFunction::ADDR_SELF); append(p_target); append(p_arguments.size()); append(p_function_name); @@ -921,6 +1184,17 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ append(p_function_name); } +void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) { + append(GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size()); + for (int i = 0; i < p_captures.size(); i++) { + append(p_captures[i]); + } + + append(p_target); + append(p_captures.size()); + append(p_function); +} + void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) { // Try to find an appropriate constructor. bool all_have_type = true; @@ -980,6 +1254,25 @@ void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, c append(p_arguments.size()); } +void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) { + append(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_ARRAY, 2 + p_arguments.size()); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_target); + if (p_element_type.script_type) { + Variant script_type = Ref<Script>(p_element_type.script_type); + int addr = get_constant_pos(script_type); + addr |= GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS; + append(addr); + } else { + append(Address()); // null. + } + append(p_arguments.size()); + append(p_element_type.builtin_type); + append(p_element_type.native_type); +} + void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) { append(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { @@ -1257,8 +1550,84 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) { } void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { - append(GDScriptFunction::OPCODE_RETURN, 1); - append(p_return_value); + if (!function->return_type.has_type || p_return_value.type.has_type) { + // Either the function is untyped or the return value is also typed. + + // If this is a typed function, then we need to check for potential conversions. + if (function->return_type.has_type) { + if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { + // Typed array. + const GDScriptDataType &element_type = function->return_type.get_container_element_type(); + + Variant script = function->return_type.script_type; + int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); + + append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2); + append(p_return_value); + append(script_idx); + append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT); + append(element_type.native_type); + } else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) { + // Add conversion. + append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1); + append(p_return_value); + append(function->return_type.builtin_type); + } else { + // Just assign. + append(GDScriptFunction::OPCODE_RETURN, 1); + append(p_return_value); + } + } else { + append(GDScriptFunction::OPCODE_RETURN, 1); + append(p_return_value); + } + } else { + switch (function->return_type.kind) { + case GDScriptDataType::BUILTIN: { + if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { + const GDScriptDataType &element_type = function->return_type.get_container_element_type(); + + Variant script = function->return_type.script_type; + int script_idx = get_constant_pos(script); + script_idx |= (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); + + append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2); + append(p_return_value); + append(script_idx); + append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT); + append(element_type.native_type); + } else { + append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1); + append(p_return_value); + append(function->return_type.builtin_type); + } + } break; + case GDScriptDataType::NATIVE: { + append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2); + append(p_return_value); + int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type]; + Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx]; + class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); + append(class_idx); + } break; + case GDScriptDataType::GDSCRIPT: + case GDScriptDataType::SCRIPT: { + Variant script = function->return_type.script_type; + int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); + + append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2); + append(p_return_value); + append(script_idx); + } break; + default: { + ERR_PRINT("Compiler bug: unresolved return."); + + // Shouldn't get here, but fail-safe to a regular return; + append(GDScriptFunction::OPCODE_RETURN, 1); + append(p_return_value); + } break; + } + } } void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 1e66af269a..b1f3cd5fb3 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -37,6 +37,17 @@ #include "gdscript_utility_functions.h" class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { + struct StackSlot { + Variant::Type type = Variant::NIL; + Vector<int> bytecode_indices; + + StackSlot() = default; + StackSlot(Variant::Type p_type) : + type(p_type) {} + }; + + const static int RESERVED_STACK = 3; // For self, class, and nil. + bool ended = false; GDScriptFunction *function = nullptr; bool debug_stack = false; @@ -47,15 +58,17 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { List<int> stack_identifiers_counts; Map<StringName, int> local_constants; + Vector<StackSlot> locals; + Vector<StackSlot> temporaries; + List<int> used_temporaries; + Map<Variant::Type, List<int>> temporaries_pool; + List<GDScriptFunction::StackDebug> stack_debug; List<Map<StringName, int>> block_identifier_stack; Map<StringName, int> block_identifiers; - int current_stack_size = 0; - int current_temporaries = 0; - int current_locals = 0; + int max_locals = 0; int current_line = 0; - int stack_max = 0; int instr_args_max = 0; int ptrcall_max = 0; @@ -80,6 +93,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { Map<Variant::ValidatedUtilityFunction, int> utilities_map; Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map; Map<MethodBind *, int> method_bind_map; + Map<GDScriptFunction *, int> lambdas_map; // Lists since these can be nested. List<int> if_jmp_addrs; @@ -102,7 +116,9 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { List<List<int>> match_continues_to_patch; void add_stack_identifier(const StringName &p_id, int p_stackpos) { - current_locals++; + if (locals.size() > max_locals) { + max_locals = locals.size(); + } stack_identifiers[p_id] = p_stackpos; if (debug_stack) { block_identifiers[p_id] = p_stackpos; @@ -116,7 +132,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } void push_stack_identifiers() { - stack_identifiers_counts.push_back(current_locals); + stack_identifiers_counts.push_back(locals.size()); stack_id_stack.push_back(stack_identifiers); if (debug_stack) { Map<StringName, int> block_ids(block_identifiers); @@ -126,17 +142,16 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } void pop_stack_identifiers() { - current_locals = stack_identifiers_counts.back()->get(); + int current_locals = stack_identifiers_counts.back()->get(); stack_identifiers_counts.pop_back(); stack_identifiers = stack_id_stack.back()->get(); stack_id_stack.pop_back(); #ifdef DEBUG_ENABLED - if (current_temporaries != 0) { - ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries)); + if (!used_temporaries.is_empty()) { + ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(used_temporaries.size())); } #endif - current_stack_size = current_locals; - + locals.resize(current_locals); if (debug_stack) { for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) { GDScriptFunction::StackDebug sd; @@ -163,64 +178,72 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } int get_constant_pos(const Variant &p_constant) { - if (constant_map.has(p_constant)) + if (constant_map.has(p_constant)) { return constant_map[p_constant]; + } int pos = constant_map.size(); constant_map[p_constant] = pos; return pos; } int get_operation_pos(const Variant::ValidatedOperatorEvaluator p_operation) { - if (operator_func_map.has(p_operation)) + if (operator_func_map.has(p_operation)) { return operator_func_map[p_operation]; + } int pos = operator_func_map.size(); operator_func_map[p_operation] = pos; return pos; } int get_setter_pos(const Variant::ValidatedSetter p_setter) { - if (setters_map.has(p_setter)) + if (setters_map.has(p_setter)) { return setters_map[p_setter]; + } int pos = setters_map.size(); setters_map[p_setter] = pos; return pos; } int get_getter_pos(const Variant::ValidatedGetter p_getter) { - if (getters_map.has(p_getter)) + if (getters_map.has(p_getter)) { return getters_map[p_getter]; + } int pos = getters_map.size(); getters_map[p_getter] = pos; return pos; } int get_keyed_setter_pos(const Variant::ValidatedKeyedSetter p_keyed_setter) { - if (keyed_setters_map.has(p_keyed_setter)) + if (keyed_setters_map.has(p_keyed_setter)) { return keyed_setters_map[p_keyed_setter]; + } int pos = keyed_setters_map.size(); keyed_setters_map[p_keyed_setter] = pos; return pos; } int get_keyed_getter_pos(const Variant::ValidatedKeyedGetter p_keyed_getter) { - if (keyed_getters_map.has(p_keyed_getter)) + if (keyed_getters_map.has(p_keyed_getter)) { return keyed_getters_map[p_keyed_getter]; + } int pos = keyed_getters_map.size(); keyed_getters_map[p_keyed_getter] = pos; return pos; } int get_indexed_setter_pos(const Variant::ValidatedIndexedSetter p_indexed_setter) { - if (indexed_setters_map.has(p_indexed_setter)) + if (indexed_setters_map.has(p_indexed_setter)) { return indexed_setters_map[p_indexed_setter]; + } int pos = indexed_setters_map.size(); indexed_setters_map[p_indexed_setter] = pos; return pos; } int get_indexed_getter_pos(const Variant::ValidatedIndexedGetter p_indexed_getter) { - if (indexed_getters_map.has(p_indexed_getter)) + if (indexed_getters_map.has(p_indexed_getter)) { return indexed_getters_map[p_indexed_getter]; + } int pos = indexed_getters_map.size(); indexed_getters_map[p_indexed_getter] = pos; return pos; @@ -271,45 +294,39 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { return pos; } - void alloc_stack(int p_level) { - if (p_level >= stack_max) - stack_max = p_level + 1; - } - - int increase_stack() { - int top = current_stack_size++; - alloc_stack(current_stack_size); - return top; + int get_lambda_function_pos(GDScriptFunction *p_lambda_function) { + if (lambdas_map.has(p_lambda_function)) { + return lambdas_map[p_lambda_function]; + } + int pos = lambdas_map.size(); + lambdas_map[p_lambda_function] = pos; + return pos; } void alloc_ptrcall(int p_params) { - if (p_params >= ptrcall_max) + if (p_params >= ptrcall_max) { ptrcall_max = p_params; + } } int address_of(const Address &p_address) { switch (p_address.mode) { case Address::SELF: - return GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS; + return GDScriptFunction::ADDR_SELF; case Address::CLASS: - return GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS; + return GDScriptFunction::ADDR_CLASS; case Address::MEMBER: return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS); - case Address::CLASS_CONSTANT: - return p_address.address | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS); - case Address::LOCAL_CONSTANT: case Address::CONSTANT: - return p_address.address | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); + return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); case Address::LOCAL_VARIABLE: - case Address::TEMPORARY: case Address::FUNCTION_PARAMETER: return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); - case Address::GLOBAL: - return p_address.address | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); - case Address::NAMED_GLOBAL: - return p_address.address | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS); + case Address::TEMPORARY: + temporaries.write[p_address.address].bytecode_indices.push_back(opcodes.size()); + return -1; case Address::NIL: - return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS; + return GDScriptFunction::ADDR_NIL; } return -1; // Unreachable. } @@ -379,6 +396,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { opcodes.push_back(get_method_bind_pos(p_method)); } + void append(GDScriptFunction *p_lambda_function) { + opcodes.push_back(get_lambda_function_pos(p_lambda_function)); + } + void patch_jump(int p_address) { opcodes.write[p_address] = opcodes.size(); } @@ -389,7 +410,7 @@ public: virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) override; virtual uint32_t add_or_get_constant(const Variant &p_constant) override; virtual uint32_t add_or_get_name(const StringName &p_name) override; - virtual uint32_t add_temporary() override; + virtual uint32_t add_temporary(const GDScriptDataType &p_type) override; virtual void pop_temporary() override; virtual void start_parameters() override; @@ -406,6 +427,7 @@ public: #endif virtual void set_initial_line(int p_line) override; + virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) override; virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) override; virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override; virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) override; @@ -428,9 +450,11 @@ public: virtual void write_set_member(const Address &p_value, const StringName &p_name) override; virtual void write_get_member(const Address &p_target, const StringName &p_name) override; virtual void write_assign(const Address &p_target, const Address &p_source) override; + virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) override; virtual void write_assign_true(const Address &p_target) override; virtual void write_assign_false(const Address &p_target) override; virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override; + virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override; virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override; virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; @@ -438,13 +462,16 @@ public: virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override; virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; + virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override; + virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) override; virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override; virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override; + virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override; virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) override; virtual void write_await(const Address &p_target, const Address &p_operand) override; virtual void write_if(const Address &p_condition) override; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 113d36be98..1a844bf241 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -30,7 +30,7 @@ #include "gdscript_cache.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/templates/vector.h" #include "gdscript.h" #include "gdscript_analyzer.h" @@ -134,7 +134,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP return ref; } GDScriptParser *parser = memnew(GDScriptParser); - ref.instance(); + ref.instantiate(); ref->parser = parser; ref->path = p_path; singleton->parser_map[p_path] = ref.ptr(); @@ -153,9 +153,9 @@ String GDScriptCache::get_source_code(const String &p_path) { ERR_FAIL_COND_V(err, ""); } - int len = f->get_len(); + uint64_t len = f->get_length(); source_file.resize(len + 1); - int r = f->get_buffer(source_file.ptrw(), len); + uint64_t r = f->get_buffer(source_file.ptrw(), len); f->close(); ERR_FAIL_COND_V(r != len, ""); source_file.write[len] = 0; @@ -180,7 +180,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri } Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(p_path, true); script->set_script_path(p_path); script->load_source_code(p_path); diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index d1d2a2abbf..943638d29f 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_CACHE_H #define GDSCRIPT_CACHE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/templates/hash_map.h" #include "core/templates/set.h" @@ -40,7 +40,7 @@ class GDScriptAnalyzer; class GDScriptParser; -class GDScriptParserRef : public Reference { +class GDScriptParserRef : public RefCounted { public: enum Status { EMPTY, diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index d72bd12033..cac6544f03 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -45,13 +45,9 @@ public: CLASS, MEMBER, CONSTANT, - CLASS_CONSTANT, - LOCAL_CONSTANT, LOCAL_VARIABLE, FUNCTION_PARAMETER, TEMPORARY, - GLOBAL, - NAMED_GLOBAL, NIL, }; AddressMode mode = NIL; @@ -75,7 +71,7 @@ public: virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) = 0; virtual uint32_t add_or_get_constant(const Variant &p_constant) = 0; virtual uint32_t add_or_get_name(const StringName &p_name) = 0; - virtual uint32_t add_temporary() = 0; + virtual uint32_t add_temporary(const GDScriptDataType &p_type) = 0; virtual void pop_temporary() = 0; virtual void start_parameters() = 0; @@ -84,9 +80,6 @@ public: virtual void start_block() = 0; virtual void end_block() = 0; - // virtual int get_max_stack_level() = 0; - // virtual int get_max_function_arguments() = 0; - virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) = 0; virtual GDScriptFunction *write_end() = 0; @@ -95,9 +88,7 @@ public: #endif virtual void set_initial_line(int p_line) = 0; - // virtual void alloc_stack(int p_level) = 0; // Is this needed? - // virtual void alloc_call(int p_arg_count) = 0; // This might be automatic from other functions. - + virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) = 0; virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) = 0; virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0; virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) = 0; @@ -120,9 +111,11 @@ public: virtual void write_set_member(const Address &p_value, const StringName &p_name) = 0; virtual void write_get_member(const Address &p_target, const StringName &p_name) = 0; virtual void write_assign(const Address &p_target, const Address &p_source) = 0; + virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) = 0; virtual void write_assign_true(const Address &p_target) = 0; virtual void write_assign_false(const Address &p_target) = 0; virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0; + virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0; virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0; virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; @@ -130,17 +123,19 @@ public: virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0; virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; + virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; + virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) = 0; virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0; virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0; + virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) = 0; virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) = 0; virtual void write_await(const Address &p_target, const Address &p_operand) = 0; virtual void write_if(const Address &p_condition) = 0; - // virtual void write_elseif(const Address &p_condition) = 0; This kind of makes things more difficult for no real benefit. virtual void write_else() = 0; virtual void write_endif() = 0; virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 63ca34fc24..7fa8e9c067 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -137,22 +137,22 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D } } } break; + case GDScriptParser::DataType::ENUM: case GDScriptParser::DataType::ENUM_VALUE: result.has_type = true; result.kind = GDScriptDataType::BUILTIN; result.builtin_type = Variant::INT; break; - case GDScriptParser::DataType::ENUM: - result.has_type = true; - result.kind = GDScriptDataType::BUILTIN; - result.builtin_type = Variant::DICTIONARY; - break; case GDScriptParser::DataType::UNRESOLVED: { ERR_PRINT("Parser bug: converting unresolved type."); return GDScriptDataType(); } } + if (p_datatype.has_container_element_type()) { + result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type())); + } + // Only hold strong reference to the script if it's not the owner of the // element qualified with this type, to avoid cyclic references (leaks). if (result.script_type && result.script_type == p_owner) { @@ -262,7 +262,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code GDScriptNativeClass *nc = nullptr; while (scr) { if (scr->constants.has(identifier)) { - return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here. + return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here. } if (scr->native.is_valid()) { nc = scr->native.ptr(); @@ -319,7 +319,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; - return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type. + Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx]; + return codegen.add_constant(global); // TODO: Get type. } // Try global classes. @@ -347,7 +348,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code #ifdef TOOLS_ENABLED if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { - return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type. + GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type. + gen->write_store_named_global(global, identifier); + return global; } #endif @@ -376,10 +379,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code Vector<GDScriptCodeGenerator::Address> values; // Create the result temporary first since it's the last to be killed. - GDScriptDataType array_type; - array_type.has_type = true; - array_type.kind = GDScriptDataType::BUILTIN; - array_type.builtin_type = Variant::ARRAY; + GDScriptDataType array_type = _gdtype_from_datatype(an->get_datatype()); GDScriptCodeGenerator::Address result = codegen.add_temporary(array_type); for (int i = 0; i < an->elements.size(); i++) { @@ -390,7 +390,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code values.push_back(val); } - gen->write_construct_array(result, values); + if (array_type.has_container_element_type()) { + gen->write_construct_typed_array(result, array_type.get_container_element_type(), values); + } else { + gen->write_construct_array(result, values); + } for (int i = 0; i < values.size(); i++) { if (values[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -423,8 +427,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } break; case GDScriptParser::DictionaryNode::LUA_TABLE: - // Lua-style: key is an identifier interpreted as string. - String key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name; + // Lua-style: key is an identifier interpreted as StringName. + StringName key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name; element = codegen.add_constant(key); break; } @@ -533,39 +537,44 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee); if (subscript->is_attribute) { - GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); - if (r_error) { - return GDScriptCodeGenerator::Address(); - } - if (within_await) { - gen->write_call_async(result, base, call->function_name, arguments); - } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) { - // Native method, use faster path. - StringName class_name; - if (base.type.kind == GDScriptDataType::NATIVE) { - class_name = base.type.native_type; - } else { - class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type; + // May be static built-in method call. + if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { + gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); + } else { + GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); + if (r_error) { + return GDScriptCodeGenerator::Address(); } - if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { - MethodBind *method = ClassDB::get_method(class_name, call->function_name); - if (_have_exact_arguments(method, arguments)) { - // Exact arguments, use ptrcall. - gen->write_call_ptrcall(result, base, method, arguments); + if (within_await) { + gen->write_call_async(result, base, call->function_name, arguments); + } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) { + // Native method, use faster path. + StringName class_name; + if (base.type.kind == GDScriptDataType::NATIVE) { + class_name = base.type.native_type; + } else { + class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type; + } + if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { + MethodBind *method = ClassDB::get_method(class_name, call->function_name); + if (_have_exact_arguments(method, arguments)) { + // Exact arguments, use ptrcall. + gen->write_call_ptrcall(result, base, method, arguments); + } else { + // Not exact arguments, but still can use method bind call. + gen->write_call_method_bind(result, base, method, arguments); + } } else { - // Not exact arguments, but still can use method bind call. - gen->write_call_method_bind(result, base, method, arguments); + gen->write_call(result, 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); } - } 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); - } - if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { - gen->pop_temporary(); + if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } } } else { _set_error("Cannot call something that isn't a function.", call->callee); @@ -676,9 +685,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code name = subscript->attribute->name; named = true; } else { - if (subscript->index->type == GDScriptParser::Node::LITERAL && static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value.get_type() == Variant::STRING) { + if (subscript->index->is_constant && subscript->index->reduced_value.get_type() == Variant::STRING_NAME) { // Also, somehow, named (speed up anyway). - name = static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value; + name = subscript->index->reduced_value; named = true; } else { // Regular indexing. @@ -707,7 +716,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::UNARY_OPERATOR: { const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression); - GDScriptCodeGenerator::Address result = codegen.add_temporary(); + GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(unary->get_datatype())); GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand); if (r_error) { @@ -725,7 +734,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::BINARY_OPERATOR: { const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression); - GDScriptCodeGenerator::Address result = codegen.add_temporary(); + GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(binary->get_datatype())); switch (binary->operation) { case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: { @@ -777,6 +786,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->pop_temporary(); } } + + if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } } break; default: { GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand); @@ -958,6 +971,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } else { gen->write_set(prev_base, key, assigned); } + if (key.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); } @@ -1068,7 +1084,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), setter_function, args); } else { // Just assign. - gen->write_assign(target, op_result); + if (assignment->use_conversion_assign) { + gen->write_assign_with_conversion(target, op_result); + } else { + gen->write_assign(target, op_result); + } } if (op_result.mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -1083,6 +1103,34 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } return GDScriptCodeGenerator::Address(); // Assignment does not return a value. } break; + case GDScriptParser::Node::LAMBDA: { + const GDScriptParser::LambdaNode *lambda = static_cast<const GDScriptParser::LambdaNode *>(p_expression); + GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(lambda->get_datatype())); + + Vector<GDScriptCodeGenerator::Address> captures; + captures.resize(lambda->captures.size()); + for (int i = 0; i < lambda->captures.size(); i++) { + captures.write[i] = _parse_expression(codegen, r_error, lambda->captures[i]); + if (r_error) { + return GDScriptCodeGenerator::Address(); + } + } + + GDScriptFunction *function = _parse_function(r_error, codegen.script, codegen.class_node, lambda->function, false, true); + if (r_error) { + return GDScriptCodeGenerator::Address(); + } + + gen->write_lambda(result, function, captures); + + for (int i = 0; i < captures.size(); i++) { + if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } + } + + return result; + } break; default: { ERR_FAIL_V_MSG(GDScriptCodeGenerator::Address(), "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); // Unreachable code. } break; @@ -1733,16 +1781,37 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui const GDScriptParser::VariableNode *lv = static_cast<const GDScriptParser::VariableNode *>(s); // Should be already in stack when the block began. GDScriptCodeGenerator::Address local = codegen.locals[lv->identifier->name]; + GDScriptParser::DataType local_type = lv->get_datatype(); if (lv->initializer != nullptr) { + // For typed arrays we need to make sure this is already initialized correctly so typed assignment work. + if (local_type.is_hard_type() && local_type.builtin_type == Variant::ARRAY) { + if (local_type.has_container_element_type()) { + codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>()); + } else { + codegen.generator->write_construct_array(local, Vector<GDScriptCodeGenerator::Address>()); + } + } GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, lv->initializer); if (error) { return error; } - gen->write_assign(local, src_address); + if (lv->use_conversion_assign) { + gen->write_assign_with_conversion(local, src_address); + } else { + gen->write_assign(local, src_address); + } if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } + } else if (lv->get_datatype().is_hard_type()) { + // Initialize with default for type. + if (local_type.has_container_element_type()) { + codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>()); + } else if (local_type.kind == GDScriptParser::DataType::BUILTIN) { + codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); + } + // The `else` branch is for objects, in such case we leave it as `null`. } } break; case GDScriptParser::Node::CONSTANT: { @@ -1779,8 +1848,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui return OK; } -Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) { - Error error = OK; +GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready, bool p_for_lambda) { + r_error = OK; CodeGen codegen; codegen.generator = memnew(GDScriptByteCodeGenerator); @@ -1797,7 +1866,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser return_type.builtin_type = Variant::NIL; if (p_func) { - func_name = p_func->identifier->name; + if (p_func->identifier) { + func_name = p_func->identifier->name; + } else { + func_name = "<anonymous lambda>"; + } is_static = p_func->is_static; rpc_mode = p_func->rpc_mode; return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); @@ -1828,11 +1901,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser } // Parse initializer if applies. - bool is_implicit_initializer = !p_for_ready && !p_func; - bool is_initializer = p_func && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init; - bool is_for_ready = p_for_ready || (p_func && String(p_func->identifier->name) == "_ready"); + bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda; + bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init; + bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready"); - if (is_implicit_initializer || is_for_ready) { + if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) { // Initialize class fields. for (int i = 0; i < p_class->members.size(); i++) { if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) { @@ -1844,21 +1917,45 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser continue; } + GDScriptParser::DataType field_type = field->get_datatype(); + + GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype())); if (field->initializer) { // Emit proper line change. codegen.generator->write_newline(field->initializer->start_line); - GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, field->initializer, false, true); - if (error) { + // For typed arrays we need to make sure this is already initialized correctly so typed assignment work. + if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type()) { + if (field_type.has_container_element_type()) { + codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>()); + } else { + codegen.generator->write_construct_array(dst_address, Vector<GDScriptCodeGenerator::Address>()); + } + } + GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, r_error, field->initializer, false, true); + if (r_error) { memdelete(codegen.generator); - return error; + return nullptr; } - GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype())); - codegen.generator->write_assign(dst_address, src_address); + if (field->use_conversion_assign) { + codegen.generator->write_assign_with_conversion(dst_address, src_address); + } else { + codegen.generator->write_assign(dst_address, src_address); + } if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } + } else if (field->get_datatype().is_hard_type()) { + codegen.generator->write_newline(field->start_line); + + // Initialize with default for type. + if (field_type.has_container_element_type()) { + codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>()); + } else if (field_type.kind == GDScriptParser::DataType::BUILTIN) { + codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); + } + // The `else` branch is for objects, in such case we leave it as `null`. } } } @@ -1869,10 +1966,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser codegen.generator->start_parameters(); for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) { const GDScriptParser::ParameterNode *parameter = p_func->parameters[i]; - GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, error, parameter->default_value, true); - if (error) { + GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true); + if (r_error) { memdelete(codegen.generator); - return error; + return nullptr; } GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name]; codegen.generator->write_assign_default_parameter(dst_addr, src_addr); @@ -1883,10 +1980,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser codegen.generator->end_parameters(); } - Error err = _parse_block(codegen, p_func->body); - if (err) { + r_error = _parse_block(codegen, p_func->body); + if (r_error) { memdelete(codegen.generator); - return err; + return nullptr; } } @@ -1912,6 +2009,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser signature += "::" + String(func_name); } + if (p_for_lambda) { + signature += "(lambda)"; + } + codegen.generator->set_signature(signature); } #endif @@ -1919,8 +2020,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser if (p_func) { codegen.generator->set_initial_line(p_func->start_line); #ifdef TOOLS_ENABLED - p_script->member_lines[func_name] = p_func->start_line; - p_script->doc_functions[func_name] = p_func->doc_description; + if (!p_for_lambda) { + p_script->member_lines[func_name] = p_func->start_line; + p_script->doc_functions[func_name] = p_func->doc_description; + } #endif } else { codegen.generator->set_initial_line(0); @@ -1949,11 +2052,13 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser #endif } - p_script->member_functions[func_name] = gd_function; + if (!p_for_lambda) { + p_script->member_functions[func_name] = gd_function; + } memdelete(codegen.generator); - return OK; + return gd_function; } Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) { @@ -1972,6 +2077,8 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP func_name = "@" + p_variable->identifier->name + "_getter"; } + codegen.function_name = func_name; + GDScriptDataType return_type; if (p_is_setter) { return_type.has_type = true; @@ -2116,7 +2223,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar if (err) { return err; } - if (base.is_null() && !base->is_valid()) { + if (base.is_null() || !base->is_valid()) { return ERR_COMPILATION_FAILED; } } @@ -2175,7 +2282,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } prop_info.hint = export_info.hint; prop_info.hint_string = export_info.hint_string; - prop_info.usage = export_info.usage; + prop_info.usage = export_info.usage | PROPERTY_USAGE_SCRIPT_VARIABLE; } else { prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE; } @@ -2345,7 +2452,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa if (!has_ready && function->identifier->name == "_ready") { has_ready = true; } - Error err = _parse_function(p_script, p_class, function); + Error err = OK; + _parse_function(err, p_script, p_class, function); if (err) { return err; } @@ -2370,7 +2478,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa { // Create an implicit constructor in any case. - Error err = _parse_function(p_script, p_class, nullptr); + Error err = OK; + _parse_function(err, p_script, p_class, nullptr); if (err) { return err; } @@ -2378,7 +2487,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa if (!has_ready && p_class->onready_used) { //create a _ready constructor - Error err = _parse_function(p_script, p_class, nullptr, true); + Error err = OK; + _parse_function(err, p_script, p_class, nullptr, true); if (err) { return err; } @@ -2402,7 +2512,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa p_script->placeholders.erase(psi); //remove placeholder GDScriptInstance *instance = memnew(GDScriptInstance); - instance->base_ref = Object::cast_to<Reference>(E->get()); + instance->base_ref_counted = Object::cast_to<RefCounted>(E->get()); instance->members.resize(p_script->member_indices.size()); instance->script = Ref<GDScript>(p_script); instance->owner = E->get(); @@ -2477,7 +2587,7 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C if (orphan_subclass.is_valid()) { subclass = orphan_subclass; } else { - subclass.instance(); + subclass.instantiate(); } } diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 651391f972..7d5bee93ac 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -61,12 +61,12 @@ class GDScriptCompiler { GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) { uint32_t addr = generator->add_local_constant(p_name, p_value); - locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_CONSTANT, addr); + locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr); return locals[p_name]; } GDScriptCodeGenerator::Address add_temporary(const GDScriptDataType &p_type = GDScriptDataType()) { - uint32_t addr = generator->add_temporary(); + uint32_t addr = generator->add_temporary(p_type); return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::TEMPORARY, addr, p_type); } @@ -128,7 +128,7 @@ class GDScriptCompiler { GDScriptCodeGenerator::Address _parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested); void _add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block); Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals = true); - Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false); + GDScriptFunction *_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false, bool p_for_lambda = false); Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter); Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index 17cb5e3c96..1acb9ceddc 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -69,35 +69,23 @@ static String _disassemble_address(const GDScript *p_script, const GDScriptFunct int addr = p_address & GDScriptFunction::ADDR_MASK; switch (p_address >> GDScriptFunction::ADDR_BITS) { - case GDScriptFunction::ADDR_TYPE_SELF: { - return "self"; - } break; - case GDScriptFunction::ADDR_TYPE_CLASS: { - return "class"; - } break; case GDScriptFunction::ADDR_TYPE_MEMBER: { return "member(" + p_script->debug_get_member_by_index(addr) + ")"; } break; - case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: { - return "class_const(" + p_function.get_global_name(addr) + ")"; - } break; - case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: { + case GDScriptFunction::ADDR_TYPE_CONSTANT: { return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")"; } break; case GDScriptFunction::ADDR_TYPE_STACK: { - return "stack(" + itos(addr) + ")"; - } break; - case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: { - return "var_stack(" + itos(addr) + ")"; - } break; - case GDScriptFunction::ADDR_TYPE_GLOBAL: { - return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")"; - } break; - case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: { - return "named_global(" + p_function.get_global_name(addr) + ")"; - } break; - case GDScriptFunction::ADDR_TYPE_NIL: { - return "nil"; + switch (addr) { + case GDScriptFunction::ADDR_STACK_SELF: + return "self"; + case GDScriptFunction::ADDR_STACK_CLASS: + return "class"; + case GDScriptFunction::ADDR_STACK_NIL: + return "nil"; + default: + return "stack(" + itos(addr) + ")"; + } } break; } @@ -322,6 +310,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4; } break; + case OPCODE_ASSIGN_TYPED_ARRAY: { + text += "assign typed array "; + text += DADDR(1); + text += " = "; + text += DADDR(2); + + incr += 3; + } break; case OPCODE_ASSIGN_TYPED_NATIVE: { text += "assign typed native ("; text += DADDR(3); @@ -385,8 +381,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += Variant::get_type_name(t) + "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(i + 1); } text += ")"; @@ -400,10 +397,11 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += DADDR(1 + argc); text += " = "; - text += "<unkown type>("; + text += "<unknown type>("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(i + 1); } text += ")"; @@ -417,8 +415,43 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += " = ["; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + + text += "]"; + + incr += 3 + argc; + } break; + case OPCODE_CONSTRUCT_TYPED_ARRAY: { + int argc = _code_ptr[ip + 1 + instr_var_args]; + + Ref<Script> script_type = get_constant(_code_ptr[ip + argc + 2]); + Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + argc + 4]; + StringName native_type = get_global_name(_code_ptr[ip + argc + 5]); + + String type_name; + if (script_type.is_valid() && script_type->is_valid()) { + type_name = script_type->get_path(); + } else if (native_type != StringName()) { + type_name = native_type; + } else { + type_name = Variant::get_type_name(builtin_type); + } + + text += " make_typed_array ("; + text += type_name; + text += ") "; + + text += DADDR(1 + argc); + text += " = ["; + + for (int i = 0; i < argc; i++) { + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } @@ -433,8 +466,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += " = {"; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i * 2 + 0); text += ": "; text += DADDR(1 + i * 2 + 1); @@ -468,8 +502,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -498,14 +533,37 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; incr = 5 + argc; } break; + case OPCODE_CALL_BUILTIN_STATIC: { + Variant::Type type = (Variant::Type)_code_ptr[ip + 1 + instr_var_args]; + int argc = _code_ptr[ip + 3 + instr_var_args]; + + text += "call built-in method static "; + text += DADDR(1 + argc); + text += " = "; + text += Variant::get_type_name(type); + text += "."; + text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]].operator String(); + text += "("; + + for (int i = 0; i < argc; i++) { + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + text += ")"; + + incr += 5 + argc; + } break; case OPCODE_CALL_PTRCALL_NO_RETURN: { text += "call-ptrcall (no return) "; @@ -518,8 +576,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -561,12 +620,12 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { DISASSEMBLE_PTRCALL(PLANE); DISASSEMBLE_PTRCALL(AABB); DISASSEMBLE_PTRCALL(BASIS); - DISASSEMBLE_PTRCALL(TRANSFORM); + DISASSEMBLE_PTRCALL(TRANSFORM3D); DISASSEMBLE_PTRCALL(COLOR); DISASSEMBLE_PTRCALL(STRING_NAME); DISASSEMBLE_PTRCALL(NODE_PATH); DISASSEMBLE_PTRCALL(RID); - DISASSEMBLE_PTRCALL(QUAT); + DISASSEMBLE_PTRCALL(QUATERNION); DISASSEMBLE_PTRCALL(OBJECT); DISASSEMBLE_PTRCALL(CALLABLE); DISASSEMBLE_PTRCALL(SIGNAL); @@ -595,8 +654,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -613,8 +673,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -627,12 +688,13 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { int argc = _code_ptr[ip + 1 + instr_var_args]; text += DADDR(1 + argc) + " = "; - text += "<unkown function>"; + text += "<unknown function>"; text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -649,8 +711,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -667,8 +730,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -679,7 +743,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += "await "; text += DADDR(1); - incr += 2; + incr = 2; } break; case OPCODE_AWAIT_RESUME: { text += "await resume "; @@ -687,6 +751,25 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr = 2; } break; + case OPCODE_CREATE_LAMBDA: { + int captures_count = _code_ptr[ip + 1 + instr_var_args]; + GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]]; + + text += DADDR(1 + captures_count); + text += "create lambda from "; + text += lambda->name.operator String(); + text += "function, captures ("; + + for (int i = 0; i < captures_count; i++) { + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + text += ")"; + + incr = 3 + captures_count; + } break; case OPCODE_JUMP: { text += "jump "; text += itos(_code_ptr[ip + 1]); @@ -720,6 +803,39 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr = 2; } break; + case OPCODE_RETURN_TYPED_BUILTIN: { + text += "return typed builtin ("; + text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 2]); + text += ") "; + text += DADDR(1); + + incr += 3; + } break; + case OPCODE_RETURN_TYPED_ARRAY: { + text += "return typed array "; + text += DADDR(1); + + incr += 5; + } break; + case OPCODE_RETURN_TYPED_NATIVE: { + text += "return typed native ("; + text += DADDR(2); + text += ") "; + text += DADDR(1); + + incr += 3; + } break; + case OPCODE_RETURN_TYPED_SCRIPT: { + Variant script = _constants_ptr[_code_ptr[ip + 2]]; + Script *sc = Object::cast_to<Script>(script.operator Object *()); + + text += "return typed script ("; + text += sc->get_path(); + text += ") "; + text += DADDR(1); + + incr += 3; + } break; #define DISASSEMBLE_ITERATE(m_type) \ case OPCODE_ITERATE_##m_type: { \ @@ -798,6 +914,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 5; } break; DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE); + case OPCODE_STORE_NAMED_GLOBAL: { + text += "store named global "; + text += DADDR(1); + text += " = "; + text += String(_global_names_ptr[_code_ptr[ip + 2]]); + + incr += 3; + } break; case OPCODE_LINE: { int line = _code_ptr[ip + 1] - 1; if (line >= 0 && line < p_code_lines.size()) { @@ -811,6 +935,51 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 2; } break; + +#define DISASSEMBLE_TYPE_ADJUST(m_v_type) \ + case OPCODE_TYPE_ADJUST_##m_v_type: { \ + text += "type adjust ("; \ + text += #m_v_type; \ + text += ") "; \ + text += DADDR(1); \ + incr += 2; \ + } break + + DISASSEMBLE_TYPE_ADJUST(BOOL); + DISASSEMBLE_TYPE_ADJUST(INT); + DISASSEMBLE_TYPE_ADJUST(FLOAT); + DISASSEMBLE_TYPE_ADJUST(STRING); + DISASSEMBLE_TYPE_ADJUST(VECTOR2); + DISASSEMBLE_TYPE_ADJUST(VECTOR2I); + DISASSEMBLE_TYPE_ADJUST(RECT2); + DISASSEMBLE_TYPE_ADJUST(RECT2I); + DISASSEMBLE_TYPE_ADJUST(VECTOR3); + DISASSEMBLE_TYPE_ADJUST(VECTOR3I); + DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D); + DISASSEMBLE_TYPE_ADJUST(PLANE); + DISASSEMBLE_TYPE_ADJUST(QUATERNION); + DISASSEMBLE_TYPE_ADJUST(AABB); + DISASSEMBLE_TYPE_ADJUST(BASIS); + DISASSEMBLE_TYPE_ADJUST(TRANSFORM); + DISASSEMBLE_TYPE_ADJUST(COLOR); + DISASSEMBLE_TYPE_ADJUST(STRING_NAME); + DISASSEMBLE_TYPE_ADJUST(NODE_PATH); + DISASSEMBLE_TYPE_ADJUST(RID); + DISASSEMBLE_TYPE_ADJUST(OBJECT); + DISASSEMBLE_TYPE_ADJUST(CALLABLE); + DISASSEMBLE_TYPE_ADJUST(SIGNAL); + DISASSEMBLE_TYPE_ADJUST(DICTIONARY); + DISASSEMBLE_TYPE_ADJUST(ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_BYTE_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_INT32_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_INT64_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_STRING_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY); + DISASSEMBLE_TYPE_ADJUST(PACKED_COLOR_ARRAY); + case OPCODE_ASSERT: { text += "assert ("; text += DADDR(1); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index a9975c8602..c1a7bedbc8 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -32,7 +32,7 @@ #include "core/config/engine.h" #include "core/core_constants.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "gdscript_analyzer.h" #include "gdscript_compiler.h" #include "gdscript_parser.h" @@ -104,7 +104,7 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str _template = _get_processed_template(_template, p_base_class_name); Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_source_code(_template); return script; @@ -131,7 +131,7 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl } } -bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { GDScriptParser parser; GDScriptAnalyzer analyzer(&parser); @@ -156,10 +156,16 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & } #endif if (err) { - GDScriptParser::ParserError parse_error = parser.get_errors().front()->get(); - r_line_error = parse_error.line; - r_col_error = parse_error.column; - r_test_error = parse_error.message; + if (r_errors) { + for (const List<GDScriptParser::ParserError>::Element *E = parser.get_errors().front(); E; E = E->next()) { + const GDScriptParser::ParserError &pe = E->get(); + ScriptLanguage::ScriptError e; + e.line = pe.line; + e.column = pe.column; + e.message = pe.message; + r_errors->push_back(e); + } + } return false; } else { const GDScriptParser::ClassNode *cl = parser.get_tree(); @@ -500,36 +506,6 @@ struct GDScriptCompletionIdentifier { const GDScriptParser::ExpressionNode *assigned_expression = nullptr; }; -// TODO: Move this to a central location (maybe core?). -static const char *underscore_classes[] = { - "ClassDB", - "Directory", - "Engine", - "File", - "Geometry", - "GodotSharp", - "JSON", - "Marshalls", - "Mutex", - "OS", - "ResourceLoader", - "ResourceSaver", - "Semaphore", - "Thread", - "VisualScriptEditor", - nullptr, -}; -static StringName _get_real_class_name(const StringName &p_source) { - const char **class_name = underscore_classes; - while (*class_name != nullptr) { - if (p_source == *class_name) { - return String("_") + p_source; - } - class_name++; - } - return p_source; -} - static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) { if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { String enum_name = p_info.class_name; @@ -768,7 +744,13 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptCodeCompletionOption> &r_result) { for (int i = 0; i < p_suite->locals.size(); i++) { - ScriptCodeCompletionOption option(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE); + ScriptCodeCompletionOption option; + if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) { + option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_CONSTANT); + option.default_value = p_suite->locals[i].constant->initializer->reduced_value; + } else { + option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE); + } r_result.insert(option.display, option); } if (p_suite->parent_block) { @@ -930,7 +912,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } } break; case GDScriptParser::DataType::NATIVE: { - StringName type = _get_real_class_name(base_type.native_type); + StringName type = GDScriptParser::get_real_class_name(base_type.native_type); if (!ClassDB::class_exists(type)) { return; } @@ -1053,7 +1035,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool } static const char *_type_names[Variant::VARIANT_MAX] = { - "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", + "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D", "Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray", "PackedVector2Array", "PackedVector3Array", "PackedColorArray" }; @@ -1067,7 +1049,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool static const char *_keywords[] = { "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super", "break", "continue", "pass", "return", - 0 + nullptr }; const char **kw = _keywords; @@ -1080,7 +1062,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool static const char *_keywords_with_space[] = { "and", "in", "not", "or", "as", "class", "extends", "is", "func", "signal", "await", "const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while", - 0 + nullptr }; const char **kws = _keywords_with_space; @@ -1093,7 +1075,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool static const char *_keywords_with_args[] = { "assert", "preload", - 0 + nullptr }; const char **kwa = _keywords_with_args; @@ -1775,15 +1757,15 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, return true; } } - base_type = base_type.class_type->base_type; } + base_type = base_type.class_type->base_type; break; case GDScriptParser::DataType::NATIVE: { if (id_type.is_set() && !id_type.is_variant()) { base_type = GDScriptParser::DataType(); break; } - StringName real_native = _get_real_class_name(base_type.native_type); + StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type); MethodInfo info; if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) { for (const List<PropertyInfo>::Element *E = info.arguments.front(); E; E = E->next()) { @@ -1854,7 +1836,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } // Check ClassDB. - StringName class_name = _get_real_class_name(p_identifier); + StringName class_name = GDScriptParser::get_real_class_name(p_identifier); if (ClassDB::class_exists(class_name) && ClassDB::is_class_exposed(class_name)) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::NATIVE; @@ -1970,7 +1952,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & } } break; case GDScriptParser::DataType::NATIVE: { - StringName class_name = _get_real_class_name(base_type.native_type); + StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type); if (!ClassDB::class_exists(class_name)) { return false; } @@ -2133,7 +2115,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex } } break; case GDScriptParser::DataType::NATIVE: { - StringName native = _get_real_class_name(base_type.native_type); + StringName native = GDScriptParser::get_real_class_name(base_type.native_type); if (!ClassDB::class_exists(native)) { return false; } @@ -2230,7 +2212,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c base_type = base_type.class_type->base_type; } break; case GDScriptParser::DataType::NATIVE: { - StringName class_name = _get_real_class_name(base_type.native_type); + StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type); if (!ClassDB::class_exists(class_name)) { base_type.kind = GDScriptParser::DataType::UNRESOLVED; break; @@ -2402,7 +2384,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_forced = r_result.size() > 0; } -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { +::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; GDScriptParser parser; @@ -2615,7 +2597,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path break; } - StringName class_name = _get_real_class_name(native_type.native_type); + StringName class_name = GDScriptParser::get_real_class_name(native_type.native_type); if (!ClassDB::class_exists(class_name)) { break; } @@ -2844,7 +2826,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } break; case GDScriptParser::DataType::NATIVE: { - StringName class_name = _get_real_class_name(base_type.native_type); + StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type); if (!ClassDB::class_exists(class_name)) { base_type.kind = GDScriptParser::DataType::UNRESOLVED; break; @@ -2897,7 +2879,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co StringName parent = ClassDB::get_parent_class(class_name); if (parent != StringName()) { if (String(parent).begins_with("_")) { - base_type.native_type = String(parent).right(1); + base_type.native_type = String(parent).substr(1); } else { base_type.native_type = parent; } @@ -2918,11 +2900,11 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co Variant v; REF v_ref; if (base_type.builtin_type == Variant::OBJECT) { - v_ref.instance(); + v_ref.instantiate(); v = v_ref; } else { Callable::CallError err; - Variant::construct(base_type.builtin_type, v, NULL, 0, err); + Variant::construct(base_type.builtin_type, v, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { break; } @@ -2953,7 +2935,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return ERR_CANT_RESOLVE; } -Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { +::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { //before parsing, try the usual stuff if (ClassDB::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; @@ -3023,6 +3005,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol is_function = true; [[fallthrough]]; } + case GDScriptParser::COMPLETION_CALL_ARGUMENTS: case GDScriptParser::COMPLETION_IDENTIFIER: { GDScriptParser::DataType base_type; if (context.current_class) { @@ -3055,9 +3038,9 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol if (!is_function) { // Guess in autoloads as singletons. if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) { - const ProjectSettings::AutoloadInfo &singleton = ProjectSettings::get_singleton()->get_autoload(p_symbol); - if (singleton.is_singleton) { - String script = singleton.path; + const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(p_symbol); + if (autoload.is_singleton) { + String script = autoload.path; if (!script.ends_with(".gd")) { // Not a script, try find the script anyway, // may have some success. @@ -3090,7 +3073,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol // proxy class remove the underscore. if (r_result.class_name.begins_with("_")) { - r_result.class_name = r_result.class_name.right(1); + r_result.class_name = r_result.class_name.substr(1); } return OK; } @@ -3100,7 +3083,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol // We cannot determine the exact nature of the identifier here // Otherwise these codes would work StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true); - if (enumName != NULL) { + if (enumName != nullptr) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM; r_result.class_name = "@GlobalScope"; r_result.class_member = enumName; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 7b37aa40a2..78399114a5 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -150,6 +150,10 @@ GDScriptFunction::GDScriptFunction() { } GDScriptFunction::~GDScriptFunction() { + for (int i = 0; i < lambdas.size(); i++) { + memdelete(lambdas[i]); + } + #ifdef DEBUG_ENABLED MutexLock lock(GDScriptLanguage::get_singleton()->lock); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index e64630a743..553c2ecc01 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_FUNCTION_H #define GDSCRIPT_FUNCTION_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" #include "core/os/thread.h" #include "core/string/string_name.h" @@ -43,7 +43,11 @@ class GDScriptInstance; class GDScript; -struct GDScriptDataType { +class GDScriptDataType { +private: + GDScriptDataType *container_element_type = nullptr; + +public: enum Kind { UNINITIALIZED, BUILTIN, @@ -71,7 +75,24 @@ struct GDScriptDataType { case BUILTIN: { Variant::Type var_type = p_variant.get_type(); bool valid = builtin_type == var_type; - if (!valid && p_allow_implicit_conversion) { + if (valid && builtin_type == Variant::ARRAY && has_container_element_type()) { + Array array = p_variant; + if (array.is_typed()) { + Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin(); + StringName array_native_type = array.get_typed_class_name(); + Ref<Script> array_script_type_ref = array.get_typed_script(); + + if (array_script_type_ref.is_valid()) { + valid = (container_element_type->kind == SCRIPT || container_element_type->kind == GDSCRIPT) && container_element_type->script_type == array_script_type_ref.ptr(); + } else if (array_native_type != StringName()) { + valid = container_element_type->kind == NATIVE && container_element_type->native_type == array_native_type; + } else { + valid = container_element_type->kind == BUILTIN && container_element_type->builtin_type == array_builtin_type; + } + } else { + valid = false; + } + } else if (!valid && p_allow_implicit_conversion) { valid = Variant::can_convert_strict(var_type, builtin_type); } return valid; @@ -153,7 +174,49 @@ struct GDScriptDataType { return info; } - GDScriptDataType() {} + void set_container_element_type(const GDScriptDataType &p_element_type) { + container_element_type = memnew(GDScriptDataType(p_element_type)); + } + + GDScriptDataType get_container_element_type() const { + ERR_FAIL_COND_V(container_element_type == nullptr, GDScriptDataType()); + return *container_element_type; + } + + bool has_container_element_type() const { + return container_element_type != nullptr; + } + + void unset_container_element_type() { + if (container_element_type) { + memdelete(container_element_type); + } + container_element_type = nullptr; + } + + GDScriptDataType() = default; + + GDScriptDataType &operator=(const GDScriptDataType &p_other) { + kind = p_other.kind; + has_type = p_other.has_type; + builtin_type = p_other.builtin_type; + native_type = p_other.native_type; + script_type = p_other.script_type; + script_type_ref = p_other.script_type_ref; + unset_container_element_type(); + if (p_other.has_container_element_type()) { + set_container_element_type(p_other.get_container_element_type()); + } + return *this; + } + + GDScriptDataType(const GDScriptDataType &p_other) { + *this = p_other; + } + + ~GDScriptDataType() { + unset_container_element_type(); + } }; class GDScriptFunction { @@ -179,6 +242,7 @@ public: OPCODE_ASSIGN_TRUE, OPCODE_ASSIGN_FALSE, OPCODE_ASSIGN_TYPED_BUILTIN, + OPCODE_ASSIGN_TYPED_ARRAY, OPCODE_ASSIGN_TYPED_NATIVE, OPCODE_ASSIGN_TYPED_SCRIPT, OPCODE_CAST_TO_BUILTIN, @@ -187,6 +251,7 @@ public: OPCODE_CONSTRUCT, // Only for basic types! OPCODE_CONSTRUCT_VALIDATED, // Only for basic types! OPCODE_CONSTRUCT_ARRAY, + OPCODE_CONSTRUCT_TYPED_ARRAY, OPCODE_CONSTRUCT_DICTIONARY, OPCODE_CALL, OPCODE_CALL_RETURN, @@ -198,6 +263,7 @@ public: OPCODE_CALL_SELF_BASE, OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND_RET, + OPCODE_CALL_BUILTIN_STATIC, // ptrcall have one instruction per return type. OPCODE_CALL_PTRCALL_NO_RETURN, OPCODE_CALL_PTRCALL_BOOL, @@ -212,10 +278,10 @@ public: OPCODE_CALL_PTRCALL_VECTOR3I, OPCODE_CALL_PTRCALL_TRANSFORM2D, OPCODE_CALL_PTRCALL_PLANE, - OPCODE_CALL_PTRCALL_QUAT, + OPCODE_CALL_PTRCALL_QUATERNION, OPCODE_CALL_PTRCALL_AABB, OPCODE_CALL_PTRCALL_BASIS, - OPCODE_CALL_PTRCALL_TRANSFORM, + OPCODE_CALL_PTRCALL_TRANSFORM3D, OPCODE_CALL_PTRCALL_COLOR, OPCODE_CALL_PTRCALL_STRING_NAME, OPCODE_CALL_PTRCALL_NODE_PATH, @@ -236,11 +302,16 @@ public: OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, OPCODE_AWAIT, OPCODE_AWAIT_RESUME, + OPCODE_CREATE_LAMBDA, OPCODE_JUMP, OPCODE_JUMP_IF, OPCODE_JUMP_IF_NOT, OPCODE_JUMP_TO_DEF_ARGUMENT, OPCODE_RETURN, + OPCODE_RETURN_TYPED_BUILTIN, + OPCODE_RETURN_TYPED_ARRAY, + OPCODE_RETURN_TYPED_NATIVE, + OPCODE_RETURN_TYPED_SCRIPT, OPCODE_ITERATE_BEGIN, OPCODE_ITERATE_BEGIN_INT, OPCODE_ITERATE_BEGIN_FLOAT, @@ -281,6 +352,41 @@ public: OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, OPCODE_ITERATE_PACKED_COLOR_ARRAY, OPCODE_ITERATE_OBJECT, + OPCODE_STORE_NAMED_GLOBAL, + OPCODE_TYPE_ADJUST_BOOL, + OPCODE_TYPE_ADJUST_INT, + OPCODE_TYPE_ADJUST_FLOAT, + OPCODE_TYPE_ADJUST_STRING, + OPCODE_TYPE_ADJUST_VECTOR2, + OPCODE_TYPE_ADJUST_VECTOR2I, + OPCODE_TYPE_ADJUST_RECT2, + OPCODE_TYPE_ADJUST_RECT2I, + OPCODE_TYPE_ADJUST_VECTOR3, + OPCODE_TYPE_ADJUST_VECTOR3I, + OPCODE_TYPE_ADJUST_TRANSFORM2D, + OPCODE_TYPE_ADJUST_PLANE, + OPCODE_TYPE_ADJUST_QUATERNION, + OPCODE_TYPE_ADJUST_AABB, + OPCODE_TYPE_ADJUST_BASIS, + OPCODE_TYPE_ADJUST_TRANSFORM, + OPCODE_TYPE_ADJUST_COLOR, + OPCODE_TYPE_ADJUST_STRING_NAME, + OPCODE_TYPE_ADJUST_NODE_PATH, + OPCODE_TYPE_ADJUST_RID, + OPCODE_TYPE_ADJUST_OBJECT, + OPCODE_TYPE_ADJUST_CALLABLE, + OPCODE_TYPE_ADJUST_SIGNAL, + OPCODE_TYPE_ADJUST_DICTIONARY, + OPCODE_TYPE_ADJUST_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, + OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, OPCODE_ASSERT, OPCODE_BREAKPOINT, OPCODE_LINE, @@ -291,16 +397,18 @@ public: ADDR_BITS = 24, ADDR_MASK = ((1 << ADDR_BITS) - 1), ADDR_TYPE_MASK = ~ADDR_MASK, - ADDR_TYPE_SELF = 0, - ADDR_TYPE_CLASS = 1, + ADDR_TYPE_STACK = 0, + ADDR_TYPE_CONSTANT = 1, ADDR_TYPE_MEMBER = 2, - ADDR_TYPE_CLASS_CONSTANT = 3, - ADDR_TYPE_LOCAL_CONSTANT = 4, - ADDR_TYPE_STACK = 5, - ADDR_TYPE_STACK_VARIABLE = 6, - ADDR_TYPE_GLOBAL = 7, - ADDR_TYPE_NAMED_GLOBAL = 8, - ADDR_TYPE_NIL = 9 + }; + + enum FixedAddresses { + ADDR_STACK_SELF = 0, + ADDR_STACK_CLASS = 1, + ADDR_STACK_NIL = 2, + ADDR_SELF = ADDR_STACK_SELF | (ADDR_TYPE_STACK << ADDR_BITS), + ADDR_CLASS = ADDR_STACK_CLASS | (ADDR_TYPE_STACK << ADDR_BITS), + ADDR_NIL = ADDR_STACK_NIL | (ADDR_TYPE_STACK << ADDR_BITS), }; enum Instruction { @@ -353,6 +461,8 @@ private: const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr; int _methods_count = 0; MethodBind **_methods_ptr = nullptr; + int _lambdas_count = 0; + GDScriptFunction **_lambdas_ptr = nullptr; const int *_code_ptr = nullptr; int _code_size = 0; int _argument_count = 0; @@ -382,10 +492,13 @@ private: Vector<Variant::ValidatedUtilityFunction> utilities; Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities; Vector<MethodBind *> methods; + Vector<GDScriptFunction *> lambdas; Vector<int> code; Vector<GDScriptDataType> argument_types; GDScriptDataType return_type; + Map<int, Variant::Type> temporary_slots; + #ifdef TOOLS_ENABLED Vector<StringName> arg_names; Vector<Variant> default_arg_values; @@ -393,7 +506,7 @@ private: List<StackDebug> stack_debug; - _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const; + _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const; _FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const; friend class GDScriptLanguage; @@ -428,7 +541,6 @@ public: #endif Vector<uint8_t> stack; int stack_size = 0; - Variant self; uint32_t alloca_size = 0; int ip = 0; int line = 0; @@ -485,8 +597,8 @@ public: ~GDScriptFunction(); }; -class GDScriptFunctionState : public Reference { - GDCLASS(GDScriptFunctionState, Reference); +class GDScriptFunctionState : public RefCounted { + GDCLASS(GDScriptFunctionState, RefCounted); friend class GDScriptFunction; GDScriptFunction *function = nullptr; GDScriptFunction::CallState state; diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp new file mode 100644 index 0000000000..0bc109b6e1 --- /dev/null +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -0,0 +1,95 @@ +/*************************************************************************/ +/* gdscript_lambda_callable.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 "gdscript_lambda_callable.h" + +#include "core/templates/hashfuncs.h" +#include "gdscript.h" + +bool GDScriptLambdaCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + // Lambda callables are only compared by reference. + return p_a == p_b; +} + +bool GDScriptLambdaCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { + // Lambda callables are only compared by reference. + return p_a < p_b; +} + +uint32_t GDScriptLambdaCallable::hash() const { + return h; +} + +String GDScriptLambdaCallable::get_as_text() const { + if (function->get_name() != StringName()) { + return function->get_name().operator String() + "(lambda)"; + } + return "(anonymous lambda)"; +} + +CallableCustom::CompareEqualFunc GDScriptLambdaCallable::get_compare_equal_func() const { + return compare_equal; +} + +CallableCustom::CompareLessFunc GDScriptLambdaCallable::get_compare_less_func() const { + return compare_less; +} + +ObjectID GDScriptLambdaCallable::get_object() const { + return script->get_instance_id(); +} + +void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + int captures_amount = captures.size(); + + if (captures_amount > 0) { + Vector<const Variant *> args; + args.resize(p_argcount + captures_amount); + for (int i = 0; i < captures_amount; i++) { + args.write[i] = &captures[i]; + } + for (int i = 0; i < p_argcount; i++) { + args.write[i + captures_amount] = p_arguments[i]; + } + + r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error); + r_call_error.argument -= captures_amount; + } else { + r_return_value = function->call(nullptr, p_arguments, p_argcount, r_call_error); + } +} + +GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) { + script = p_script; + function = p_function; + captures = p_captures; + + h = (uint32_t)hash_djb2_one_64((uint64_t)this); +} diff --git a/modules/etc/texture_loader_pkm.h b/modules/gdscript/gdscript_lambda_callable.h index 2ed5e75807..336778d549 100644 --- a/modules/etc/texture_loader_pkm.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* texture_loader_pkm.h */ +/* gdscript_lambda_callable.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,38 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEXTURE_LOADER_PKM_H -#define TEXTURE_LOADER_PKM_H +#ifndef GDSCRIPT_LAMBDA_CALLABLE +#define GDSCRIPT_LAMBDA_CALLABLE -#include "core/io/resource_loader.h" -#include "scene/resources/texture.h" +#include "core/object/ref_counted.h" +#include "core/templates/vector.h" +#include "core/variant/callable.h" +#include "core/variant/variant.h" + +class GDScript; +class GDScriptFunction; +class GDScriptInstance; + +class GDScriptLambdaCallable : public CallableCustom { + GDScriptFunction *function = nullptr; + Ref<GDScript> script; + uint32_t h; + + Vector<Variant> captures; + + static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); + static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b); -class ResourceFormatPKM : 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; + uint32_t hash() const override; + String get_as_text() const override; + CompareEqualFunc get_compare_equal_func() const override; + CompareLessFunc get_compare_less_func() const override; + ObjectID get_object() const override; + void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; - virtual ~ResourceFormatPKM() {} + GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures); + virtual ~GDScriptLambdaCallable() = default; }; -#endif // TEXTURE_LOADER_PKM_H +#endif // GDSCRIPT_LAMBDA_CALLABLE diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 7f3dd6b2e5..1a22820c63 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -31,9 +31,9 @@ #include "gdscript_parser.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/math/math_defs.h" -#include "core/os/file_access.h" #include "gdscript.h" #ifdef DEBUG_ENABLED @@ -61,9 +61,9 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { builtin_types["Vector3i"] = Variant::VECTOR3I; builtin_types["AABB"] = Variant::AABB; builtin_types["Plane"] = Variant::PLANE; - builtin_types["Quat"] = Variant::QUAT; + builtin_types["Quaternion"] = Variant::QUATERNION; builtin_types["Basis"] = Variant::BASIS; - builtin_types["Transform"] = Variant::TRANSFORM; + builtin_types["Transform3D"] = Variant::TRANSFORM3D; builtin_types["Color"] = Variant::COLOR; builtin_types["RID"] = Variant::RID; builtin_types["Object"] = Variant::OBJECT; @@ -94,8 +94,43 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { return Variant::VARIANT_MAX; } +// TODO: Move this to a central location (maybe core?). +static HashMap<StringName, StringName> underscore_map; +static const char *underscore_classes[] = { + "ClassDB", + "Directory", + "Engine", + "File", + "Geometry", + "GodotSharp", + "JSON", + "Marshalls", + "Mutex", + "OS", + "ResourceLoader", + "ResourceSaver", + "Semaphore", + "Thread", + "VisualScriptEditor", + nullptr, +}; +StringName GDScriptParser::get_real_class_name(const StringName &p_source) { + if (underscore_map.is_empty()) { + const char **class_name = underscore_classes; + while (*class_name != nullptr) { + underscore_map[*class_name] = String("_") + *class_name; + class_name++; + } + } + if (underscore_map.has(p_source)) { + return underscore_map[p_source]; + } + return p_source; +} + void GDScriptParser::cleanup() { builtin_types.clear(); + underscore_map.clear(); } void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const { @@ -109,12 +144,11 @@ void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const GDScriptParser::GDScriptParser() { // Register valid annotations. // TODO: Should this be static? - // TODO: Validate applicable types (e.g. a VARIABLE annotation that only applies to string variables). register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation); register_annotation(MethodInfo("@icon", { Variant::STRING, "icon_path" }), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation); register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation); // Export annotations. - register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_TYPE_STRING, Variant::NIL>); + register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); register_annotation(MethodInfo("@export_enum", { Variant::STRING, "names" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, 0, true); register_annotation(MethodInfo("@export_file", { Variant::STRING, "filter" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, 1, true); register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>); @@ -123,7 +157,6 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, 3); - register_annotation(MethodInfo("@export_exp_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_RANGE, Variant::FLOAT>, 3); register_annotation(MethodInfo("@export_exp_easing", { Variant::STRING, "hint1" }, { Variant::STRING, "hint2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, 2); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); register_annotation(MethodInfo("@export_node_path", { Variant::STRING, "type" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, 1, true); @@ -368,6 +401,8 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_ } GDScriptTokenizer::Token GDScriptParser::advance() { + lambda_ended = false; // Empty marker since we're past the end in any case. + if (current.type == GDScriptTokenizer::Token::TK_EOF) { ERR_FAIL_COND_V_MSG(current.type == GDScriptTokenizer::Token::TK_EOF, current, "GDScript parser bug: Trying to advance past the end of stream."); } @@ -394,7 +429,7 @@ bool GDScriptParser::match(GDScriptTokenizer::Token::Type p_token_type) { return true; } -bool GDScriptParser::check(GDScriptTokenizer::Token::Type p_token_type) { +bool GDScriptParser::check(GDScriptTokenizer::Token::Type p_token_type) const { if (p_token_type == GDScriptTokenizer::Token::IDENTIFIER) { return current.is_identifier(); } @@ -409,7 +444,7 @@ bool GDScriptParser::consume(GDScriptTokenizer::Token::Type p_token_type, const return false; } -bool GDScriptParser::is_at_end() { +bool GDScriptParser::is_at_end() const { return check(GDScriptTokenizer::Token::TK_EOF); } @@ -460,16 +495,34 @@ void GDScriptParser::pop_multiline() { tokenizer.set_multiline_mode(multiline_stack.size() > 0 ? multiline_stack.back()->get() : false); } -bool GDScriptParser::is_statement_end() { +bool GDScriptParser::is_statement_end_token() const { return check(GDScriptTokenizer::Token::NEWLINE) || check(GDScriptTokenizer::Token::SEMICOLON) || check(GDScriptTokenizer::Token::TK_EOF); } +bool GDScriptParser::is_statement_end() const { + return lambda_ended || in_lambda || is_statement_end_token(); +} + void GDScriptParser::end_statement(const String &p_context) { bool found = false; while (is_statement_end() && !is_at_end()) { // Remove sequential newlines/semicolons. + if (is_statement_end_token()) { + // Only consume if this is an actual token. + advance(); + } else if (lambda_ended) { + lambda_ended = false; // Consume this "token". + found = true; + break; + } else { + if (!found) { + lambda_ended = true; // Mark the lambda as done since we found something else to end the statement. + found = true; + } + break; + } + found = true; - advance(); } if (!found && !is_at_end()) { push_error(vformat(R"(Expected end of statement after %s, found "%s" instead.)", p_context, current.get_name())); @@ -680,7 +733,6 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() while (!annotation_stack.is_empty()) { AnnotationNode *last_annotation = annotation_stack.back()->get(); if (last_annotation->applies_to(p_target)) { - last_annotation->apply(this, member); member->annotations.push_front(last_annotation); annotation_stack.pop_back(); } else { @@ -778,6 +830,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper VariableNode *variable = alloc_node<VariableNode>(); variable->identifier = parse_identifier(); + variable->export_info.name = variable->identifier->name; if (match(GDScriptTokenizer::Token::COLON)) { if (check(GDScriptTokenizer::Token::NEWLINE)) { @@ -811,6 +864,9 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper if (match(GDScriptTokenizer::Token::EQUAL)) { // Initializer. variable->initializer = parse_expression(false); + if (variable->initializer == nullptr) { + push_error(R"(Expected expression for variable initial value after "=".)"); + } variable->assignments++; } @@ -824,8 +880,6 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper end_statement("variable declaration"); - variable->export_info.name = variable->identifier->name; - return variable; } @@ -1118,7 +1172,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() { consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" for enum.)"); #ifdef TOOLS_ENABLED - // Enum values documentaion. + // Enum values documentation. for (int i = 0; i < enum_node->values.size(); i++) { if (i == enum_node->values.size() - 1) { // If close bracket is same line as last value. @@ -1147,36 +1201,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() { return enum_node; } -GDScriptParser::FunctionNode *GDScriptParser::parse_function() { - bool _static = false; - if (previous.type == GDScriptTokenizer::Token::STATIC) { - // TODO: Improve message if user uses "static" with "var" or "const" - if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) { - return nullptr; - } - _static = true; - } - - FunctionNode *function = alloc_node<FunctionNode>(); - make_completion_context(COMPLETION_OVERRIDE_METHOD, function); - - if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) { - return nullptr; - } - - FunctionNode *previous_function = current_function; - current_function = function; - - function->identifier = parse_identifier(); - function->is_static = _static; - - push_multiline(true); - consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)"); - - SuiteNode *body = alloc_node<SuiteNode>(); - SuiteNode *previous_suite = current_suite; - current_suite = body; - +void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type) { if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) { bool default_used = false; do { @@ -1196,29 +1221,61 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function() { continue; } } - if (function->parameters_indices.has(parameter->identifier->name)) { - push_error(vformat(R"(Parameter with name "%s" was already declared for this function.)", parameter->identifier->name)); + if (p_function->parameters_indices.has(parameter->identifier->name)) { + push_error(vformat(R"(Parameter with name "%s" was already declared for this %s.)", parameter->identifier->name, p_type)); } else { - function->parameters_indices[parameter->identifier->name] = function->parameters.size(); - function->parameters.push_back(parameter); - body->add_local(parameter); + p_function->parameters_indices[parameter->identifier->name] = p_function->parameters.size(); + p_function->parameters.push_back(parameter); + p_body->add_local(parameter, current_function); } } while (match(GDScriptTokenizer::Token::COMMA)); } pop_multiline(); - consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after function parameters.)*"); + consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, vformat(R"*(Expected closing ")" after %s parameters.)*", p_type)); if (match(GDScriptTokenizer::Token::FORWARD_ARROW)) { - make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, function); - function->return_type = parse_type(true); - if (function->return_type == nullptr) { + make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, p_function); + p_function->return_type = parse_type(true); + if (p_function->return_type == nullptr) { push_error(R"(Expected return type or "void" after "->".)"); } } // TODO: Improve token consumption so it synchronizes to a statement boundary. This way we can get into the function body with unrecognized tokens. - consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after function declaration.)"); + consume(GDScriptTokenizer::Token::COLON, vformat(R"(Expected ":" after %s declaration.)", p_type)); +} + +GDScriptParser::FunctionNode *GDScriptParser::parse_function() { + bool _static = false; + if (previous.type == GDScriptTokenizer::Token::STATIC) { + // TODO: Improve message if user uses "static" with "var" or "const" + if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) { + return nullptr; + } + _static = true; + } + + FunctionNode *function = alloc_node<FunctionNode>(); + make_completion_context(COMPLETION_OVERRIDE_METHOD, function); + + if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) { + return nullptr; + } + + FunctionNode *previous_function = current_function; + current_function = function; + + function->identifier = parse_identifier(); + function->is_static = _static; + + SuiteNode *body = alloc_node<SuiteNode>(); + SuiteNode *previous_suite = current_suite; + current_suite = body; + + push_multiline(true); + consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)"); + parse_function_signature(function, body, "function"); current_suite = previous_suite; function->body = parse_suite("function declaration", body); @@ -1304,29 +1361,34 @@ bool GDScriptParser::register_annotation(const MethodInfo &p_info, uint32_t p_ta return true; } -GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite) { +GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite, bool p_for_lambda) { SuiteNode *suite = p_suite != nullptr ? p_suite : alloc_node<SuiteNode>(); suite->parent_block = current_suite; + suite->parent_function = current_function; current_suite = suite; bool multiline = false; - if (check(GDScriptTokenizer::Token::NEWLINE)) { + if (match(GDScriptTokenizer::Token::NEWLINE)) { multiline = true; } if (multiline) { - consume(GDScriptTokenizer::Token::NEWLINE, vformat(R"(Expected newline after %s.)", p_context)); - if (!consume(GDScriptTokenizer::Token::INDENT, vformat(R"(Expected indented block after %s.)", p_context))) { current_suite = suite->parent_block; return suite; } } + int error_count = 0; + do { Node *statement = parse_statement(); if (statement == nullptr) { + if (error_count++ > 100) { + push_error("Too many statement errors.", suite); + break; + } continue; } suite->statements.push_back(statement); @@ -1339,7 +1401,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, if (local.type != SuiteNode::Local::UNDEFINED) { push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", local.get_name(), variable->identifier->name)); } - current_suite->add_local(variable); + current_suite->add_local(variable, current_function); break; } case Node::CONSTANT: { @@ -1354,19 +1416,29 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, } push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", name, constant->identifier->name)); } - current_suite->add_local(constant); + current_suite->add_local(constant, current_function); break; } default: break; } - } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !is_at_end()); + } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end()); if (multiline) { - consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context)); + if (!lambda_ended) { + consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context)); + + } else { + match(GDScriptTokenizer::Token::DEDENT); + } + } else if (previous.type == GDScriptTokenizer::Token::SEMICOLON) { + consume(GDScriptTokenizer::Token::NEWLINE, vformat(R"(Expected newline after ";" at the end of %s.)", p_context)); } + if (p_for_lambda) { + lambda_ended = true; + } current_suite = suite->parent_block; return suite; } @@ -1423,6 +1495,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { push_error(R"(Constructor cannot return a value.)"); } n_return->return_value = parse_expression(false); + } else if (in_lambda && !is_statement_end_token()) { + // Try to parse it anyway as this might not be the statement end in a lambda. + // If this fails the expression will be nullptr, but that's the same as no return, so it's fine. + n_return->return_value = parse_expression(false); } result = n_return; @@ -1451,10 +1527,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { default: { // Expression statement. ExpressionNode *expression = parse_expression(true); // Allow assignment here. + bool has_ended_lambda = false; if (expression == nullptr) { - push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name())); + if (in_lambda) { + // If it's not a valid expression beginning, it might be the continuation of the outer expression where this lambda is. + lambda_ended = true; + has_ended_lambda = true; + } else { + push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name())); + } } end_statement("expression"); + lambda_ended = lambda_ended || has_ended_lambda; result = expression; #ifdef DEBUG_ENABLED @@ -1478,7 +1562,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { if (unreachable && result != nullptr) { current_suite->has_unreachable_code = true; if (current_function) { - push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name); + push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier ? current_function->identifier->name : "<anonymous lambda>"); } else { // TODO: Properties setters and getters with unreachable code are not being warned } @@ -1563,7 +1647,7 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() { SuiteNode *suite = alloc_node<SuiteNode>(); if (n_for->variable) { - suite->add_local(SuiteNode::Local(n_for->variable)); + suite->add_local(SuiteNode::Local(n_for->variable, current_function)); } suite->parent_for = n_for; @@ -1718,7 +1802,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { branch->patterns[0]->binds.get_key_list(&binds); for (List<StringName>::Element *E = binds.front(); E != nullptr; E = E->next()) { - SuiteNode::Local local(branch->patterns[0]->binds[E->get()]); + SuiteNode::Local local(branch->patterns[0]->binds[E->get()], current_function); suite->add_local(local); } } @@ -1918,7 +2002,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr // Completion can appear whenever an expression is expected. make_completion_context(COMPLETION_IDENTIFIER, nullptr); - GDScriptTokenizer::Token token = advance(); + GDScriptTokenizer::Token token = current; ParseFunction prefix_rule = get_rule(token.type)->prefix; if (prefix_rule == nullptr) { @@ -1926,6 +2010,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr return nullptr; } + advance(); // Only consume the token if there's a valid rule. + ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign); while (p_precedence <= get_rule(current.type)->precedence) { @@ -1967,6 +2053,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode if (current_suite != nullptr && current_suite->has_local(identifier->name)) { const SuiteNode::Local &declaration = current_suite->get_local(identifier->name); + + identifier->source_function = declaration.source_function; switch (declaration.type) { case SuiteNode::Local::CONSTANT: identifier->source = IdentifierNode::LOCAL_CONSTANT; @@ -2020,6 +2108,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre if (current_function && current_function->is_static) { push_error(R"(Cannot use "self" inside a static function.)"); } + if (in_lambda) { + push_error(R"(Cannot use "self" inside a lambda.)"); + } SelfNode *self = alloc_node<SelfNode>(); self->current_class = current_class; return self; @@ -2405,6 +2496,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode push_error(R"(Expected "=" after dictionary key.)"); } } + key->is_constant = true; + key->reduced_value = static_cast<IdentifierNode *>(key)->name; break; case DictionaryNode::PYTHON_DICT: if (!match(GDScriptTokenizer::Token::COLON)) { @@ -2451,7 +2544,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode * if (for_completion) { bool is_builtin = false; - if (p_previous_operand->type == Node::IDENTIFIER) { + if (p_previous_operand && p_previous_operand->type == Node::IDENTIFIER) { const IdentifierNode *id = static_cast<const IdentifierNode *>(p_previous_operand); Variant::Type builtin_type = get_builtin_type(id->name); if (builtin_type < Variant::VARIANT_MAX) { @@ -2638,6 +2731,65 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_ return preload; } +GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign) { + LambdaNode *lambda = alloc_node<LambdaNode>(); + lambda->parent_function = current_function; + FunctionNode *function = alloc_node<FunctionNode>(); + function->source_lambda = lambda; + + function->is_static = current_function != nullptr ? current_function->is_static : false; + + if (match(GDScriptTokenizer::Token::IDENTIFIER)) { + function->identifier = parse_identifier(); + } + + bool multiline_context = multiline_stack.back()->get(); + + // Reset the multiline stack since we don't want the multiline mode one in the lambda body. + push_multiline(false); + if (multiline_context) { + tokenizer.push_expression_indented_block(); + } + + push_multiline(true); // For the parameters. + if (function->identifier) { + consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after lambda name.)"); + } else { + consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after "func".)"); + } + + FunctionNode *previous_function = current_function; + current_function = function; + + SuiteNode *body = alloc_node<SuiteNode>(); + SuiteNode *previous_suite = current_suite; + current_suite = body; + + parse_function_signature(function, body, "lambda"); + + current_suite = previous_suite; + + bool previous_in_lambda = in_lambda; + in_lambda = true; + + function->body = parse_suite("lambda declaration", body, true); + + pop_multiline(); + + if (multiline_context) { + // If we're in multiline mode, we want to skip the spurious DEDENT and NEWLINE tokens. + while (check(GDScriptTokenizer::Token::DEDENT) || check(GDScriptTokenizer::Token::INDENT) || check(GDScriptTokenizer::Token::NEWLINE)) { + current = tokenizer.scan(); // Not advance() since we don't want to change the previous token. + } + tokenizer.pop_expression_indented_block(); + } + + current_function = previous_function; + in_lambda = previous_in_lambda; + lambda->function = function; + return lambda; +} + GDScriptParser::ExpressionNode *GDScriptParser::parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign) { // Just for better error messages. GDScriptTokenizer::Token::Type invalid = previous.type; @@ -2674,6 +2826,19 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) { type->type_chain.push_back(type_element); + if (match(GDScriptTokenizer::Token::BRACKET_OPEN)) { + // Typed collection (like Array[int]). + type->container_type = parse_type(false); // Don't allow void for array element type. + if (type->container_type == nullptr) { + push_error(R"(Expected type for collection after "[".)"); + type = nullptr; + } else if (type->container_type->container_type != nullptr) { + push_error("Nested typed collections are not supported."); + } + consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after collection type.)"); + return type; + } + int chain_index = 1; while (match(GDScriptTokenizer::Token::PERIOD)) { make_completion_context(COMPLETION_TYPE_ATTRIBUTE, type, chain_index++); @@ -2969,7 +3134,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty { nullptr, nullptr, PREC_NONE }, // CONST, { nullptr, nullptr, PREC_NONE }, // ENUM, { nullptr, nullptr, PREC_NONE }, // EXTENDS, - { nullptr, nullptr, PREC_NONE }, // FUNC, + { &GDScriptParser::parse_lambda, nullptr, PREC_NONE }, // FUNC, { nullptr, &GDScriptParser::parse_binary_operator, PREC_CONTENT_TEST }, // IN, { nullptr, &GDScriptParser::parse_binary_operator, PREC_TYPE_TEST }, // IS, { nullptr, nullptr, PREC_NONE }, // NAMESPACE, @@ -3160,29 +3325,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } variable->exported = true; - // TODO: Improving setting type, especially for range hints, which can be int or float. + variable->export_info.type = t_type; variable->export_info.hint = t_hint; - if (p_annotation->name == "@export") { - if (variable->datatype_specifier == nullptr) { - if (variable->initializer == nullptr) { - push_error(R"(Cannot use "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation); - return false; - } - if (variable->initializer->type == Node::LITERAL) { - variable->export_info.type = static_cast<LiteralNode *>(variable->initializer)->value.get_type(); - } else if (variable->initializer->type == Node::ARRAY) { - variable->export_info.type = Variant::ARRAY; - } else if (variable->initializer->type == Node::DICTIONARY) { - variable->export_info.type = Variant::DICTIONARY; - } else { - push_error(R"(To use "@export" annotation with type-less variable, the default value must be a literal.)", p_annotation); - return false; - } - } // else: Actual type will be set by the analyzer, which can infer the proper type. - } - String hint_string; for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) { if (i > 0) { @@ -3193,6 +3339,86 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint_string = hint_string; + // This is called after tne analyzer is done finding the type, so this should be set here. + DataType export_type = variable->get_datatype(); + + if (p_annotation->name == "@export") { + if (variable->datatype_specifier == nullptr && variable->initializer == nullptr) { + push_error(R"(Cannot use simple "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation); + return false; + } + + bool is_array = false; + + if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) { + export_type = export_type.get_container_element_type(); // Use inner type for. + is_array = true; + } + + if (export_type.is_variant() || export_type.has_no_type()) { + push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation); + return false; + } + + switch (export_type.kind) { + case GDScriptParser::DataType::BUILTIN: + variable->export_info.type = export_type.builtin_type; + variable->export_info.hint = PROPERTY_HINT_NONE; + variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type); + break; + case GDScriptParser::DataType::NATIVE: + if (ClassDB::is_parent_class(get_real_class_name(export_type.native_type), "Resource")) { + variable->export_info.type = Variant::OBJECT; + variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; + variable->export_info.hint_string = get_real_class_name(export_type.native_type); + } else { + push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable); + return false; + } + break; + case GDScriptParser::DataType::ENUM: { + variable->export_info.type = Variant::INT; + variable->export_info.hint = PROPERTY_HINT_ENUM; + + 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 += ":"; + enum_hint_string += String::num_int64(E->get()).xml_escape(); + + if (E->next()) { + enum_hint_string += ","; + } + } + + variable->export_info.hint_string = enum_hint_string; + } break; + default: + // TODO: Allow custom user resources. + push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable); + break; + } + + if (is_array) { + String hint_prefix = itos(variable->export_info.type); + if (variable->export_info.hint) { + hint_prefix += "/" + itos(variable->export_info.hint); + } + variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; + variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; + variable->export_info.type = Variant::ARRAY; + } + } else { + // Validate variable type with export. + if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) { + // Allow float/int conversion. + if ((t_type != Variant::FLOAT || export_type.builtin_type != Variant::INT) && (t_type != Variant::INT || export_type.builtin_type != Variant::FLOAT)) { + push_error(vformat(R"("%s" annotation requires a variable of type "%s" but type "%s" was given instead.)", p_annotation->name.operator String(), Variant::get_type_name(t_type), export_type.to_string()), variable); + return false; + } + } + } + return true; } @@ -3278,6 +3504,9 @@ String GDScriptParser::DataType::to_string() const { if (builtin_type == Variant::NIL) { return "null"; } + if (builtin_type == Variant::ARRAY && has_container_element_type()) { + return vformat("Array[%s]", container_element_type->to_string()); + } return Variant::get_type_name(builtin_type); case NATIVE: if (is_meta_type) { @@ -3641,6 +3870,10 @@ void GDScriptParser::TreePrinter::print_dictionary(DictionaryNode *p_dictionary) } void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression) { + if (p_expression == nullptr) { + push_text("<invalid expression>"); + return; + } switch (p_expression->type) { case Node::ARRAY: print_array(static_cast<ArrayNode *>(p_expression)); @@ -3669,6 +3902,9 @@ void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression) case Node::IDENTIFIER: print_identifier(static_cast<IdentifierNode *>(p_expression)); break; + case Node::LAMBDA: + print_lambda(static_cast<LambdaNode *>(p_expression)); + break; case Node::LITERAL: print_literal(static_cast<LiteralNode *>(p_expression)); break; @@ -3728,12 +3964,17 @@ void GDScriptParser::TreePrinter::print_for(ForNode *p_for) { decrease_indent(); } -void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function) { +void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const String &p_context) { for (const List<AnnotationNode *>::Element *E = p_function->annotations.front(); E != nullptr; E = E->next()) { print_annotation(E->get()); } - push_text("Function "); - print_identifier(p_function->identifier); + push_text(p_context); + push_text(" "); + if (p_function->identifier) { + print_identifier(p_function->identifier); + } else { + push_text("<anonymous>"); + } push_text("( "); for (int i = 0; i < p_function->parameters.size(); i++) { if (i > 0) { @@ -3787,6 +4028,18 @@ void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) { } } +void GDScriptParser::TreePrinter::print_lambda(LambdaNode *p_lambda) { + print_function(p_lambda->function, "Lambda"); + push_text("| captures [ "); + for (int i = 0; i < p_lambda->captures.size(); i++) { + if (i > 0) { + push_text(" , "); + } + push_text(p_lambda->captures[i]->name.operator String()); + } + push_line(" ]"); +} + void GDScriptParser::TreePrinter::print_literal(LiteralNode *p_literal) { // Prefix for string types. switch (p_literal->value.get_type()) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index a4b1d4c866..9e0b60a407 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -33,7 +33,7 @@ #include "core/io/multiplayer_api.h" #include "core/io/resource.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" #include "core/string/string_name.h" #include "core/string/ustring.h" @@ -76,6 +76,7 @@ public: struct GetNodeNode; struct IdentifierNode; struct IfNode; + struct LambdaNode; struct LiteralNode; struct MatchNode; struct MatchBranchNode; @@ -94,7 +95,12 @@ public: struct VariableNode; struct WhileNode; - struct DataType { + class DataType { + private: + // Private access so we can control memory management. + DataType *container_element_type = nullptr; + + public: enum Kind { BUILTIN, NATIVE, @@ -104,7 +110,6 @@ public: ENUM_VALUE, // Value from enumeration. VARIANT, // Can be any type. UNRESOLVED, - // TODO: Enum }; Kind kind = UNRESOLVED; @@ -128,7 +133,7 @@ public: ClassNode *class_type = nullptr; MethodInfo method_info; // For callable/signals. - HashMap<StringName, int> enum_values; // For enums. + Map<StringName, int> enum_values; // For enums. _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; } _FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; } @@ -136,6 +141,26 @@ public: _FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; } String to_string() const; + _FORCE_INLINE_ void set_container_element_type(const DataType &p_type) { + container_element_type = memnew(DataType(p_type)); + } + + _FORCE_INLINE_ DataType get_container_element_type() const { + ERR_FAIL_COND_V(container_element_type == nullptr, DataType()); + return *container_element_type; + } + + _FORCE_INLINE_ bool has_container_element_type() const { + return container_element_type != nullptr; + } + + _FORCE_INLINE_ void unset_container_element_type() { + if (container_element_type) { + memdelete(container_element_type); + }; + container_element_type = nullptr; + } + bool operator==(const DataType &p_other) const { if (type_source == UNDETECTED || p_other.type_source == UNDETECTED) { return true; // Can be consireded equal for parsing purposes. @@ -173,6 +198,37 @@ public: bool operator!=(const DataType &p_other) const { return !(this->operator==(p_other)); } + + DataType &operator=(const DataType &p_other) { + kind = p_other.kind; + type_source = p_other.type_source; + is_constant = p_other.is_constant; + is_meta_type = p_other.is_meta_type; + is_coroutine = p_other.is_coroutine; + builtin_type = p_other.builtin_type; + native_type = p_other.native_type; + enum_type = p_other.enum_type; + script_type = p_other.script_type; + script_path = p_other.script_path; + class_type = p_other.class_type; + method_info = p_other.method_info; + enum_values = p_other.enum_values; + unset_container_element_type(); + if (p_other.has_container_element_type()) { + set_container_element_type(p_other.get_container_element_type()); + } + return *this; + } + + DataType() = default; + + DataType(const DataType &p_other) { + *this = p_other; + } + + ~DataType() { + unset_container_element_type(); + } }; struct ParserError { @@ -212,6 +268,7 @@ public: GET_NODE, IDENTIFIER, IF, + LAMBDA, LITERAL, MATCH, MATCH_BRANCH, @@ -313,6 +370,7 @@ public: Variant::Operator variant_op = Variant::OP_MAX; ExpressionNode *assignee = nullptr; ExpressionNode *assigned_value = nullptr; + bool use_conversion_assign = false; AssignmentNode() { type = ASSIGNMENT; @@ -673,6 +731,7 @@ public: bool is_coroutine = false; MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; MethodInfo info; + LambdaNode *source_lambda = nullptr; #ifdef TOOLS_ENABLED Vector<Variant> default_arg_values; String doc_description; @@ -716,6 +775,7 @@ public: VariableNode *variable_source; IdentifierNode *bind_source; }; + FunctionNode *source_function = nullptr; int usages = 0; // Useful for binds/iterator variable. @@ -734,6 +794,21 @@ public: } }; + struct LambdaNode : public ExpressionNode { + FunctionNode *function = nullptr; + FunctionNode *parent_function = nullptr; + Vector<IdentifierNode *> captures; + Map<StringName, int> captures_indices; + + bool has_name() const { + return function && function->identifier; + } + + LambdaNode() { + type = LAMBDA; + } + }; + struct LiteralNode : public ExpressionNode { Variant value; @@ -887,6 +962,7 @@ public: IdentifierNode *bind; }; StringName name; + FunctionNode *source_function = nullptr; int start_line = 0, end_line = 0; int start_column = 0, end_column = 0; @@ -896,10 +972,11 @@ public: String get_name() const; Local() {} - Local(ConstantNode *p_constant) { + Local(ConstantNode *p_constant, FunctionNode *p_source_function) { type = CONSTANT; constant = p_constant; name = p_constant->identifier->name; + source_function = p_source_function; start_line = p_constant->start_line; end_line = p_constant->end_line; @@ -908,10 +985,11 @@ public: leftmost_column = p_constant->leftmost_column; rightmost_column = p_constant->rightmost_column; } - Local(VariableNode *p_variable) { + Local(VariableNode *p_variable, FunctionNode *p_source_function) { type = VARIABLE; variable = p_variable; name = p_variable->identifier->name; + source_function = p_source_function; start_line = p_variable->start_line; end_line = p_variable->end_line; @@ -920,10 +998,11 @@ public: leftmost_column = p_variable->leftmost_column; rightmost_column = p_variable->rightmost_column; } - Local(ParameterNode *p_parameter) { + Local(ParameterNode *p_parameter, FunctionNode *p_source_function) { type = PARAMETER; parameter = p_parameter; name = p_parameter->identifier->name; + source_function = p_source_function; start_line = p_parameter->start_line; end_line = p_parameter->end_line; @@ -932,10 +1011,11 @@ public: leftmost_column = p_parameter->leftmost_column; rightmost_column = p_parameter->rightmost_column; } - Local(IdentifierNode *p_identifier) { + Local(IdentifierNode *p_identifier, FunctionNode *p_source_function) { type = FOR_VARIABLE; bind = p_identifier; name = p_identifier->name; + source_function = p_source_function; start_line = p_identifier->start_line; end_line = p_identifier->end_line; @@ -960,9 +1040,9 @@ public: bool has_local(const StringName &p_name) const; const Local &get_local(const StringName &p_name) const; template <class T> - void add_local(T *p_local) { + void add_local(T *p_local, FunctionNode *p_source_function) { locals_indices[p_local->identifier->name] = locals.size(); - locals.push_back(Local(p_local)); + locals.push_back(Local(p_local, p_source_function)); } void add_local(const Local &p_local) { locals_indices[p_local.name] = locals.size(); @@ -987,6 +1067,7 @@ public: struct TypeNode : public Node { Vector<IdentifierNode *> type_chain; + TypeNode *container_type = nullptr; TypeNode() { type = TYPE; @@ -1039,6 +1120,7 @@ public: MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; int assignments = 0; int usages = 0; + bool use_conversion_assign = false; #ifdef TOOLS_ENABLED String doc_description; #endif // TOOLS_ENABLED @@ -1135,6 +1217,8 @@ private: CompletionCall completion_call; List<CompletionCall> completion_call_stack; bool passed_cursor = false; + bool in_lambda = false; + bool lambda_ended = false; // Marker for when a lambda ends, to apply an end of statement if needed. typedef bool (GDScriptParser::*AnnotationAction)(const AnnotationNode *p_annotation, Node *p_target); struct AnnotationInfo { @@ -1222,10 +1306,11 @@ private: GDScriptTokenizer::Token advance(); bool match(GDScriptTokenizer::Token::Type p_token_type); - bool check(GDScriptTokenizer::Token::Type p_token_type); + bool check(GDScriptTokenizer::Token::Type p_token_type) const; bool consume(GDScriptTokenizer::Token::Type p_token_type, const String &p_error_message); - bool is_at_end(); - bool is_statement_end(); + bool is_at_end() const; + bool is_statement_end_token() const; + bool is_statement_end() const; void end_statement(const String &p_context); void synchronize(); void push_multiline(bool p_state); @@ -1243,7 +1328,8 @@ private: EnumNode *parse_enum(); ParameterNode *parse_parameter(); FunctionNode *parse_function(); - SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr); + void parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type); + SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false); // Annotations AnnotationNode *parse_annotation(uint32_t p_valid_targets); bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, int p_optional_arguments = 0, bool p_is_vararg = false); @@ -1298,6 +1384,7 @@ private: ExpressionNode *parse_await(ExpressionNode *p_previous_operand, bool p_can_assign); ExpressionNode *parse_attribute(ExpressionNode *p_previous_operand, bool p_can_assign); ExpressionNode *parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign); + ExpressionNode *parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign); ExpressionNode *parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign); TypeNode *parse_type(bool p_allow_void = false); #ifdef TOOLS_ENABLED @@ -1313,6 +1400,7 @@ public: ClassNode *get_tree() const { return head; } bool is_tool() const { return _is_tool; } static Variant::Type get_builtin_type(const StringName &p_type); + static StringName get_real_class_name(const StringName &p_source); CompletionContext get_completion_context() const { return completion_context; } CompletionCall get_completion_call() const { return completion_call; } @@ -1358,10 +1446,11 @@ public: void print_expression(ExpressionNode *p_expression); void print_enum(EnumNode *p_enum); void print_for(ForNode *p_for); - void print_function(FunctionNode *p_function); + void print_function(FunctionNode *p_function, const String &p_context = "Function"); void print_get_node(GetNodeNode *p_get_node); void print_if(IfNode *p_if, bool p_is_elif = false); void print_identifier(IdentifierNode *p_identifier); + void print_lambda(LambdaNode *p_lambda); void print_literal(LiteralNode *p_literal); void print_match(MatchNode *p_match); void print_match_branch(MatchBranchNode *p_match_branch); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index e432dfc891..3f14156dfa 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -242,6 +242,16 @@ void GDScriptTokenizer::set_multiline_mode(bool p_state) { multiline_mode = p_state; } +void GDScriptTokenizer::push_expression_indented_block() { + indent_stack_stack.push_back(indent_stack); +} + +void GDScriptTokenizer::pop_expression_indented_block() { + ERR_FAIL_COND(indent_stack_stack.size() == 0); + indent_stack = indent_stack_stack.back()->get(); + indent_stack_stack.pop_back(); +} + int GDScriptTokenizer::get_cursor_line() const { return cursor_line; } @@ -633,6 +643,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { push_error(error); } previous_was_underscore = true; + } else { + previous_was_underscore = false; } _advance(); } @@ -704,6 +716,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { push_error(error); } previous_was_underscore = true; + } else { + previous_was_underscore = false; } _advance(); } diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index bea4b14019..84b82c07f0 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -217,6 +217,7 @@ private: Token last_newline; int pending_indents = 0; List<int> indent_stack; + List<List<int>> indent_stack_stack; // For lambdas, which require manipulating the indentation point. List<char32_t> paren_stack; char32_t indent_char = '\0'; int position = 0; @@ -263,6 +264,8 @@ public: void set_multiline_mode(bool p_state); bool is_past_cursor() const; static String get_token_name(Token::Type p_token_type); + void push_expression_indented_block(); // For lambdas, or blocks inside expressions. + void pop_expression_indented_block(); // For lambdas, or blocks inside expressions. GDScriptTokenizer(); }; diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 348d221352..64c629662c 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -298,7 +298,7 @@ struct GDScriptUtilityFunctionsDefinitions { sname.push_back(p->name); p = p->_owner; } - sname.invert(); + sname.reverse(); if (!p->path.is_resource_file()) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 2216fcab2d..8a261a88e3 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -33,23 +33,24 @@ #include "core/core_string_names.h" #include "core/os/os.h" #include "gdscript.h" +#include "gdscript_lambda_callable.h" -Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const { +Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const { int address = p_address & ADDR_MASK; //sequential table (jump table generated by compiler) switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) { - case ADDR_TYPE_SELF: { + case ADDR_TYPE_STACK: { #ifdef DEBUG_ENABLED - if (unlikely(!p_instance)) { - r_error = "Cannot access self without instance."; - return nullptr; - } + ERR_FAIL_INDEX_V(address, _stack_size, nullptr); #endif - return &self; + return &p_stack[address]; } break; - case ADDR_TYPE_CLASS: { - return &static_ref; + case ADDR_TYPE_CONSTANT: { +#ifdef DEBUG_ENABLED + ERR_FAIL_INDEX_V(address, _constant_count, nullptr); +#endif + return &_constants_ptr[address]; } break; case ADDR_TYPE_MEMBER: { #ifdef DEBUG_ENABLED @@ -61,65 +62,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta //member indexing is O(1) return &p_instance->members.write[address]; } break; - case ADDR_TYPE_CLASS_CONSTANT: { - //todo change to index! - GDScript *s = p_script; -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _global_names_count, nullptr); -#endif - const StringName *sn = &_global_names_ptr[address]; - - while (s) { - GDScript *o = s; - while (o) { - Map<StringName, Variant>::Element *E = o->constants.find(*sn); - if (E) { - return &E->get(); - } - o = o->_owner; - } - s = s->_base; - } - - ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug."); - } break; - case ADDR_TYPE_LOCAL_CONSTANT: { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _constant_count, nullptr); -#endif - return &_constants_ptr[address]; - } break; - case ADDR_TYPE_STACK: - case ADDR_TYPE_STACK_VARIABLE: { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _stack_size, nullptr); -#endif - return &p_stack[address]; - } break; - case ADDR_TYPE_GLOBAL: { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr); -#endif - return &GDScriptLanguage::get_singleton()->get_global_array()[address]; - } break; -#ifdef TOOLS_ENABLED - case ADDR_TYPE_NAMED_GLOBAL: { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _global_names_count, nullptr); -#endif - StringName id = _global_names_ptr[address]; - - if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) { - return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id]; - } else { - r_error = "Autoload singleton '" + String(id) + "' has been removed."; - return nullptr; - } - } break; -#endif - case ADDR_TYPE_NIL: { - return &nil; - } break; } ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode)."); @@ -127,6 +69,17 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta } #ifdef DEBUG_ENABLED +static String _get_script_name(const Ref<Script> p_script) { + Ref<GDScript> gdscript = p_script; + if (gdscript.is_valid()) { + return gdscript->get_script_class_name(); + } else if (p_script->get_name().is_empty()) { + return p_script->get_path().get_file(); + } else { + return p_script->get_name(); + } +} + static String _get_var_type(const Variant *p_var) { String basestr; @@ -140,15 +93,30 @@ static String _get_var_type(const Variant *p_var) { basestr = "previously freed"; } } else { + basestr = bobj->get_class(); if (bobj->get_script_instance()) { - basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")"; - } else { - basestr = bobj->get_class(); + basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; } } } else { - basestr = Variant::get_type_name(p_var->get_type()); + if (p_var->get_type() == Variant::ARRAY) { + basestr = "Array"; + const Array *p_array = VariantInternal::get_array(p_var); + Variant::Type builtin_type = (Variant::Type)p_array->get_typed_builtin(); + StringName native_type = p_array->get_typed_class_name(); + Ref<Script> script_type = p_array->get_typed_script(); + + if (script_type.is_valid() && script_type->is_valid()) { + basestr += "[" + _get_script_name(script_type) + "]"; + } else if (native_type != StringName()) { + basestr += "[" + native_type.operator String() + "]"; + } else if (builtin_type != Variant::NIL) { + basestr += "[" + Variant::get_type_name(builtin_type) + "]"; + } + } else { + basestr = Variant::get_type_name(p_var->get_type()); + } } return basestr; @@ -184,6 +152,44 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const return err_text; } +void (*type_init_function_table[])(Variant *) = { + nullptr, // NIL (shouldn't be called). + &VariantInitializer<bool>::init, // BOOL. + &VariantInitializer<int64_t>::init, // INT. + &VariantInitializer<double>::init, // FLOAT. + &VariantInitializer<String>::init, // STRING. + &VariantInitializer<Vector2>::init, // VECTOR2. + &VariantInitializer<Vector2i>::init, // VECTOR2I. + &VariantInitializer<Rect2>::init, // RECT2. + &VariantInitializer<Rect2i>::init, // RECT2I. + &VariantInitializer<Vector3>::init, // VECTOR3. + &VariantInitializer<Vector3i>::init, // VECTOR3I. + &VariantInitializer<Transform2D>::init, // TRANSFORM2D. + &VariantInitializer<Plane>::init, // PLANE. + &VariantInitializer<Quaternion>::init, // QUATERNION. + &VariantInitializer<AABB>::init, // AABB. + &VariantInitializer<Basis>::init, // BASIS. + &VariantInitializer<Transform3D>::init, // TRANSFORM3D. + &VariantInitializer<Color>::init, // COLOR. + &VariantInitializer<StringName>::init, // STRING_NAME. + &VariantInitializer<NodePath>::init, // NODE_PATH. + &VariantInitializer<RID>::init, // RID. + &VariantTypeAdjust<Object *>::adjust, // OBJECT. + &VariantInitializer<Callable>::init, // CALLABLE. + &VariantInitializer<Signal>::init, // SIGNAL. + &VariantInitializer<Dictionary>::init, // DICTIONARY. + &VariantInitializer<Array>::init, // ARRAY. + &VariantInitializer<PackedByteArray>::init, // PACKED_BYTE_ARRAY. + &VariantInitializer<PackedInt32Array>::init, // PACKED_INT32_ARRAY. + &VariantInitializer<PackedInt64Array>::init, // PACKED_INT64_ARRAY. + &VariantInitializer<PackedFloat32Array>::init, // PACKED_FLOAT32_ARRAY. + &VariantInitializer<PackedFloat64Array>::init, // PACKED_FLOAT64_ARRAY. + &VariantInitializer<PackedStringArray>::init, // PACKED_STRING_ARRAY. + &VariantInitializer<PackedVector2Array>::init, // PACKED_VECTOR2_ARRAY. + &VariantInitializer<PackedVector3Array>::init, // PACKED_VECTOR3_ARRAY. + &VariantInitializer<PackedColorArray>::init, // PACKED_COLOR_ARRAY. +}; + #if defined(__GNUC__) #define OPCODES_TABLE \ static const void *switch_table_ops[] = { \ @@ -207,6 +213,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_ASSIGN_TRUE, \ &&OPCODE_ASSIGN_FALSE, \ &&OPCODE_ASSIGN_TYPED_BUILTIN, \ + &&OPCODE_ASSIGN_TYPED_ARRAY, \ &&OPCODE_ASSIGN_TYPED_NATIVE, \ &&OPCODE_ASSIGN_TYPED_SCRIPT, \ &&OPCODE_CAST_TO_BUILTIN, \ @@ -215,6 +222,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_CONSTRUCT, \ &&OPCODE_CONSTRUCT_VALIDATED, \ &&OPCODE_CONSTRUCT_ARRAY, \ + &&OPCODE_CONSTRUCT_TYPED_ARRAY, \ &&OPCODE_CONSTRUCT_DICTIONARY, \ &&OPCODE_CALL, \ &&OPCODE_CALL_RETURN, \ @@ -226,6 +234,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_CALL_SELF_BASE, \ &&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND_RET, \ + &&OPCODE_CALL_BUILTIN_STATIC, \ &&OPCODE_CALL_PTRCALL_NO_RETURN, \ &&OPCODE_CALL_PTRCALL_BOOL, \ &&OPCODE_CALL_PTRCALL_INT, \ @@ -239,10 +248,10 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_CALL_PTRCALL_VECTOR3I, \ &&OPCODE_CALL_PTRCALL_TRANSFORM2D, \ &&OPCODE_CALL_PTRCALL_PLANE, \ - &&OPCODE_CALL_PTRCALL_QUAT, \ + &&OPCODE_CALL_PTRCALL_QUATERNION, \ &&OPCODE_CALL_PTRCALL_AABB, \ &&OPCODE_CALL_PTRCALL_BASIS, \ - &&OPCODE_CALL_PTRCALL_TRANSFORM, \ + &&OPCODE_CALL_PTRCALL_TRANSFORM3D, \ &&OPCODE_CALL_PTRCALL_COLOR, \ &&OPCODE_CALL_PTRCALL_STRING_NAME, \ &&OPCODE_CALL_PTRCALL_NODE_PATH, \ @@ -263,11 +272,16 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \ &&OPCODE_AWAIT, \ &&OPCODE_AWAIT_RESUME, \ + &&OPCODE_CREATE_LAMBDA, \ &&OPCODE_JUMP, \ &&OPCODE_JUMP_IF, \ &&OPCODE_JUMP_IF_NOT, \ &&OPCODE_JUMP_TO_DEF_ARGUMENT, \ &&OPCODE_RETURN, \ + &&OPCODE_RETURN_TYPED_BUILTIN, \ + &&OPCODE_RETURN_TYPED_ARRAY, \ + &&OPCODE_RETURN_TYPED_NATIVE, \ + &&OPCODE_RETURN_TYPED_SCRIPT, \ &&OPCODE_ITERATE_BEGIN, \ &&OPCODE_ITERATE_BEGIN_INT, \ &&OPCODE_ITERATE_BEGIN_FLOAT, \ @@ -308,6 +322,41 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \ &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \ &&OPCODE_ITERATE_OBJECT, \ + &&OPCODE_STORE_NAMED_GLOBAL, \ + &&OPCODE_TYPE_ADJUST_BOOL, \ + &&OPCODE_TYPE_ADJUST_INT, \ + &&OPCODE_TYPE_ADJUST_FLOAT, \ + &&OPCODE_TYPE_ADJUST_STRING, \ + &&OPCODE_TYPE_ADJUST_VECTOR2, \ + &&OPCODE_TYPE_ADJUST_VECTOR2I, \ + &&OPCODE_TYPE_ADJUST_RECT2, \ + &&OPCODE_TYPE_ADJUST_RECT2I, \ + &&OPCODE_TYPE_ADJUST_VECTOR3, \ + &&OPCODE_TYPE_ADJUST_VECTOR3I, \ + &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \ + &&OPCODE_TYPE_ADJUST_PLANE, \ + &&OPCODE_TYPE_ADJUST_QUATERNION, \ + &&OPCODE_TYPE_ADJUST_AABB, \ + &&OPCODE_TYPE_ADJUST_BASIS, \ + &&OPCODE_TYPE_ADJUST_TRANSFORM, \ + &&OPCODE_TYPE_ADJUST_COLOR, \ + &&OPCODE_TYPE_ADJUST_STRING_NAME, \ + &&OPCODE_TYPE_ADJUST_NODE_PATH, \ + &&OPCODE_TYPE_ADJUST_RID, \ + &&OPCODE_TYPE_ADJUST_OBJECT, \ + &&OPCODE_TYPE_ADJUST_CALLABLE, \ + &&OPCODE_TYPE_ADJUST_SIGNAL, \ + &&OPCODE_TYPE_ADJUST_DICTIONARY, \ + &&OPCODE_TYPE_ADJUST_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \ + &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \ &&OPCODE_ASSERT, \ &&OPCODE_BREAKPOINT, \ &&OPCODE_LINE, \ @@ -349,7 +398,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const #define OP_GET_VECTOR3I get_vector3i #define OP_GET_RECT2 get_rect2 #define OP_GET_RECT2I get_rect2i -#define OP_GET_QUAT get_quat +#define OP_GET_QUATERNION get_quaternion #define OP_GET_COLOR get_color #define OP_GET_STRING get_string #define OP_GET_STRING_NAME get_string_name @@ -367,7 +416,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const #define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array #define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array #define OP_GET_PACKED_COLOR_ARRAY get_color_array -#define OP_GET_TRANSFORM get_transform +#define OP_GET_TRANSFORM3D get_transform #define OP_GET_TRANSFORM2D get_transform2d #define OP_GET_PLANE get_plane #define OP_GET_AABB get_aabb @@ -383,11 +432,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a r_err.error = Callable::CallError::CALL_OK; - Variant self; - Variant static_ref; Variant retvalue; Variant *stack = nullptr; - Variant **instruction_args; + Variant **instruction_args = nullptr; const void **call_args_ptr = nullptr; int defarg = 0; @@ -412,7 +459,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a script = p_state->script; p_instance = p_state->instance; defarg = p_state->defarg; - self = p_state->self; } else { if (p_argcount != _argument_count) { @@ -430,55 +476,49 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } - alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size; + // Add 3 here for self, class, and nil. + alloca_size = sizeof(Variant *) * 3 + sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size; - if (alloca_size) { - uint8_t *aptr = (uint8_t *)alloca(alloca_size); + uint8_t *aptr = (uint8_t *)alloca(alloca_size); + stack = (Variant *)aptr; - if (_stack_size) { - stack = (Variant *)aptr; - for (int i = 0; i < p_argcount; i++) { - if (!argument_types[i].has_type) { - memnew_placement(&stack[i], Variant(*p_args[i])); - continue; - } - - if (!argument_types[i].is_type(*p_args[i], true)) { - r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_err.argument = i; - r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; - return Variant(); - } - if (argument_types[i].kind == GDScriptDataType::BUILTIN) { - Variant arg; - Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err); - memnew_placement(&stack[i], Variant(arg)); - } else { - memnew_placement(&stack[i], Variant(*p_args[i])); - } - } - for (int i = p_argcount; i < _stack_size; i++) { - memnew_placement(&stack[i], Variant); - } - } else { - stack = nullptr; + for (int i = 0; i < p_argcount; i++) { + if (!argument_types[i].has_type) { + memnew_placement(&stack[i + 3], Variant(*p_args[i])); + continue; } - if (_instruction_args_size) { - instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; + if (!argument_types[i].is_type(*p_args[i], true)) { + r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_err.argument = i; + r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; + return Variant(); + } + if (argument_types[i].kind == GDScriptDataType::BUILTIN) { + Variant arg; + Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err); + memnew_placement(&stack[i + 3], Variant(arg)); } else { - instruction_args = nullptr; + memnew_placement(&stack[i + 3], Variant(*p_args[i])); } + } + for (int i = p_argcount + 3; i < _stack_size; i++) { + memnew_placement(&stack[i], Variant); + } + memnew_placement(&stack[ADDR_STACK_NIL], Variant); + + if (_instruction_args_size) { + instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; } else { - stack = nullptr; instruction_args = nullptr; } if (p_instance) { - self = p_instance->owner; + memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner)); script = p_instance->script.ptr(); } else { + memnew_placement(&stack[ADDR_STACK_SELF], Variant); script = _script; } } @@ -488,7 +528,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a call_args_ptr = nullptr; } - static_ref = script; + memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script)); + + for (const Map<int, Variant::Type>::Element *E = temporary_slots.front(); E; E = E->next()) { + type_init_function_table[E->get()](&stack[E->key()]); + } String err_text; @@ -509,10 +553,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #define CHECK_SPACE(m_space) \ GD_ERR_BREAK((ip + m_space) > _code_size) -#define GET_VARIANT_PTR(m_v, m_code_ofs) \ - Variant *m_v; \ - m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \ - if (unlikely(!m_v)) \ +#define GET_VARIANT_PTR(m_v, m_code_ofs) \ + Variant *m_v; \ + m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text); \ + if (unlikely(!m_v)) \ OPCODE_BREAK; #else @@ -520,7 +564,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #define CHECK_SPACE(m_space) #define GET_VARIANT_PTR(m_v, m_code_ofs) \ Variant *m_v; \ - m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); + m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text); #endif @@ -544,7 +588,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED OPCODE_WHILE(ip < _code_size) { - int last_opcode = _code_ptr[ip]; + int last_opcode = _code_ptr[ip] & INSTR_MASK; #else OPCODE_WHILE(true) { #endif @@ -1077,6 +1121,31 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_ASSIGN_TYPED_ARRAY) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(src, 1); + + Array *dst_arr = VariantInternal::get_array(dst); + + if (src->get_type() != Variant::ARRAY) { +#ifdef DEBUG_ENABLED + err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + + "' to a variable of type '" + +"'."; +#endif + OPCODE_BREAK; + } + if (!dst_arr->typed_assign(*src)) { +#ifdef DEBUG_ENABLED + err_text = "Trying to assign a typed array with an array of different type.'"; +#endif + OPCODE_BREAK; + } + + ip += 3; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) { CHECK_SPACE(4); GET_INSTRUCTION_ARG(dst, 0); @@ -1308,6 +1377,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } GET_INSTRUCTION_ARG(dst, argc); + *dst = Variant(); // Clear potential previous typed array. *dst = array; @@ -1315,6 +1385,35 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CONSTRUCT_TYPED_ARRAY) { + CHECK_SPACE(3 + instr_arg_count); + ip += instr_arg_count; + + int argc = _code_ptr[ip + 1]; + + GET_INSTRUCTION_ARG(script_type, argc + 1); + Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 2]; + int native_type_idx = _code_ptr[ip + 3]; + GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count); + const StringName native_type = _global_names_ptr[native_type_idx]; + + Array array; + array.set_typed(builtin_type, native_type, script_type); + array.resize(argc); + + for (int i = 0; i < argc; i++) { + array[i] = *(instruction_args[i]); + } + + GET_INSTRUCTION_ARG(dst, argc); + *dst = Variant(); // Clear potential previous typed array. + + *dst = array; + + ip += 4; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_CONSTRUCT_DICTIONARY) { CHECK_SPACE(2 + instr_arg_count); @@ -1398,13 +1497,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (err.error != Callable::CallError::CALL_OK) { String methodstr = *methodname; String basestr = _get_var_type(base); + bool is_callable = false; if (methodstr == "call") { - if (argc >= 1) { + if (argc >= 1 && base->get_type() != Variant::CALLABLE) { methodstr = String(*argptrs[0]) + " (via call)"; if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) { err.argument += 1; } + } else { + methodstr = base->operator String() + " (Callable)"; + is_callable = true; } } else if (methodstr == "free") { if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { @@ -1424,7 +1527,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } } - err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs); + err_text = _get_call_error(err, "function '" + methodstr + (is_callable ? "" : "' in base '" + basestr) + "'", (const Variant **)argptrs); OPCODE_BREAK; } #endif @@ -1513,6 +1616,51 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_BUILTIN_STATIC) { + CHECK_SPACE(4 + instr_arg_count); + + ip += instr_arg_count; + + GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= Variant::VARIANT_MAX); + Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 1]; + + int methodname_idx = _code_ptr[ip + 2]; + GD_ERR_BREAK(methodname_idx < 0 || methodname_idx >= _global_names_count); + const StringName *methodname = &_global_names_ptr[methodname_idx]; + + int argc = _code_ptr[ip + 3]; + GD_ERR_BREAK(argc < 0); + + GET_INSTRUCTION_ARG(ret, argc); + + const Variant **argptrs = const_cast<const Variant **>(instruction_args); + +#ifdef DEBUG_ENABLED + uint64_t call_time = 0; + + if (GDScriptLanguage::get_singleton()->profiling) { + call_time = OS::get_singleton()->get_ticks_usec(); + } +#endif + + Callable::CallError err; + Variant::call_static(builtin_type, *methodname, argptrs, argc, *ret, err); + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { + function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + } + + if (err.error != Callable::CallError::CALL_OK) { + err_text = _get_call_error(err, "static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs); + OPCODE_BREAK; + } +#endif + + ip += 4; + } + DISPATCH_OPCODE; + #ifdef DEBUG_ENABLED #define OPCODE_CALL_PTR(m_type) \ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \ @@ -1585,10 +1733,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_CALL_PTR(VECTOR3I); OPCODE_CALL_PTR(TRANSFORM2D); OPCODE_CALL_PTR(PLANE); - OPCODE_CALL_PTR(QUAT); + OPCODE_CALL_PTR(QUATERNION); OPCODE_CALL_PTR(AABB); OPCODE_CALL_PTR(BASIS); - OPCODE_CALL_PTR(TRANSFORM); + OPCODE_CALL_PTR(TRANSFORM3D); OPCODE_CALL_PTR(COLOR); OPCODE_CALL_PTR(STRING_NAME); OPCODE_CALL_PTR(NODE_PATH); @@ -1822,7 +1970,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (err.error != Callable::CallError::CALL_OK) { // TODO: Add this information in debug. - String methodstr = "<unkown function>"; + String methodstr = "<unknown function>"; if (dst->get_type() == Variant::STRING) { // Call provided error string. err_text = "Error calling GDScript utility function '" + methodstr + "': " + String(*dst); @@ -1841,7 +1989,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a ip += instr_arg_count; - int self_fun = _code_ptr[ip + 1]; + int argc = _code_ptr[ip + 1]; + GD_ERR_BREAK(argc < 0); + + int self_fun = _code_ptr[ip + 2]; #ifdef DEBUG_ENABLED if (self_fun < 0 || self_fun >= _global_names_count) { err_text = "compiler bug, function name not found"; @@ -1850,9 +2001,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif const StringName *methodname = &_global_names_ptr[self_fun]; - int argc = _code_ptr[ip + 2]; - GD_ERR_BREAK(argc < 0); - Variant **argptrs = instruction_args; GET_INSTRUCTION_ARG(dst, argc); @@ -1951,7 +2099,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i])); } gdfs->state.stack_size = _stack_size; - gdfs->state.self = self; gdfs->state.alloca_size = alloca_size; gdfs->state.ip = ip + 2; gdfs->state.line = line; @@ -2004,6 +2151,34 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CREATE_LAMBDA) { + CHECK_SPACE(2 + instr_arg_count); + + ip += instr_arg_count; + + int captures_count = _code_ptr[ip + 1]; + GD_ERR_BREAK(captures_count < 0); + + int lambda_index = _code_ptr[ip + 2]; + GD_ERR_BREAK(lambda_index < 0 || lambda_index >= _lambdas_count); + GDScriptFunction *lambda = _lambdas_ptr[lambda_index]; + + Vector<Variant> captures; + captures.resize(captures_count); + for (int i = 0; i < captures_count; i++) { + GET_INSTRUCTION_ARG(arg, i); + captures.write[i] = *arg; + } + + GDScriptLambdaCallable *callable = memnew(GDScriptLambdaCallable(Ref<GDScript>(script), lambda, captures)); + + GET_INSTRUCTION_ARG(result, captures_count); + *result = Callable(callable); + + ip += 3; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_JUMP) { CHECK_SPACE(2); int to = _code_ptr[ip + 1]; @@ -2063,6 +2238,183 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } + OPCODE(OPCODE_RETURN_TYPED_BUILTIN) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(r, 0); + + Variant::Type ret_type = (Variant::Type)_code_ptr[ip + 2]; + GD_ERR_BREAK(ret_type < 0 || ret_type >= Variant::VARIANT_MAX); + + if (r->get_type() != ret_type) { + if (Variant::can_convert_strict(r->get_type(), ret_type)) { + Callable::CallError ce; + Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce); + } else { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type)); +#endif // DEBUG_ENABLED + + // Construct a base type anyway so type constraints are met. + Callable::CallError ce; + Variant::construct(ret_type, retvalue, nullptr, 0, ce); + OPCODE_BREAK; + } + } else { + retvalue = *r; + } +#ifdef DEBUG_ENABLED + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + OPCODE(OPCODE_RETURN_TYPED_ARRAY) { + CHECK_SPACE(5); + GET_INSTRUCTION_ARG(r, 0); + + GET_INSTRUCTION_ARG(script_type, 1); + Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 3]; + int native_type_idx = _code_ptr[ip + 4]; + GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count); + const StringName native_type = _global_names_ptr[native_type_idx]; + + if (r->get_type() != Variant::ARRAY) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "Array[%s]".)", + Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type)); +#endif + OPCODE_BREAK; + } + + Array array; + array.set_typed(builtin_type, native_type, script_type); + +#ifdef DEBUG_ENABLED + bool valid = array.typed_assign(*VariantInternal::get_array(r)); +#else + array.typed_assign(*VariantInternal::get_array(r)); +#endif // DEBUG_ENABLED + + // Assign the return value anyway since we want it to be the valid type. + retvalue = array; + +#ifdef DEBUG_ENABLED + if (!valid) { + err_text = "Trying to return a typed array with an array of different type.'"; + OPCODE_BREAK; + } + + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + OPCODE(OPCODE_RETURN_TYPED_NATIVE) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(r, 0); + + GET_INSTRUCTION_ARG(type, 1); + GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *()); + GD_ERR_BREAK(!nc); + + if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) { + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + Variant::get_type_name(r->get_type()), nc->get_name()); + OPCODE_BREAK; + } + +#ifdef DEBUG_ENABLED + bool freed = false; + Object *ret_obj = r->get_validated_object_with_check(freed); + + if (freed) { + err_text = "Trying to return a previously freed instance."; + OPCODE_BREAK; + } +#else + Object *ret_obj = r->operator Object *(); +#endif // DEBUG_ENABLED + if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + ret_obj->get_class_name(), nc->get_name()); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + retvalue = *r; + +#ifdef DEBUG_ENABLED + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + OPCODE(OPCODE_RETURN_TYPED_SCRIPT) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(r, 0); + + GET_INSTRUCTION_ARG(type, 1); + Script *base_type = Object::cast_to<Script>(type->operator Object *()); + GD_ERR_BREAK(!base_type); + + if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + Variant::get_type_name(r->get_type()), _get_script_name(Ref<Script>(base_type))); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + +#ifdef DEBUG_ENABLED + bool freed = false; + Object *ret_obj = r->get_validated_object_with_check(freed); + + if (freed) { + err_text = "Trying to return a previously freed instance."; + OPCODE_BREAK; + } +#else + Object *ret_obj = r->operator Object *(); +#endif // DEBUG_ENABLED + + if (ret_obj) { + ScriptInstance *ret_inst = ret_obj->get_script_instance(); + if (!ret_inst) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + ret_obj->get_class_name(), _get_script_name(Ref<GDScript>(base_type))); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + Script *ret_type = ret_obj->get_script_instance()->get_script().ptr(); + bool valid = false; + + while (ret_type) { + if (ret_type == base_type) { + valid = true; + break; + } + ret_type = ret_type->get_base_script().ptr(); + } + + if (!valid) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + _get_script_name(ret_obj->get_script_instance()->get_script()), _get_script_name(Ref<GDScript>(base_type))); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + } + retvalue = *r; + +#ifdef DEBUG_ENABLED + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + OPCODE(OPCODE_ITERATE_BEGIN) { CHECK_SPACE(8); // Space for this and a regular iterate. @@ -2764,6 +3116,63 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_STORE_NAMED_GLOBAL) { + CHECK_SPACE(3); + int globalname_idx = _code_ptr[ip + 2]; + GD_ERR_BREAK(globalname_idx < 0 || globalname_idx >= _global_names_count); + const StringName *globalname = &_global_names_ptr[globalname_idx]; + + GET_INSTRUCTION_ARG(dst, 0); + *dst = GDScriptLanguage::get_singleton()->get_named_globals_map()[*globalname]; + + ip += 3; + } + DISPATCH_OPCODE; + +#define OPCODE_TYPE_ADJUST(m_v_type, m_c_type) \ + OPCODE(OPCODE_TYPE_ADJUST_##m_v_type) { \ + CHECK_SPACE(2); \ + GET_INSTRUCTION_ARG(arg, 0); \ + VariantTypeAdjust<m_c_type>::adjust(arg); \ + ip += 2; \ + } \ + DISPATCH_OPCODE + + OPCODE_TYPE_ADJUST(BOOL, bool); + OPCODE_TYPE_ADJUST(INT, int64_t); + OPCODE_TYPE_ADJUST(FLOAT, double); + OPCODE_TYPE_ADJUST(STRING, String); + OPCODE_TYPE_ADJUST(VECTOR2, Vector2); + OPCODE_TYPE_ADJUST(VECTOR2I, Vector2i); + OPCODE_TYPE_ADJUST(RECT2, Rect2); + OPCODE_TYPE_ADJUST(RECT2I, Rect2i); + OPCODE_TYPE_ADJUST(VECTOR3, Vector3); + OPCODE_TYPE_ADJUST(VECTOR3I, Vector3i); + OPCODE_TYPE_ADJUST(TRANSFORM2D, Transform2D); + OPCODE_TYPE_ADJUST(PLANE, Plane); + OPCODE_TYPE_ADJUST(QUATERNION, Quaternion); + OPCODE_TYPE_ADJUST(AABB, AABB); + OPCODE_TYPE_ADJUST(BASIS, Basis); + OPCODE_TYPE_ADJUST(TRANSFORM, Transform3D); + OPCODE_TYPE_ADJUST(COLOR, Color); + OPCODE_TYPE_ADJUST(STRING_NAME, StringName); + OPCODE_TYPE_ADJUST(NODE_PATH, NodePath); + OPCODE_TYPE_ADJUST(RID, RID); + OPCODE_TYPE_ADJUST(OBJECT, Object *); + OPCODE_TYPE_ADJUST(CALLABLE, Callable); + OPCODE_TYPE_ADJUST(SIGNAL, Signal); + OPCODE_TYPE_ADJUST(DICTIONARY, Dictionary); + OPCODE_TYPE_ADJUST(ARRAY, Array); + OPCODE_TYPE_ADJUST(PACKED_BYTE_ARRAY, PackedByteArray); + OPCODE_TYPE_ADJUST(PACKED_INT32_ARRAY, PackedInt32Array); + OPCODE_TYPE_ADJUST(PACKED_INT64_ARRAY, PackedInt64Array); + OPCODE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY, PackedFloat32Array); + OPCODE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY, PackedFloat64Array); + OPCODE_TYPE_ADJUST(PACKED_STRING_ARRAY, PackedStringArray); + OPCODE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY, PackedVector2Array); + OPCODE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY, PackedVector3Array); + OPCODE_TYPE_ADJUST(PACKED_COLOR_ARRAY, PackedColorArray); + OPCODE(OPCODE_ASSERT) { CHECK_SPACE(3); diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index e63b6ab20e..f817964a3c 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -32,7 +32,6 @@ #include "../gdscript.h" #include "../gdscript_analyzer.h" -#include "core/io/json.h" #include "gdscript_language_protocol.h" #include "gdscript_workspace.h" @@ -49,8 +48,9 @@ void ExtendGDScriptParser::update_diagnostics() { diagnostic.code = -1; lsp::Range range; lsp::Position pos; - int line = LINE_NUMBER_TO_INDEX(error.line); - const String &line_text = get_lines()[line]; + const PackedStringArray lines = get_lines(); + int line = CLAMP(LINE_NUMBER_TO_INDEX(error.line), 0, lines.size() - 1); + const String &line_text = lines[line]; pos.line = line; pos.character = line_text.length() - line_text.strip_edges(true, false).length(); range.start = pos; @@ -182,7 +182,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p symbol.detail += ": " + m.get_datatype().to_string(); } if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) { - symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value); + symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string(); } symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line)); @@ -223,10 +223,10 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } if (!value_text.is_empty()) { symbol.detail += " = " + value_text; @@ -352,8 +352,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN parameters += ": " + parameter->get_datatype().to_string(); } if (parameter->default_value != nullptr) { - String value = JSON::print(parameter->default_value->reduced_value); - parameters += " = " + value; + parameters += " = " + parameter->default_value->reduced_value.to_json_string(); } } r_symbol.detail += parameters + ")"; @@ -361,24 +360,73 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN r_symbol.detail += " -> " + p_func->get_datatype().to_string(); } - for (int i = 0; i < p_func->body->locals.size(); i++) { - const SuiteNode::Local &local = p_func->body->locals[i]; - lsp::DocumentSymbol symbol; - symbol.name = local.name; - symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable; - symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line); - symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column); - symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line); - symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column); - symbol.uri = uri; - symbol.script_path = path; - symbol.detail = SuiteNode::Local::CONSTANT ? "const " : "var "; - symbol.detail += symbol.name; - if (local.get_datatype().is_hard_type()) { - symbol.detail += ": " + local.get_datatype().to_string(); + List<GDScriptParser::SuiteNode *> function_nodes; + + List<GDScriptParser::Node *> node_stack; + node_stack.push_back(p_func->body); + + while (!node_stack.is_empty()) { + GDScriptParser::Node *node = node_stack[0]; + node_stack.pop_front(); + + switch (node->type) { + case GDScriptParser::TypeNode::IF: { + GDScriptParser::IfNode *if_node = (GDScriptParser::IfNode *)node; + node_stack.push_back(if_node->true_block); + if (if_node->false_block) { + node_stack.push_back(if_node->false_block); + } + } break; + + case GDScriptParser::TypeNode::FOR: { + GDScriptParser::ForNode *for_node = (GDScriptParser::ForNode *)node; + node_stack.push_back(for_node->loop); + } break; + + case GDScriptParser::TypeNode::WHILE: { + GDScriptParser::WhileNode *while_node = (GDScriptParser::WhileNode *)node; + node_stack.push_back(while_node->loop); + } break; + + case GDScriptParser::TypeNode::MATCH_BRANCH: { + GDScriptParser::MatchBranchNode *match_node = (GDScriptParser::MatchBranchNode *)node; + node_stack.push_back(match_node->block); + } break; + + case GDScriptParser::TypeNode::SUITE: { + GDScriptParser::SuiteNode *suite_node = (GDScriptParser::SuiteNode *)node; + function_nodes.push_back(suite_node); + for (int i = 0; i < suite_node->statements.size(); ++i) { + node_stack.push_back(suite_node->statements[i]); + } + } break; + + default: + continue; + } + } + + for (List<GDScriptParser::SuiteNode *>::Element *N = function_nodes.front(); N; N = N->next()) { + const GDScriptParser::SuiteNode *suite_node = N->get(); + for (int i = 0; i < suite_node->locals.size(); i++) { + const SuiteNode::Local &local = suite_node->locals[i]; + lsp::DocumentSymbol symbol; + symbol.name = local.name; + symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable; + symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line); + symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column); + symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line); + symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column); + symbol.uri = uri; + symbol.script_path = path; + symbol.detail = local.type == SuiteNode::Local::CONSTANT ? "const " : "var "; + symbol.detail += symbol.name; + if (local.get_datatype().is_hard_type()) { + symbol.detail += ": " + local.get_datatype().to_string(); + } + symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(local.start_line)); + r_symbol.children.push_back(symbol); } - symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(local.start_line)); - r_symbol.children.push_back(symbol); } } diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 912c9a174e..0d1f98778e 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -31,8 +31,6 @@ #include "gdscript_language_protocol.h" #include "core/config/project_settings.h" -#include "core/io/json.h" -#include "core/os/copymem.h" #include "editor/doc_tools.h" #include "editor/editor_log.h" #include "editor/editor_node.h" @@ -195,7 +193,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id)); Ref<LSPeer> peer = clients.get(latest_client_id); if (peer != nullptr) { - String msg = JSON::print(request); + String msg = Variant(request).to_json_string(); msg = format_output(msg); (*peer)->res_queue.push_back(msg.utf8()); } @@ -256,7 +254,7 @@ void GDScriptLanguageProtocol::poll() { } } -Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) { +Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) { return server->listen(p_port, p_bind_ip); } @@ -281,7 +279,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia ERR_FAIL_COND(peer == nullptr); Dictionary message = make_notification(p_method, p_params); - String msg = JSON::print(message); + String msg = Variant(message).to_json_string(); msg = format_output(msg); peer->res_queue.push_back(msg.utf8()); } @@ -295,10 +293,10 @@ bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const { } GDScriptLanguageProtocol::GDScriptLanguageProtocol() { - server.instance(); + server.instantiate(); singleton = this; - workspace.instance(); - text_document.instance(); + workspace.instantiate(); + text_document.instantiate(); set_scope("textDocument", text_document.ptr()); set_scope("completionItem", text_document.ptr()); set_scope("workspace", workspace.ptr()); diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index 8b08ae0655..5a2dd55c46 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GDSCRIPT_PROTOCAL_SERVER_H -#define GDSCRIPT_PROTOCAL_SERVER_H +#ifndef GDSCRIPT_LANGUAGE_PROTOCOL_H +#define GDSCRIPT_LANGUAGE_PROTOCOL_H #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" @@ -37,7 +37,13 @@ #include "gdscript_text_document.h" #include "gdscript_workspace.h" #include "lsp.hpp" + +#include "modules/modules_enabled.gen.h" +#ifdef MODULE_JSONRPC_ENABLED #include "modules/jsonrpc/jsonrpc.h" +#else +#error "Can't build GDScript LSP without JSONRPC module." +#endif #define LSP_MAX_BUFFER_SIZE 4194304 #define LSP_MAX_CLIENTS 8 @@ -46,7 +52,7 @@ class GDScriptLanguageProtocol : public JSONRPC { GDCLASS(GDScriptLanguageProtocol, JSONRPC) private: - struct LSPeer : Reference { + struct LSPeer : RefCounted { Ref<StreamPeerTCP> connection; uint8_t req_buf[LSP_MAX_BUFFER_SIZE]; @@ -69,7 +75,7 @@ private: static GDScriptLanguageProtocol *singleton; HashMap<int, Ref<LSPeer>> clients; - Ref<TCP_Server> server; + Ref<TCPServer> server; int latest_client_id = 0; int next_client_id = 0; @@ -97,7 +103,7 @@ public: _FORCE_INLINE_ bool is_initialized() const { return _initialized; } void poll(); - Error start(int p_port, const IP_Address &p_bind_ip); + Error start(int p_port, const IPAddress &p_bind_ip); void stop(); void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1); @@ -108,4 +114,4 @@ public: GDScriptLanguageProtocol(); }; -#endif +#endif // GDSCRIPT_LANGUAGE_PROTOCOL_H diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 98ada9de4d..c47164d95b 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -30,7 +30,7 @@ #include "gdscript_language_server.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "editor/editor_log.h" #include "editor/editor_node.h" @@ -78,7 +78,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) { void GDScriptLanguageServer::start() { port = (int)_EDITOR_GET("network/language_server/remote_port"); use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); - if (protocol.start(port, IP_Address("127.0.0.1")) == OK) { + if (protocol.start(port, IPAddress("127.0.0.1")) == OK) { EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR); if (use_thread) { thread_running = true; @@ -101,7 +101,7 @@ void GDScriptLanguageServer::stop() { } void register_lsp_types() { - ClassDB::register_class<GDScriptLanguageProtocol>(); - ClassDB::register_class<GDScriptTextDocument>(); - ClassDB::register_class<GDScriptWorkspace>(); + GDREGISTER_CLASS(GDScriptLanguageProtocol); + GDREGISTER_CLASS(GDScriptTextDocument); + GDREGISTER_CLASS(GDScriptWorkspace); } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 9f2373bf56..59d2e6c8fa 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -40,6 +40,7 @@ void GDScriptTextDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); + ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose); ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange); ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol); ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol); @@ -61,6 +62,11 @@ void GDScriptTextDocument::didOpen(const Variant &p_param) { sync_script_content(doc.uri, doc.text); } +void GDScriptTextDocument::didClose(const Variant &p_param) { + // Left empty on purpose. Godot does nothing special on closing a document, + // but it satisfies LSP clients that require didClose be implemented. +} + void GDScriptTextDocument::didChange(const Variant &p_param) { lsp::TextDocumentItem doc = load_document_item(p_param); Dictionary dict = p_param; @@ -400,6 +406,7 @@ GDScriptTextDocument::~GDScriptTextDocument() { void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) { String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path); GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); + EditorFileSystem::get_singleton()->update_file(path); } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 792e601bc1..e2987f779c 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -31,18 +31,19 @@ #ifndef GDSCRIPT_TEXT_DOCUMENT_H #define GDSCRIPT_TEXT_DOCUMENT_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "lsp.hpp" -class GDScriptTextDocument : public Reference { - GDCLASS(GDScriptTextDocument, Reference) +class GDScriptTextDocument : public RefCounted { + GDCLASS(GDScriptTextDocument, RefCounted) protected: static void _bind_methods(); FileAccess *file_checker; void didOpen(const Variant &p_param); + void didClose(const Variant &p_param); void didChange(const Variant &p_param); void sync_script_content(const String &p_path, const String &p_content); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 69cad1a335..1915c92cbf 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -42,6 +42,7 @@ #include "scene/resources/packed_scene.h" void GDScriptWorkspace::_bind_methods() { + ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::did_delete_files); ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol); ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script); ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_local_script); @@ -51,6 +52,16 @@ void GDScriptWorkspace::_bind_methods() { ClassDB::bind_method(D_METHOD("generate_script_api", "path"), &GDScriptWorkspace::generate_script_api); } +void GDScriptWorkspace::did_delete_files(const Dictionary &p_params) { + Array files = p_params["files"]; + for (int i = 0; i < files.size(); ++i) { + Dictionary file = files[i]; + String uri = file["uri"]; + String path = get_file_path(uri); + parse_script(path, ""); + } +} + void GDScriptWorkspace::remove_cache_parser(const String &p_path) { Map<String, ExtendGDScriptParser *>::Element *parser = parse_results.find(p_path); Map<String, ExtendGDScriptParser *>::Element *script = scripts.find(p_path); @@ -177,7 +188,9 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) { E->get()->get_symbols().symbol_tree_as_list(E->key(), script_symbols); for (int i = 0; i < script_symbols.size(); ++i) { if (query.is_subsequence_ofi(script_symbols[i].name)) { - arr.push_back(script_symbols[i].to_json()); + lsp::DocumentedSymbolInformation symbol = script_symbols[i]; + symbol.location.uri = get_file_uri(symbol.location.uri); + arr.push_back(symbol.to_json()); } } } @@ -413,7 +426,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { RES owner_res = ResourceLoader::load(owner_path); if (Object::cast_to<PackedScene>(owner_res.ptr())) { Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); - owner_scene_node = owner_packed_scene->instance(); + owner_scene_node = owner_packed_scene->instantiate(); break; } } diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 7fd8bfcf20..8b166a873c 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -37,8 +37,8 @@ #include "gdscript_extend_parser.h" #include "lsp.hpp" -class GDScriptWorkspace : public Reference { - GDCLASS(GDScriptWorkspace, Reference); +class GDScriptWorkspace : public RefCounted { + GDCLASS(GDScriptWorkspace, RefCounted); private: void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners); @@ -89,6 +89,7 @@ public: void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list); Dictionary generate_script_api(const String &p_path); Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature); + void did_delete_files(const Dictionary &p_params); GDScriptWorkspace(); ~GDScriptWorkspace(); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index 6635098be2..a7dcfdb22d 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -766,7 +766,7 @@ struct MarkupContent { // Use namespace instead of enumeration to follow the LSP specifications // lsp::EnumName::EnumValue is OK but lsp::EnumValue is not -// And here C++ compilers are unhappy with our enumeration name like Color, File, Reference etc. +// And here C++ compilers are unhappy with our enumeration name like Color, File, RefCounted etc. /** * The kind of a completion entry. */ @@ -788,7 +788,7 @@ static const int Keyword = 14; static const int Snippet = 15; static const int Color = 16; static const int File = 17; -static const int Reference = 18; +static const int RefCounted = 18; static const int Folder = 19; static const int EnumMember = 20; static const int Constant = 21; @@ -1528,6 +1528,114 @@ struct SignatureHelp { } }; +/** + * A pattern to describe in which file operation requests or notifications + * the server is interested in. + */ +struct FileOperationPattern { + /** + * The glob pattern to match. + */ + String glob = "**/*.gd"; + + /** + * Whether to match `file`s or `folder`s with this pattern. + * + * Matches both if undefined. + */ + String matches = "file"; + + Dictionary to_json() const { + Dictionary dict; + + dict["glob"] = glob; + dict["matches"] = matches; + + return dict; + } +}; + +/** + * A filter to describe in which file operation requests or notifications + * the server is interested in. + */ +struct FileOperationFilter { + /** + * The actual file operation pattern. + */ + FileOperationPattern pattern; + + Dictionary to_json() const { + Dictionary dict; + + dict["pattern"] = pattern.to_json(); + + return dict; + } +}; + +/** + * The options to register for file operations. + */ +struct FileOperationRegistrationOptions { + /** + * The actual filters. + */ + Vector<FileOperationFilter> filters; + + FileOperationRegistrationOptions() { + filters.push_back(FileOperationFilter()); + } + + Dictionary to_json() const { + Dictionary dict; + + Array filts; + for (int i = 0; i < filters.size(); i++) { + filts.push_back(filters[i].to_json()); + } + dict["filters"] = filts; + + return dict; + } +}; + +/** + * The server is interested in file notifications/requests. + */ +struct FileOperations { + /** + * The server is interested in receiving didDeleteFiles file notifications. + */ + FileOperationRegistrationOptions didDelete; + + Dictionary to_json() const { + Dictionary dict; + + dict["didDelete"] = didDelete.to_json(); + + return dict; + } +}; + +/** + * Workspace specific server capabilities + */ +struct Workspace { + /** + * The server is interested in file notifications/requests. + */ + FileOperations fileOperations; + + Dictionary to_json() const { + Dictionary dict; + + dict["fileOperations"] = fileOperations.to_json(); + + return dict; + } +}; + struct ServerCapabilities { /** * Defines how text documents are synced. Is either a detailed structure defining each notification or @@ -1590,6 +1698,11 @@ struct ServerCapabilities { bool workspaceSymbolProvider = true; /** + * The server supports workspace folder. + */ + Workspace workspace; + + /** * The server provides code actions. The `CodeActionOptions` return type is only * valid if the client signals code action literal support via the property * `textDocument.codeAction.codeActionLiteralSupport`. @@ -1676,6 +1789,7 @@ struct ServerCapabilities { dict["documentHighlightProvider"] = documentHighlightProvider; dict["documentSymbolProvider"] = documentSymbolProvider; dict["workspaceSymbolProvider"] = workspaceSymbolProvider; + dict["workspace"] = workspace.to_json(); dict["codeActionProvider"] = codeActionProvider; dict["documentFormattingProvider"] = documentFormattingProvider; dict["documentRangeFormattingProvider"] = documentRangeFormattingProvider; diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 93b709a613..c2b1981f31 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -30,10 +30,10 @@ #include "register_types.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/io/resource_loader.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "gdscript.h" #include "gdscript_analyzer.h" #include "gdscript_cache.h" @@ -92,12 +92,12 @@ public: static void _editor_init() { Ref<EditorExportGDScript> gd_export; - gd_export.instance(); + gd_export.instantiate(); EditorExport::get_singleton()->add_export_plugin(gd_export); #ifdef TOOLS_ENABLED Ref<GDScriptSyntaxHighlighter> gdscript_syntax_highlighter; - gdscript_syntax_highlighter.instance(); + gdscript_syntax_highlighter.instantiate(); ScriptEditor::get_singleton()->register_syntax_highlighter(gdscript_syntax_highlighter); #endif @@ -112,15 +112,15 @@ static void _editor_init() { #endif // TOOLS_ENABLED void register_gdscript_types() { - ClassDB::register_class<GDScript>(); + GDREGISTER_CLASS(GDScript); script_language_gd = memnew(GDScriptLanguage); ScriptServer::register_language(script_language_gd); - resource_loader_gd.instance(); + resource_loader_gd.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gd); - resource_saver_gd.instance(); + resource_saver_gd.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gd); gdscript_cache = memnew(GDScriptCache); @@ -128,7 +128,7 @@ void register_gdscript_types() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(_editor_init); - gdscript_translation_parser_plugin.instance(); + gdscript_translation_parser_plugin.instantiate(); EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); #endif // TOOLS_ENABLED @@ -158,25 +158,24 @@ void unregister_gdscript_types() { #endif // TOOLS_ENABLED GDScriptParser::cleanup(); - GDScriptAnalyzer::cleanup(); GDScriptUtilityFunctions::unregister_functions(); } #ifdef TESTS_ENABLED void test_tokenizer() { - TestGDScript::test(TestGDScript::TestType::TEST_TOKENIZER); + GDScriptTests::test(GDScriptTests::TestType::TEST_TOKENIZER); } void test_parser() { - TestGDScript::test(TestGDScript::TestType::TEST_PARSER); + GDScriptTests::test(GDScriptTests::TestType::TEST_PARSER); } void test_compiler() { - TestGDScript::test(TestGDScript::TestType::TEST_COMPILER); + GDScriptTests::test(GDScriptTests::TestType::TEST_COMPILER); } void test_bytecode() { - TestGDScript::test(TestGDScript::TestType::TEST_BYTECODE); + GDScriptTests::test(GDScriptTests::TestType::TEST_BYTECODE); } REGISTER_TEST_COMMAND("gdscript-tokenizer", &test_tokenizer); diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp new file mode 100644 index 0000000000..b7faebb4ef --- /dev/null +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -0,0 +1,583 @@ +/*************************************************************************/ +/* gdscript_test_runner.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 "gdscript_test_runner.h" + +#include "../gdscript.h" +#include "../gdscript_analyzer.h" +#include "../gdscript_compiler.h" +#include "../gdscript_parser.h" + +#include "core/config/project_settings.h" +#include "core/core_string_names.h" +#include "core/io/dir_access.h" +#include "core/io/file_access_pack.h" +#include "core/os/os.h" +#include "core/string/string_builder.h" +#include "scene/resources/packed_scene.h" + +#include "tests/test_macros.h" + +namespace GDScriptTests { + +void init_autoloads() { + Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + + // First pass, add the constants so they exist before any script is loaded. + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->get(); + + if (info.is_singleton) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->add_global_constant(info.name, Variant()); + } + } + } + + // Second pass, load into global constants. + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->get(); + + if (!info.is_singleton) { + // Skip non-singletons since we don't have a scene tree here anyway. + continue; + } + + RES res = ResourceLoader::load(info.path); + ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path); + Node *n = nullptr; + if (res->is_class("PackedScene")) { + Ref<PackedScene> ps = res; + n = ps->instantiate(); + } else if (res->is_class("Script")) { + Ref<Script> script_res = res; + StringName ibt = script_res->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "Node"); + ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); + + Object *obj = ClassDB::instantiate(ibt); + + ERR_CONTINUE_MSG(obj == nullptr, + "Cannot instance script for autoload, expected 'Node' inheritance, got: " + + String(ibt)); + + n = Object::cast_to<Node>(obj); + n->set_script(script_res); + } + + ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path); + n->set_name(info.name); + + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->add_global_constant(info.name, n); + } + } +} + +void init_language(const String &p_base_path) { + // Setup project settings since it's needed by the languages to get the global scripts. + // This also sets up the base resource path. + Error err = ProjectSettings::get_singleton()->setup(p_base_path, String(), true); + if (err) { + print_line("Could not load project settings."); + // Keep going since some scripts still work without this. + } + + // Initialize the language for the test routine. + GDScriptLanguage::get_singleton()->init(); + init_autoloads(); +} + +void finish_language() { + GDScriptLanguage::get_singleton()->finish(); + ScriptServer::global_classes_clear(); +} + +StringName GDScriptTestRunner::test_function_name; + +GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_language) { + test_function_name = StaticCString::create("test"); + do_init_languages = p_init_language; + + source_dir = p_source_dir; + if (!source_dir.ends_with("/")) { + source_dir += "/"; + } + + 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 printing to show results + _print_line_enabled = true; + _print_error_enabled = true; +} + +GDScriptTestRunner::~GDScriptTestRunner() { + test_function_name = StringName(); + if (do_init_languages) { + finish_language(); + } +} + +int GDScriptTestRunner::run_tests() { + if (!make_tests()) { + FAIL("An error occurred while making the tests."); + return -1; + } + + if (!generate_class_index()) { + FAIL("An error occurred while generating class index."); + return -1; + } + + int failed = 0; + for (int i = 0; i < tests.size(); i++) { + GDScriptTest test = tests[i]; + GDScriptTest::TestResult result = test.run_test(); + + String expected = FileAccess::get_file_as_string(test.get_output_file()); + INFO(test.get_source_file()); + if (!result.passed) { + INFO(expected); + failed++; + } + + CHECK_MESSAGE(result.passed, (result.passed ? String() : result.output)); + } + + return failed; +} + +bool GDScriptTestRunner::generate_outputs() { + is_generating = true; + + if (!make_tests()) { + print_line("Failed to generate a test output."); + return false; + } + + if (!generate_class_index()) { + return false; + } + + for (int i = 0; i < tests.size(); i++) { + OS::get_singleton()->print("."); + GDScriptTest test = tests[i]; + bool result = test.generate_output(); + + if (!result) { + print_line("\nCould not generate output for " + test.get_source_file()); + return false; + } + } + print_line("\nGenerated output files for " + itos(tests.size()) + " tests successfully."); + + return true; +} + +bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { + Error err = OK; + DirAccessRef dir(DirAccess::open(p_dir, &err)); + + if (err != OK) { + return false; + } + + String current_dir = dir->get_current_dir(); + + dir->list_dir_begin(); + String next = dir->get_next(); + + while (!next.is_empty()) { + if (dir->current_is_dir()) { + if (next == "." || next == "..") { + next = dir->get_next(); + continue; + } + if (!make_tests_for_dir(current_dir.plus_file(next))) { + return false; + } + } else { + if (next.get_extension().to_lower() == "gd") { + String out_file = next.get_basename() + ".out"; + if (!is_generating && !dir->file_exists(out_file)) { + ERR_FAIL_V_MSG(false, "Could not find output file for " + next); + } + GDScriptTest test(current_dir.plus_file(next), current_dir.plus_file(out_file), source_dir); + tests.push_back(test); + } + } + + next = dir->get_next(); + } + + dir->list_dir_end(); + + return true; +} + +bool GDScriptTestRunner::make_tests() { + Error err = OK; + DirAccessRef dir(DirAccess::open(source_dir, &err)); + + ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory."); + + source_dir = dir->get_current_dir() + "/"; // Make it absolute path. + return make_tests_for_dir(dir->get_current_dir()); +} + +bool GDScriptTestRunner::generate_class_index() { + StringName gdscript_name = GDScriptLanguage::get_singleton()->get_name(); + for (int i = 0; i < tests.size(); i++) { + GDScriptTest test = tests[i]; + String base_type; + + String class_name = GDScriptLanguage::get_singleton()->get_global_class_name(test.get_source_file(), &base_type); + if (class_name == String()) { + continue; + } + ERR_FAIL_COND_V_MSG(ScriptServer::is_global_class(class_name), false, + "Class name '" + class_name + "' from " + test.get_source_file() + " is already used in " + ScriptServer::get_global_class_path(class_name)); + + ScriptServer::add_global_class(class_name, base_type, gdscript_name, test.get_source_file()); + } + return true; +} + +GDScriptTest::GDScriptTest(const String &p_source_path, const String &p_output_path, const String &p_base_dir) { + source_file = p_source_path; + output_file = p_output_path; + base_dir = p_base_dir; + _print_handler.printfunc = print_handler; + _error_handler.errfunc = error_handler; +} + +void GDScriptTestRunner::handle_cmdline() { + List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); + // TODO: this could likely be ported to use test commands: + // https://github.com/godotengine/godot/pull/41355 + // Currently requires to startup the whole engine, which is slow. + String test_cmd = "--gdscript-test"; + String gen_cmd = "--gdscript-generate-tests"; + + for (List<String>::Element *E = cmdline_args.front(); E != nullptr; E = E->next()) { + String &cmd = E->get(); + if (cmd == test_cmd || cmd == gen_cmd) { + if (E->next() == nullptr) { + ERR_PRINT("Needed a path for the test files."); + exit(-1); + } + + const String &path = E->next()->get(); + + GDScriptTestRunner runner(path, false); + int failed = 0; + if (cmd == test_cmd) { + failed = runner.run_tests(); + } else { + bool completed = runner.generate_outputs(); + failed = completed ? 0 : -1; + } + exit(failed); + } + } +} + +void GDScriptTest::enable_stdout() { + // TODO: this could likely be handled by doctest or `tests/test_macros.h`. + OS::get_singleton()->set_stdout_enabled(true); + OS::get_singleton()->set_stderr_enabled(true); +} + +void GDScriptTest::disable_stdout() { + // TODO: this could likely be handled by doctest or `tests/test_macros.h`. + OS::get_singleton()->set_stdout_enabled(false); + OS::get_singleton()->set_stderr_enabled(false); +} + +void GDScriptTest::print_handler(void *p_this, const String &p_message, bool p_error) { + TestResult *result = (TestResult *)p_this; + result->output += p_message + "\n"; +} + +void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type) { + ErrorHandlerData *data = (ErrorHandlerData *)p_this; + GDScriptTest *self = data->self; + TestResult *result = data->result; + + result->status = GDTEST_RUNTIME_ERROR; + + StringBuilder builder; + builder.append(">> "); + switch (p_type) { + case ERR_HANDLER_ERROR: + builder.append("ERROR"); + break; + case ERR_HANDLER_WARNING: + builder.append("WARNING"); + break; + case ERR_HANDLER_SCRIPT: + builder.append("SCRIPT ERROR"); + break; + case ERR_HANDLER_SHADER: + builder.append("SHADER ERROR"); + break; + default: + builder.append("Unknown error type"); + break; + } + + builder.append("\n>> on function: "); + builder.append(p_function); + builder.append("()\n>> "); + builder.append(String(p_file).trim_prefix(self->base_dir)); + builder.append("\n>> "); + builder.append(itos(p_line)); + builder.append("\n>> "); + builder.append(p_error); + if (strlen(p_explanation) > 0) { + builder.append("\n>> "); + builder.append(p_explanation); + } + builder.append("\n"); + + result->output = builder.as_string(); +} + +bool GDScriptTest::check_output(const String &p_output) const { + Error err = OK; + String expected = FileAccess::get_file_as_string(output_file, &err); + + ERR_FAIL_COND_V_MSG(err != OK, false, "Error when opening the output file."); + + String got = p_output.strip_edges(); // TODO: may be hacky. + got += "\n"; // Make sure to insert newline for CI static checks. + + return got == expected; +} + +String GDScriptTest::get_text_for_status(GDScriptTest::TestStatus p_status) const { + switch (p_status) { + case GDTEST_OK: + return "GDTEST_OK"; + case GDTEST_LOAD_ERROR: + return "GDTEST_LOAD_ERROR"; + case GDTEST_PARSER_ERROR: + return "GDTEST_PARSER_ERROR"; + case GDTEST_ANALYZER_ERROR: + return "GDTEST_ANALYZER_ERROR"; + case GDTEST_COMPILER_ERROR: + return "GDTEST_COMPILER_ERROR"; + case GDTEST_RUNTIME_ERROR: + return "GDTEST_RUNTIME_ERROR"; + } + return ""; +} + +GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { + disable_stdout(); + + TestResult result; + result.status = GDTEST_OK; + result.output = String(); + + Error err = OK; + + // Create script. + Ref<GDScript> script; + script.instantiate(); + script->set_path(source_file); + script->set_script_path(source_file); + err = script->load_source_code(source_file); + if (err != OK) { + enable_stdout(); + result.status = GDTEST_LOAD_ERROR; + result.passed = false; + ERR_FAIL_V_MSG(result, "\nCould not load source code for: '" + source_file + "'"); + } + + // Test parsing. + GDScriptParser parser; + err = parser.parse(script->get_source_code(), source_file, false); + if (err != OK) { + enable_stdout(); + result.status = GDTEST_PARSER_ERROR; + result.output = get_text_for_status(result.status) + "\n"; + + const List<GDScriptParser::ParserError> &errors = parser.get_errors(); + for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) { + result.output += E->get().message + "\n"; // TODO: line, column? + break; // Only the first error since the following might be cascading. + } + if (!p_is_generating) { + result.passed = check_output(result.output); + } + return result; + } + + // Test type-checking. + GDScriptAnalyzer analyzer(&parser); + err = analyzer.analyze(); + if (err != OK) { + enable_stdout(); + result.status = GDTEST_ANALYZER_ERROR; + result.output = get_text_for_status(result.status) + "\n"; + + const List<GDScriptParser::ParserError> &errors = parser.get_errors(); + for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) { + result.output += E->get().message + "\n"; // TODO: line, column? + break; // Only the first error since the following might be cascading. + } + if (!p_is_generating) { + result.passed = check_output(result.output); + } + return result; + } + + StringBuilder warning_string; + for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E != nullptr; E = E->next()) { + const GDScriptWarning warning = E->get(); + warning_string.append(">> WARNING"); + warning_string.append("\n>> Line: "); + warning_string.append(itos(warning.start_line)); + warning_string.append("\n>> "); + warning_string.append(warning.get_name()); + warning_string.append("\n>> "); + warning_string.append(warning.get_message()); + warning_string.append("\n"); + } + result.output += warning_string.as_string(); + + // Test compiling. + GDScriptCompiler compiler; + err = compiler.compile(&parser, script.ptr(), false); + if (err != OK) { + enable_stdout(); + result.status = GDTEST_COMPILER_ERROR; + result.output = get_text_for_status(result.status) + "\n"; + result.output = compiler.get_error(); + if (!p_is_generating) { + result.passed = check_output(result.output); + } + return result; + } + + // Test running. + const Map<StringName, GDScriptFunction *>::Element *test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name); + if (test_function_element == nullptr) { + enable_stdout(); + result.status = GDTEST_LOAD_ERROR; + result.output = ""; + result.passed = false; + ERR_FAIL_V_MSG(result, "\nCould not find test function on: '" + source_file + "'"); + } + + script->reload(); + + // Create object instance for test. + Object *obj = ClassDB::instantiate(script->get_native()->get_name()); + Ref<RefCounted> obj_ref; + if (obj->is_ref_counted()) { + obj_ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj)); + } + obj->set_script(script); + GDScriptInstance *instance = static_cast<GDScriptInstance *>(obj->get_script_instance()); + + // Setup output handlers. + ErrorHandlerData error_data(&result, this); + + _print_handler.userdata = &result; + _error_handler.userdata = &error_data; + add_print_handler(&_print_handler); + add_error_handler(&_error_handler); + + // Call test function. + Callable::CallError call_err; + instance->call(GDScriptTestRunner::test_function_name, nullptr, 0, call_err); + + // Tear down output handlers. + remove_print_handler(&_print_handler); + remove_error_handler(&_error_handler); + + // Check results. + if (call_err.error != Callable::CallError::CALL_OK) { + enable_stdout(); + result.status = GDTEST_LOAD_ERROR; + result.passed = false; + ERR_FAIL_V_MSG(result, "\nCould not call test function on: '" + source_file + "'"); + } + + result.output = get_text_for_status(result.status) + "\n" + result.output; + if (!p_is_generating) { + result.passed = check_output(result.output); + } + + if (obj_ref.is_null()) { + memdelete(obj); + } + + enable_stdout(); + return result; +} + +GDScriptTest::TestResult GDScriptTest::run_test() { + return execute_test_code(false); +} + +bool GDScriptTest::generate_output() { + TestResult result = execute_test_code(true); + if (result.status == GDTEST_LOAD_ERROR) { + return false; + } + + Error err = OK; + FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); + if (err != OK) { + return false; + } + + String output = result.output.strip_edges(); // TODO: may be hacky. + output += "\n"; // Make sure to insert newline for CI static checks. + + out_file->store_string(output); + out_file->close(); + + return true; +} + +} // namespace GDScriptTests diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h new file mode 100644 index 0000000000..9b2d14a371 --- /dev/null +++ b/modules/gdscript/tests/gdscript_test_runner.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* gdscript_test_runner.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 GDSCRIPT_TEST_H +#define GDSCRIPT_TEST_H + +#include "../gdscript.h" +#include "core/error/error_macros.h" +#include "core/string/print_string.h" +#include "core/string/ustring.h" +#include "core/templates/vector.h" + +namespace GDScriptTests { + +void init_autoloads(); +void init_language(const String &p_base_path); +void finish_language(); + +// Single test instance in a suite. +class GDScriptTest { +public: + enum TestStatus { + GDTEST_OK, + GDTEST_LOAD_ERROR, + GDTEST_PARSER_ERROR, + GDTEST_ANALYZER_ERROR, + GDTEST_COMPILER_ERROR, + GDTEST_RUNTIME_ERROR, + }; + + struct TestResult { + TestStatus status; + String output; + bool passed; + }; + +private: + struct ErrorHandlerData { + TestResult *result; + GDScriptTest *self; + ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) { + result = p_result; + self = p_this; + } + }; + + String source_file; + String output_file; + String base_dir; + + PrintHandlerList _print_handler; + ErrorHandlerList _error_handler; + + void enable_stdout(); + void disable_stdout(); + bool check_output(const String &p_output) const; + String get_text_for_status(TestStatus p_status) const; + + TestResult execute_test_code(bool p_is_generating); + +public: + static void print_handler(void *p_this, const String &p_message, bool p_error); + static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type); + TestResult run_test(); + bool generate_output(); + + const String &get_source_file() const { return source_file; } + const String &get_output_file() const { return output_file; } + + GDScriptTest(const String &p_source_path, const String &p_output_path, const String &p_base_dir); + GDScriptTest() : + GDScriptTest(String(), String(), String()) {} // Needed to use in Vector. +}; + +class GDScriptTestRunner { + String source_dir; + Vector<GDScriptTest> tests; + + bool is_generating = false; + bool do_init_languages = false; + + bool make_tests(); + bool make_tests_for_dir(const String &p_dir); + bool generate_class_index(); + +public: + static StringName test_function_name; + + static void handle_cmdline(); + int run_tests(); + bool generate_outputs(); + + GDScriptTestRunner(const String &p_source_dir, bool p_init_language); + ~GDScriptTestRunner(); +}; + +} // namespace GDScriptTests + +#endif // GDSCRIPT_TEST_H diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h new file mode 100644 index 0000000000..cf4e61f07d --- /dev/null +++ b/modules/gdscript/tests/gdscript_test_runner_suite.h @@ -0,0 +1,74 @@ +/*************************************************************************/ +/* gdscript_test_runner_suite.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 GDSCRIPT_TEST_RUNNER_SUITE_H +#define GDSCRIPT_TEST_RUNNER_SUITE_H + +#include "gdscript_test_runner.h" +#include "tests/test_macros.h" + +namespace GDScriptTests { + +TEST_SUITE("[Modules][GDScript]") { + // GDScript 2.0 is still under heavy construction. + // Allow the tests to fail, but do not ignore errors during development. + // Update the scripts and expected output as needed. + TEST_CASE("Script compilation and runtime") { + GDScriptTestRunner runner("modules/gdscript/tests/scripts", true); + int fail_count = runner.run_tests(); + INFO("Make sure `*.out` files have expected results."); + REQUIRE_MESSAGE(fail_count == 0, "All GDScript tests should pass."); + } +} + +TEST_CASE("[Modules][GDScript] Load source code dynamically and run it") { + Ref<GDScript> gdscript = memnew(GDScript); + gdscript->set_source_code(R"( +extends RefCounted + +func _init(): + set_meta("result", 42) +)"); + // A spurious `Condition "err" is true` message is printed (despite parsing being successful and returning `OK`). + // Silence it. + ERR_PRINT_OFF; + const Error error = gdscript->reload(); + ERR_PRINT_ON; + CHECK_MESSAGE(error == OK, "The script should parse successfully."); + + // Run the script by assigning it to a reference-counted object. + Ref<RefCounted> ref_counted = memnew(RefCounted); + ref_counted->set_script(gdscript); + CHECK_MESSAGE(int(ref_counted->get_meta("result")) == 42, "The script should assign object metadata successfully."); +} + +} // namespace GDScriptTests + +#endif // GDSCRIPT_TEST_RUNNER_SUITE_H diff --git a/modules/gdscript/tests/scripts/.gitignore b/modules/gdscript/tests/scripts/.gitignore new file mode 100644 index 0000000000..94c5b1bf6b --- /dev/null +++ b/modules/gdscript/tests/scripts/.gitignore @@ -0,0 +1,2 @@ +# Ignore metadata if someone open this on Godot. +/.godot diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd new file mode 100644 index 0000000000..d21d8bce96 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd @@ -0,0 +1,9 @@ +extends Node + +func test(): + set_name("TestNodeName") + if get_name() == &"TestNodeName": + print("Name is equal") + else: + print("Name is not equal") + print(get_name() is StringName) diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out new file mode 100644 index 0000000000..dc4348d9c3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out @@ -0,0 +1,3 @@ +GDTEST_OK +Name is equal +True diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd new file mode 100644 index 0000000000..c56ad94095 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd @@ -0,0 +1,6 @@ +func args(a, b): + print(a) + print(b) + +func test(): + args(1,) diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.out b/modules/gdscript/tests/scripts/parser/errors/missing_argument.out new file mode 100644 index 0000000000..fc2a891109 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_argument.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Too few arguments for "args()" call. Expected at least 2 but received 1. diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd new file mode 100644 index 0000000000..a1077e1985 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd @@ -0,0 +1,2 @@ +func test(): + var a = ("missing paren ->" diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out new file mode 100644 index 0000000000..7326afa33d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected closing ")" after grouping expression. diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd new file mode 100644 index 0000000000..62cb633e9e --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd @@ -0,0 +1,3 @@ +func test(): + if true # Missing colon here. + print("true") diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_colon.out b/modules/gdscript/tests/scripts/parser/errors/missing_colon.out new file mode 100644 index 0000000000..687b963bc8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected ":" after "if" condition. diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd new file mode 100644 index 0000000000..116b0151da --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd @@ -0,0 +1,6 @@ +func args(a, b): + print(a) + print(b) + +func test(): + args(1,2 diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out new file mode 100644 index 0000000000..34ea7ac323 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected closing ")" after call arguments. diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd new file mode 100644 index 0000000000..9ad77f1432 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd @@ -0,0 +1,3 @@ +func test(): + print("Using spaces") + print("Using tabs") diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out new file mode 100644 index 0000000000..6390de9788 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Used "\t" for indentation instead " " as used before in the file. diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd new file mode 100644 index 0000000000..3875ce3936 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd @@ -0,0 +1,3 @@ +extends Node +func test(): + var a = $ # Expected some node path. diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out new file mode 100644 index 0000000000..b3dc181a22 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expect node path as string or identifier after "$". diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd new file mode 100644 index 0000000000..6fd2692d47 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd @@ -0,0 +1,3 @@ +extends Node +func test(): + $23 # Can't use number here. diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out new file mode 100644 index 0000000000..b3dc181a22 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expect node path as string or identifier after "$". diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd new file mode 100644 index 0000000000..1836d42226 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd @@ -0,0 +1,3 @@ +extends Node +func test(): + $MyNode/23 # Can't use number here. diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out new file mode 100644 index 0000000000..dcb4ccecb0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expect node path after "/". diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd new file mode 100644 index 0000000000..08f2eedb2d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd @@ -0,0 +1,2 @@ +func test(): + print("A"); print("B") diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out new file mode 100644 index 0000000000..fc03f3efe8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out @@ -0,0 +1,3 @@ +GDTEST_OK +A +B diff --git a/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd new file mode 100644 index 0000000000..6097b11b10 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd @@ -0,0 +1,7 @@ +# See https://github.com/godotengine/godot/issues/41066. + +func f(p, ): ## <-- no errors + print(p) + +func test(): + f(0, ) ## <-- no error diff --git a/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out new file mode 100644 index 0000000000..94e2ec2af8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out @@ -0,0 +1,2 @@ +GDTEST_OK +0 diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd new file mode 100644 index 0000000000..3b48f10ca7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd @@ -0,0 +1,12 @@ +var a # No init. +var b = 42 # Init. + +func test(): + var c # No init, local. + var d = 23 # Init, local. + + a = 1 + c = 2 + + prints(a, b, c, d) + print("OK") diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.out b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out new file mode 100644 index 0000000000..2e0a63c024 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out @@ -0,0 +1,7 @@ +GDTEST_OK +>> WARNING +>> Line: 5 +>> UNASSIGNED_VARIABLE +>> The variable 'c' was used but never assigned a value. +1 42 2 23 +OK diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd new file mode 100644 index 0000000000..68e3bd424f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd @@ -0,0 +1,2 @@ +func test(): + var unused = "not used" diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out new file mode 100644 index 0000000000..270e0e69c0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 2 +>> UNUSED_VARIABLE +>> The local variable 'unused' is declared but never used in the block. If this is intended, prefix it with an underscore: '_unused' diff --git a/modules/gdscript/tests/scripts/project.godot b/modules/gdscript/tests/scripts/project.godot new file mode 100644 index 0000000000..25b49c0abd --- /dev/null +++ b/modules/gdscript/tests/scripts/project.godot @@ -0,0 +1,10 @@ +; This is not an actual project. +; This config only exists to properly set up the test environment. +; It also helps for opening Godot to edit the scripts, but please don't +; let the editor changes be saved. + +config_version=4 + +[application] + +config/name="GDScript Integration Test Suite" diff --git a/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd new file mode 100644 index 0000000000..10780b5379 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd @@ -0,0 +1,5 @@ +func test(): + var node := Node.new() + var inside_tree = node.is_inside_tree + node.free() + inside_tree.call() diff --git a/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out new file mode 100644 index 0000000000..e585c374e2 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/callable_call_after_free_object.gd +>> 5 +>> Attempt to call function 'null::is_inside_tree (Callable)' on a null instance. diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 3cc0eee672..7aa5895981 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -31,8 +31,8 @@ #include "test_gdscript.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "core/os/file_access.h" #include "core/os/main_loop.h" #include "core/os/os.h" #include "core/string/string_builder.h" @@ -47,7 +47,7 @@ #include "editor/editor_settings.h" #endif -namespace TestGDScript { +namespace GDScriptTests { static void test_tokenizer(const String &p_code, const Vector<String> &p_lines) { GDScriptTokenizer tokenizer; @@ -66,7 +66,7 @@ static void test_tokenizer(const String &p_code, const Vector<String> &p_lines) StringBuilder token; token += " --> "; // Padding for line number. - for (int l = current.start_line; l <= current.end_line; l++) { + for (int l = current.start_line; l <= current.end_line && l <= p_lines.size(); l++) { print_line(vformat("%04d %s", l, p_lines[l - 1]).replace("\t", tab)); } @@ -118,6 +118,18 @@ static void test_parser(const String &p_code, const String &p_script_path, const print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } } + + GDScriptAnalyzer analyzer(&parser); + analyzer.analyze(); + + if (err != OK) { + const List<GDScriptParser::ParserError> &errors = parser.get_errors(); + for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { + const GDScriptParser::ParserError &error = E->get(); + print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); + } + } + #ifdef TOOLS_ENABLED GDScriptParser::TreePrinter printer; printer.print_tree(parser); @@ -153,7 +165,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con GDScriptCompiler compiler; Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(p_script_path); err = compiler.compile(&parser, script.ptr(), false); @@ -183,60 +195,6 @@ static void test_compiler(const String &p_code, const String &p_script_path, con } } -void init_autoloads() { - Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - - // First pass, add the constants so they exist before any script is loaded. - for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { - const ProjectSettings::AutoloadInfo &info = E->get(); - - if (info.is_singleton) { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_global_constant(info.name, Variant()); - } - } - } - - // Second pass, load into global constants. - for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { - const ProjectSettings::AutoloadInfo &info = E->get(); - - if (!info.is_singleton) { - // Skip non-singletons since we don't have a scene tree here anyway. - continue; - } - - RES res = ResourceLoader::load(info.path); - ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path); - Node *n = nullptr; - if (res->is_class("PackedScene")) { - Ref<PackedScene> ps = res; - n = ps->instance(); - } else if (res->is_class("Script")) { - Ref<Script> script_res = res; - StringName ibt = script_res->get_instance_base_type(); - bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); - - Object *obj = ClassDB::instance(ibt); - - ERR_CONTINUE_MSG(obj == nullptr, - "Cannot instance script for autoload, expected 'Node' inheritance, got: " + - String(ibt)); - - n = Object::cast_to<Node>(obj); - n->set_script(script_res); - } - - ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path); - n->set_name(info.name); - - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_global_constant(info.name, n); - } - } -} - void test(TestType p_type) { List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); @@ -253,24 +211,12 @@ void test(TestType p_type) { FileAccessRef fa = FileAccess::open(test, FileAccess::READ); ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test); - // Init PackedData since it's used by ProjectSettings. - PackedData *packed_data = memnew(PackedData); - - // Setup project settings since it's needed by the languages to get the global scripts. - // This also sets up the base resource path. - Error err = ProjectSettings::get_singleton()->setup(fa->get_path_absolute().get_base_dir(), String(), true); - if (err) { - print_line("Could not load project settings."); - // Keep going since some scripts still work without this. - } - // Initialize the language for the test routine. - ScriptServer::init_languages(); - init_autoloads(); + init_language(fa->get_path_absolute().get_base_dir()); Vector<uint8_t> buf; - int flen = fa->get_len(); - buf.resize(fa->get_len() + 1); + uint64_t flen = fa->get_length(); + buf.resize(flen + 1); fa->get_buffer(buf.ptrw(), flen); buf.write[flen] = 0; @@ -300,8 +246,6 @@ void test(TestType p_type) { print_line("Not implemented."); } - // Destroy stuff we set up earlier. - ScriptServer::finish_languages(); - memdelete(packed_data); + finish_language(); } -} // namespace TestGDScript +} // namespace GDScriptTests diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h index bbda46cdad..c7ee5a2208 100644 --- a/modules/gdscript/tests/test_gdscript.h +++ b/modules/gdscript/tests/test_gdscript.h @@ -31,7 +31,10 @@ #ifndef TEST_GDSCRIPT_H #define TEST_GDSCRIPT_H -namespace TestGDScript { +#include "gdscript_test_runner.h" +#include "tests/test_macros.h" + +namespace GDScriptTests { enum TestType { TEST_TOKENIZER, @@ -41,6 +44,7 @@ enum TestType { }; void test(TestType p_type); -} // namespace TestGDScript + +} // namespace GDScriptTests #endif // TEST_GDSCRIPT_H diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index 545aa68747..730c6b89f7 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -37,7 +37,7 @@ #include <glslang/Include/Types.h> #include <glslang/Public/ShaderLang.h> -static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error) { +static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice::Capabilities *p_capabilities) { Vector<uint8_t> ret; ERR_FAIL_COND_V(p_language == RenderingDevice::SHADER_LANGUAGE_HLSL, ret); @@ -51,20 +51,79 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage }; int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 + bool check_subgroup_support = true; // assume we support subgroups - glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0; - glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_3; + glslang::EShTargetClientVersion ClientVersion = glslang::EShTargetVulkan_1_2; + glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5; glslang::TShader::ForbidIncluder includer; + if (p_capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) { + if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 0) { + ClientVersion = glslang::EShTargetVulkan_1_0; + TargetVersion = glslang::EShTargetSpv_1_0; + check_subgroup_support = false; // subgroups are not supported in Vulkan 1.0 + } else if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 1) { + ClientVersion = glslang::EShTargetVulkan_1_1; + TargetVersion = glslang::EShTargetSpv_1_3; + } else { + // use defaults + } + } else { + // once we support other backends we'll need to do something here + if (r_error) { + (*r_error) = "GLSLANG - Unsupported device family"; + } + return ret; + } + glslang::TShader shader(stages[p_stage]); CharString cs = p_source_code.ascii(); const char *cs_strings = cs.get_data(); + std::string preamble = ""; shader.setStrings(&cs_strings, 1); shader.setEnvInput(glslang::EShSourceGlsl, stages[p_stage], glslang::EShClientVulkan, ClientInputSemanticsVersion); - shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); + shader.setEnvClient(glslang::EShClientVulkan, ClientVersion); shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion); + if (check_subgroup_support) { + uint32_t stage_bit = 1 << p_stage; + + if ((p_capabilities->subgroup_in_shaders & stage_bit) == stage_bit) { + // stage supports subgroups + preamble += "#define has_GL_KHR_shader_subgroup_basic 1\n"; + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_VOTE_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_vote 1\n"; + } + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_ARITHMETIC_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_arithmetic 1\n"; + } + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_BALLOT_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_ballot 1\n"; + } + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_shuffle 1\n"; + } + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_RELATIVE_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_shuffle_relative 1\n"; + } + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_CLUSTERED_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_clustered 1\n"; + } + if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_QUAD_BIT) { + preamble += "#define has_GL_KHR_shader_subgroup_quad 1\n"; + } + } + } + + if (p_capabilities->supports_multiview) { + preamble += "#define has_VK_KHR_multiview 1\n"; + } + + if (preamble != "") { + shader.setPreamble(preamble.c_str()); + } + EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); const int DefaultVersion = 100; std::string pre_processed_code; @@ -118,17 +177,24 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage ret.resize(SpirV.size() * sizeof(uint32_t)); { uint8_t *w = ret.ptrw(); - copymem(w, &SpirV[0], SpirV.size() * sizeof(uint32_t)); + memcpy(w, &SpirV[0], SpirV.size() * sizeof(uint32_t)); } return ret; } +static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities *p_capabilities) { + String version; + version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(p_capabilities->version_major) + ", minor=" + itos(p_capabilities->version_minor) + " , subgroup_size=" + itos(p_capabilities->subgroup_operations) + " , subgroup_ops=" + itos(p_capabilities->subgroup_operations) + " , subgroup_in_shaders=" + itos(p_capabilities->subgroup_in_shaders); + return version; +} + void preregister_glslang_types() { // initialize in case it's not initialized. This is done once per thread // and it's safe to call multiple times glslang::InitializeProcess(); RenderingDevice::shader_set_compile_function(_compile_shader_glsl); + RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl); } void register_glslang_types() { diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index a1f596f7dd..41a318ce19 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -17,9 +17,9 @@ </member> <member name="count" type="int" setter="set_count" getter="get_count" default="0"> </member> - <member name="max" type="PackedFloat64Array" setter="set_max" getter="get_max" default="PackedFloat64Array( )"> + <member name="max" type="PackedFloat64Array" setter="set_max" getter="get_max" default="PackedFloat64Array()"> </member> - <member name="min" type="PackedFloat64Array" setter="set_min" getter="get_min" default="PackedFloat64Array( )"> + <member name="min" type="PackedFloat64Array" setter="set_min" getter="get_min" default="PackedFloat64Array()"> </member> <member name="normalized" type="bool" setter="set_normalized" getter="get_normalized" default="false"> </member> diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index bfeaf9a86e..f51d287685 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> </member> <member name="inner_cone_angle" type="float" setter="set_inner_cone_angle" getter="get_inner_cone_angle" default="0.0"> </member> diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index 55f79d2c55..fd7e4a169e 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array( )"> + <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> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index 5b7d4fadec..bfbb12df4d 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -11,9 +11,7 @@ <members> <member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1"> </member> - <member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array( )"> - </member> - <member name="fake_joint_parent" type="int" setter="set_fake_joint_parent" getter="get_fake_joint_parent" default="-1"> + <member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array()"> </member> <member name="height" type="int" setter="set_height" getter="get_height" default="-1"> </member> @@ -25,17 +23,17 @@ </member> <member name="parent" type="int" setter="set_parent" getter="get_parent" default="-1"> </member> - <member name="rotation" type="Quat" setter="set_rotation" getter="get_rotation" default="Quat( 0, 0, 0, 1 )"> + <member name="rotation" type="Quaternion" setter="set_rotation" getter="get_rotation" default="Quaternion(0, 0, 0, 1)"> </member> - <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3( 1, 1, 1 )"> + <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)"> </member> <member name="skeleton" type="int" setter="set_skeleton" getter="get_skeleton" default="-1"> </member> <member name="skin" type="int" setter="set_skin" getter="get_skin" default="-1"> </member> - <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3( 0, 0, 0 )"> + <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3(0, 0, 0)"> </member> - <member name="xform" type="Transform" setter="set_xform" getter="get_xform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="xform" type="Transform3D" setter="set_xform" getter="get_xform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> </member> </members> <constants> diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml index 9680c27705..40563c9ac6 100644 --- a/modules/gltf/doc_classes/GLTFSkeleton.xml +++ b/modules/gltf/doc_classes/GLTFSkeleton.xml @@ -57,9 +57,9 @@ </method> </methods> <members> - <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array( )"> + <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array()"> </member> - <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array( )"> + <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array()"> </member> </members> <constants> diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml index 5a80c7097a..e20e127e52 100644 --- a/modules/gltf/doc_classes/GLTFSkin.xml +++ b/modules/gltf/doc_classes/GLTFSkin.xml @@ -53,13 +53,13 @@ <members> <member name="godot_skin" type="Skin" setter="set_godot_skin" getter="get_godot_skin"> </member> - <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array( )"> + <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array()"> </member> - <member name="joints_original" type="PackedInt32Array" setter="set_joints_original" getter="get_joints_original" default="PackedInt32Array( )"> + <member name="joints_original" type="PackedInt32Array" setter="set_joints_original" getter="get_joints_original" default="PackedInt32Array()"> </member> - <member name="non_joints" type="PackedInt32Array" setter="set_non_joints" getter="get_non_joints" default="PackedInt32Array( )"> + <member name="non_joints" type="PackedInt32Array" setter="set_non_joints" getter="get_non_joints" default="PackedInt32Array()"> </member> - <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array( )"> + <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array()"> </member> <member name="skeleton" type="int" setter="set_skeleton" getter="get_skeleton" default="-1"> </member> diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml index 68cc7c845d..6e9c419649 100644 --- a/modules/gltf/doc_classes/GLTFSpecGloss.xml +++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color( 1, 1, 1, 1 )"> + <member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color(1, 1, 1, 1)"> </member> <member name="diffuse_img" type="Image" setter="set_diffuse_img" getter="get_diffuse_img"> </member> @@ -17,7 +17,7 @@ </member> <member name="spec_gloss_img" type="Image" setter="set_spec_gloss_img" getter="get_spec_gloss_img"> </member> - <member name="specular_factor" type="Color" setter="set_specular_factor" getter="get_specular_factor" default="Color( 1, 1, 1, 1 )"> + <member name="specular_factor" type="Color" setter="set_specular_factor" getter="get_specular_factor" default="Color(1, 1, 1, 1)"> </member> </members> <constants> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 8255cd73d0..a7b5b7b43e 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -243,9 +243,9 @@ </method> </methods> <members> - <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[ ]"> + <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[]"> </member> - <member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray( )"> + <member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()"> </member> <member name="json" type="Dictionary" setter="set_json" getter="get_json" default="{}"> </member> @@ -253,7 +253,7 @@ </member> <member name="minor_version" type="int" setter="set_minor_version" getter="get_minor_version" default="0"> </member> - <member name="root_nodes" type="Array" setter="set_root_nodes" getter="get_root_nodes" default="[ ]"> + <member name="root_nodes" type="Array" setter="set_root_nodes" getter="get_root_nodes" default="[]"> </member> <member name="scene_name" type="String" setter="set_scene_name" getter="get_scene_name" default=""""> </member> diff --git a/modules/gltf/doc_classes/PackedSceneGLTF.xml b/modules/gltf/doc_classes/PackedSceneGLTF.xml index a04c6ef0b6..a22111e9b7 100644 --- a/modules/gltf/doc_classes/PackedSceneGLTF.xml +++ b/modules/gltf/doc_classes/PackedSceneGLTF.xml @@ -51,7 +51,7 @@ </method> </methods> <members> - <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" override="true" default="{"conn_count": 0,"conns": PackedInt32Array( ),"editable_instances": [ ],"names": PackedStringArray( ),"node_count": 0,"node_paths": [ ],"nodes": PackedInt32Array( ),"variants": [ ],"version": 2}" /> + <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" override="true" default="{"conn_count": 0,"conns": PackedInt32Array(),"editable_instances": [],"names": PackedStringArray(),"node_count": 0,"node_paths": [],"nodes": PackedInt32Array(),"variants": [],"version": 2}" /> </members> <constants> </constants> diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp index 4cdaccde6f..ae080bcc9a 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp @@ -49,7 +49,7 @@ bool SceneExporterGLTFPlugin::has_main_screen() const { SceneExporterGLTFPlugin::SceneExporterGLTFPlugin(EditorNode *p_node) { editor = p_node; - convert_gltf2.instance(); + convert_gltf2.instantiate(); file_export_lib = memnew(EditorFileDialog); editor->get_gui_base()->add_child(file_export_lib); file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action)); diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp index 35f44ca122..eca1c85bf3 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor_scene_importer_gltf.cpp @@ -28,23 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/crypto/crypto_core.h" -#include "core/io/json.h" -#include "core/math/disjoint_set.h" -#include "core/math/math_defs.h" -#include "core/os/file_access.h" -#include "core/os/os.h" -#include "editor/import/resource_importer_scene.h" -#include "modules/gltf/gltf_state.h" -#include "modules/regex/regex.h" -#include "scene/3d/bone_attachment_3d.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/packed_scene.h" -#include "scene/resources/surface_tool.h" +#include "editor_scene_importer_gltf.h" + +#include "gltf_document.h" +#include "gltf_state.h" -#include "modules/gltf/editor_scene_importer_gltf.h" +#include "scene/3d/node_3d.h" +#include "scene/animation/animation_player.h" +#include "scene/resources/animation.h" uint32_t EditorSceneImporterGLTF::get_import_flags() const { return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; @@ -60,7 +51,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, List<String> *r_missing_deps, Error *r_err) { Ref<PackedSceneGLTF> importer; - importer.instance(); + importer.instantiate(); return importer->import_scene(p_path, p_flags, p_bake_fps, r_missing_deps, r_err, Ref<GLTFState>()); } @@ -91,13 +82,13 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags, Error *r_err, Ref<GLTFState> r_state) { if (r_state == Ref<GLTFState>()) { - r_state.instance(); + r_state.instantiate(); } r_state->use_named_skin_binds = p_flags & EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS; Ref<GLTFDocument> gltf_document; - gltf_document.instance(); + gltf_document.instantiate(); Error err = gltf_document->parse(r_state, p_path); if (r_err) { *r_err = err; @@ -139,9 +130,9 @@ void PackedSceneGLTF::save_scene(Node *p_node, const String &p_path, *r_err = err; } Ref<GLTFDocument> gltf_document; - gltf_document.instance(); + gltf_document.instantiate(); Ref<GLTFState> state; - state.instance(); + state.instantiate(); err = gltf_document->serialize(state, p_node, p_path); if (r_err) { *r_err = err; @@ -172,7 +163,7 @@ Error PackedSceneGLTF::export_gltf(Node *p_root, String p_path, int32_t flags = p_flags; real_t baked_fps = p_bake_fps; Ref<PackedSceneGLTF> exporter; - exporter.instance(); + exporter.instantiate(); exporter->save_scene(p_root, path, "", flags, baked_fps, &deps, &err); int32_t error_code = err; if (error_code != 0) { diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h index db961e591d..7bc5f594ed 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor_scene_importer_gltf.h @@ -31,29 +31,13 @@ #ifndef EDITOR_SCENE_IMPORTER_GLTF_H #define EDITOR_SCENE_IMPORTER_GLTF_H -#include "core/config/project_settings.h" -#include "core/io/json.h" -#include "core/object/object.h" -#include "core/templates/vector.h" +#include "gltf_state.h" + #include "editor/import/resource_importer_scene.h" -#include "modules/csg/csg_shape.h" -#include "modules/gridmap/grid_map.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/multimesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/gui/check_box.h" #include "scene/main/node.h" #include "scene/resources/packed_scene.h" -#include "scene/resources/surface_tool.h" - -#include "gltf_document.h" -#include "gltf_state.h" -class AnimationPlayer; -class BoneAttachment; -class EditorSceneImporterMeshNode3D; +class Animation; #ifdef TOOLS_ENABLED class EditorSceneImporterGLTF : public EditorSceneImporter { @@ -64,8 +48,8 @@ public: virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, - List<String> *r_missing_deps = NULL, - Error *r_err = NULL) override; + List<String> *r_missing_deps = nullptr, + Error *r_err = nullptr) override; virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; }; @@ -80,7 +64,7 @@ protected: public: virtual void save_scene(Node *p_node, const String &p_path, const String &p_src_path, uint32_t p_flags, int p_bake_fps, - List<String> *r_missing_deps, Error *r_err = NULL); + List<String> *r_missing_deps, Error *r_err = nullptr); virtual void _build_parent_hierachy(Ref<GLTFState> state); virtual Error export_gltf(Node *p_root, String p_path, int32_t p_flags = 0, real_t p_bake_fps = 1000.0f); diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h index a494e6bd67..216d2161c4 100644 --- a/modules/gltf/gltf_animation.h +++ b/modules/gltf/gltf_animation.h @@ -56,7 +56,7 @@ public: struct Track { Channel<Vector3> translation_track; - Channel<Quat> rotation_track; + Channel<Quaternion> rotation_track; Channel<Vector3> scale_track; Vector<Channel<float>> weight_tracks; }; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index d6e67a78d7..71a9b3667f 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -29,9 +29,7 @@ /*************************************************************************/ #include "gltf_document.h" -#include "core/error/error_list.h" -#include "core/error/error_macros.h" -#include "core/variant/variant.h" + #include "gltf_accessor.h" #include "gltf_animation.h" #include "gltf_camera.h" @@ -44,35 +42,33 @@ #include "gltf_state.h" #include "gltf_texture.h" -#include <stdio.h> -#include <stdlib.h> - -#include "core/core_bind.h" #include "core/crypto/crypto_core.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/json.h" #include "core/math/disjoint_set.h" -#include "core/os/file_access.h" #include "core/variant/typed_array.h" +#include "core/variant/variant.h" #include "core/version.h" #include "core/version_hash.gen.h" #include "drivers/png/png_driver_common.h" #include "editor/import/resource_importer_scene.h" +#include "scene/2d/node_2d.h" +#include "scene/3d/camera_3d.h" +#include "scene/3d/multimesh_instance_3d.h" +#include "scene/animation/animation_player.h" +#include "scene/resources/surface_tool.h" + +#include "modules/modules_enabled.gen.h" #ifdef MODULE_CSG_ENABLED #include "modules/csg/csg_shape.h" #endif // MODULE_CSG_ENABLED #ifdef MODULE_GRIDMAP_ENABLED #include "modules/gridmap/grid_map.h" #endif // MODULE_GRIDMAP_ENABLED -#include "scene/2d/node_2d.h" -#include "scene/3d/bone_attachment_3d.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/multimesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/main/node.h" -#include "scene/resources/surface_tool.h" + +#include <stdio.h> +#include <stdlib.h> #include <limits> Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &p_path) { @@ -233,20 +229,18 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { } Vector<uint8_t> array; - array.resize(f->get_len()); + array.resize(f->get_length()); f->get_buffer(array.ptrw(), array.size()); String text; text.parse_utf8((const char *)array.ptr(), array.size()); - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); + _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT); return err; } - state->json = v; + state->json = json.get_data(); return OK; } @@ -299,16 +293,14 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { String text; text.parse_utf8((const char *)json_data.ptr(), json_data.size()); - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); + _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT); return err; } - state->json = v; + state->json = json.get_data(); //data? @@ -342,25 +334,25 @@ static Vector3 _arr_to_vec3(const Array &p_array) { return Vector3(p_array[0], p_array[1], p_array[2]); } -static Array _quat_to_array(const Quat &p_quat) { +static Array _quaternion_to_array(const Quaternion &p_quaternion) { Array array; array.resize(4); - array[0] = p_quat.x; - array[1] = p_quat.y; - array[2] = p_quat.z; - array[3] = p_quat.w; + array[0] = p_quaternion.x; + array[1] = p_quaternion.y; + array[2] = p_quaternion.z; + array[3] = p_quaternion.w; return array; } -static Quat _arr_to_quat(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 4, Quat()); - return Quat(p_array[0], p_array[1], p_array[2], p_array[3]); +static Quaternion _arr_to_quaternion(const Array &p_array) { + ERR_FAIL_COND_V(p_array.size() != 4, Quaternion()); + return Quaternion(p_array[0], p_array[1], p_array[2], p_array[3]); } -static Transform _arr_to_xform(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 16, Transform()); +static Transform3D _arr_to_xform(const Array &p_array) { + ERR_FAIL_COND_V(p_array.size() != 16, Transform3D()); - Transform xform; + Transform3D xform; xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2])); xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6])); xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10])); @@ -369,7 +361,7 @@ static Transform _arr_to_xform(const Array &p_array) { return xform; } -static Vector<real_t> _xform_to_array(const Transform p_transform) { +static Vector<real_t> _xform_to_array(const Transform3D p_transform) { Vector<real_t> array; array.resize(16); Vector3 axis_x = p_transform.get_basis().get_axis(Vector3::AXIS_X); @@ -421,12 +413,12 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { } if (n->skeleton != -1 && n->skin < 0) { } - if (n->xform != Transform()) { + if (n->xform != Transform3D()) { node["matrix"] = _xform_to_array(n->xform); } - if (!n->rotation.is_equal_approx(Quat())) { - node["rotation"] = _quat_to_array(n->rotation); + if (!n->rotation.is_equal_approx(Quaternion())) { + node["rotation"] = _quaternion_to_array(n->rotation); } if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { @@ -569,7 +561,7 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { const Array &nodes = state->json["nodes"]; for (int i = 0; i < nodes.size(); i++) { Ref<GLTFNode> node; - node.instance(); + node.instantiate(); const Dictionary &n = nodes[i]; if (n.has("name")) { @@ -591,13 +583,13 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { node->translation = _arr_to_vec3(n["translation"]); } if (n.has("rotation")) { - node->rotation = _arr_to_quat(n["rotation"]); + node->rotation = _arr_to_quaternion(n["rotation"]); } if (n.has("scale")) { node->scale = _arr_to_vec3(n["scale"]); } - node->xform.basis.set_quat_scale(node->rotation, node->scale); + node->xform.basis.set_quaternion_scale(node->rotation, node->scale); node->xform.origin = node->translation; } @@ -664,7 +656,7 @@ static Vector<uint8_t> _parse_base64_uri(const String &uri) { int start = uri.find(","); ERR_FAIL_COND_V(start == -1, Vector<uint8_t>()); - CharString substr = uri.right(start + 1).ascii(); + CharString substr = uri.substr(start + 1).ascii(); int strlen = substr.length(); @@ -830,7 +822,7 @@ Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) { const Dictionary &d = buffers[i]; Ref<GLTFBufferView> buffer_view; - buffer_view.instance(); + buffer_view.instantiate(); ERR_FAIL_COND_V(!d.has("buffer"), ERR_PARSE_ERROR); buffer_view->buffer = d["buffer"]; @@ -940,22 +932,29 @@ String GLTFDocument::_get_accessor_type_name(const GLTFDocument::GLTFType p_type } GLTFDocument::GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { - if (p_string == "SCALAR") + if (p_string == "SCALAR") { return GLTFDocument::TYPE_SCALAR; + } - if (p_string == "VEC2") + if (p_string == "VEC2") { return GLTFDocument::TYPE_VEC2; - if (p_string == "VEC3") + } + if (p_string == "VEC3") { return GLTFDocument::TYPE_VEC3; - if (p_string == "VEC4") + } + if (p_string == "VEC4") { return GLTFDocument::TYPE_VEC4; + } - if (p_string == "MAT2") + if (p_string == "MAT2") { return GLTFDocument::TYPE_MAT2; - if (p_string == "MAT3") + } + if (p_string == "MAT3") { return GLTFDocument::TYPE_MAT3; - if (p_string == "MAT4") + } + if (p_string == "MAT4") { return GLTFDocument::TYPE_MAT4; + } ERR_FAIL_V(GLTFDocument::TYPE_SCALAR); } @@ -969,7 +968,7 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) { const Dictionary &d = accessors[i]; Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR); accessor->component_type = d["componentType"]; @@ -1111,7 +1110,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } Ref<GLTFBufferView> bv; - bv.instance(); + bv.instantiate(); const uint32_t offset = bv->byte_offset = byte_offset; Vector<uint8_t> &gltf_buffer = state->buffers.write[0]; @@ -1150,7 +1149,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } int64_t old_size = gltf_buffer.size(); gltf_buffer.resize(old_size + (buffer.size() * sizeof(int8_t))); - copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t)); + memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t)); bv->byte_length = buffer.size() * sizeof(int8_t); } break; case COMPONENT_TYPE_UNSIGNED_BYTE: { @@ -1196,7 +1195,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } int64_t old_size = gltf_buffer.size(); gltf_buffer.resize(old_size + (buffer.size() * sizeof(int16_t))); - copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t)); + memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t)); bv->byte_length = buffer.size() * sizeof(int16_t); } break; case COMPONENT_TYPE_UNSIGNED_SHORT: { @@ -1220,7 +1219,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } int64_t old_size = gltf_buffer.size(); gltf_buffer.resize(old_size + (buffer.size() * sizeof(uint16_t))); - copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t)); + memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t)); bv->byte_length = buffer.size() * sizeof(uint16_t); } break; case COMPONENT_TYPE_INT: { @@ -1240,7 +1239,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } int64_t old_size = gltf_buffer.size(); gltf_buffer.resize(old_size + (buffer.size() * sizeof(int32_t))); - copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t)); + memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t)); bv->byte_length = buffer.size() * sizeof(int32_t); } break; case COMPONENT_TYPE_FLOAT: { @@ -1260,7 +1259,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } int64_t old_size = gltf_buffer.size(); gltf_buffer.resize(old_size + (buffer.size() * sizeof(float))); - copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float)); + memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float)); bv->byte_length = buffer.size() * sizeof(float); } break; } @@ -1434,8 +1433,9 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc ERR_FAIL_INDEX_V(a->buffer_view, state->buffer_views.size(), Vector<double>()); const Error err = _decode_buffer_view(state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex); - if (err != OK) + if (err != OK) { return Vector<double>(); + } } else { //fill with zeros, as bufferview is not defined. for (int i = 0; i < (a->count * component_count); i++) { @@ -1450,14 +1450,16 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type); Error err = _decode_buffer_view(state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false); - if (err != OK) + if (err != OK) { return Vector<double>(); + } Vector<double> data; data.resize(component_count * a->sparse_count); err = _decode_buffer_view(state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex); - if (err != OK) + if (err != OK) { return Vector<double>(); + } for (int i = 0; i < indices.size(); i++) { const int write_offset = int(indices[i]) * component_count; @@ -1502,7 +1504,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c ERR_FAIL_COND_V(attribs.size() == 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; @@ -1528,8 +1530,9 @@ Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const G const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<int> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } const double *attribs_ptr = attribs.ptr(); const int ret_size = attribs.size(); @@ -1546,8 +1549,9 @@ Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, con const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<float> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } const double *attribs_ptr = attribs.ptr(); const int ret_size = attribs.size(); @@ -1584,7 +1588,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC2; @@ -1633,7 +1637,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1698,7 +1702,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1745,7 +1749,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1767,7 +1771,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, return state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, const Vector<Quat> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1782,11 +1786,11 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, Vector<double> type_min; type_min.resize(element_count); for (int i = 0; i < p_attribs.size(); i++) { - Quat quat = p_attribs[i]; - attribs.write[(i * element_count) + 0] = Math::snapped(quat.x, CMP_NORMALIZE_TOLERANCE); - attribs.write[(i * element_count) + 1] = Math::snapped(quat.y, CMP_NORMALIZE_TOLERANCE); - attribs.write[(i * element_count) + 2] = Math::snapped(quat.z, CMP_NORMALIZE_TOLERANCE); - attribs.write[(i * element_count) + 3] = Math::snapped(quat.w, CMP_NORMALIZE_TOLERANCE); + Quaternion quaternion = p_attribs[i]; + attribs.write[(i * element_count) + 0] = Math::snapped(quaternion.x, CMP_NORMALIZE_TOLERANCE); + attribs.write[(i * element_count) + 1] = Math::snapped(quaternion.y, CMP_NORMALIZE_TOLERANCE); + attribs.write[(i * element_count) + 2] = Math::snapped(quaternion.z, CMP_NORMALIZE_TOLERANCE); + attribs.write[(i * element_count) + 3] = Math::snapped(quaternion.w, CMP_NORMALIZE_TOLERANCE); _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); } @@ -1794,7 +1798,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1820,8 +1824,9 @@ Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, con const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<Vector2> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret); const double *attribs_ptr = attribs.ptr(); @@ -1858,7 +1863,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, ERR_FAIL_COND_V(!attribs.size(), -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; @@ -1904,7 +1909,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC3; @@ -1926,7 +1931,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c return state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1940,7 +1945,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, Vector<double> type_min; type_min.resize(element_count); for (int i = 0; i < p_attribs.size(); i++) { - Transform attrib = p_attribs[i]; + Transform3D attrib = p_attribs[i]; Basis basis = attrib.get_basis(); Vector3 axis_0 = basis.get_axis(Vector3::AXIS_X); @@ -1972,7 +1977,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_MAT4; @@ -1998,8 +2003,9 @@ Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, con const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<Vector3> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret); const double *attribs_ptr = attribs.ptr(); @@ -2017,8 +2023,9 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<Color> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } const int type = state->accessors[p_accessor]->type; ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret); @@ -2038,12 +2045,13 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons } return ret; } -Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { +Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Quat> ret; + Vector<Quaternion> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); const double *attribs_ptr = attribs.ptr(); @@ -2051,7 +2059,7 @@ Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const ret.resize(ret_size); { for (int i = 0; i < ret_size; i++) { - ret.write[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); + ret.write[i] = Quaternion(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); } } return ret; @@ -2060,8 +2068,9 @@ Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> sta const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<Transform2D> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); ret.resize(attribs.size() / 4); @@ -2076,8 +2085,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); Vector<Basis> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); ret.resize(attribs.size() / 9); @@ -2089,12 +2099,13 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons return ret; } -Vector<Transform> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { +Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Transform> ret; + Vector<Transform3D> ret; - if (attribs.size() == 0) + if (attribs.size() == 0) { return ret; + } ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); ret.resize(attribs.size() / 16); @@ -2316,7 +2327,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { //generate indices because they need to be swapped for CW/CCW const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->create_from_triangle_arrays(array); st->index(); Vector<int32_t> generated_indices = st->commit_to_arrays()[Mesh::ARRAY_INDEX]; @@ -2370,9 +2381,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { for (int i = 0; i < ret_size; i++) { Color tangent; tangent.r = tarr[(i * 4) + 0]; - tangent.r = tarr[(i * 4) + 1]; - tangent.r = tarr[(i * 4) + 2]; - tangent.r = tarr[(i * 4) + 3]; + tangent.g = tarr[(i * 4) + 1]; + tangent.b = tarr[(i * 4) + 2]; + tangent.a = tarr[(i * 4) + 3]; } t["TANGENT"] = _encode_accessor_as_color(state, attribs, true); } @@ -2440,7 +2451,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Dictionary d = meshes[i]; Ref<GLTFMesh> mesh; - mesh.instance(); + mesh.instantiate(); bool has_vertex_color = false; ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR); @@ -2448,7 +2459,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; - import_mesh.instance(); + import_mesh.instantiate(); String mesh_name = "mesh"; if (d.has("name") && !String(d["name"]).is_empty()) { mesh_name = d["name"]; @@ -2633,11 +2644,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (generate_tangents) { //must generate mikktspace tangents.. ergh.. Ref<SurfaceTool> st; - st.instance(); + 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->create_from_triangle_arrays(array); st->generate_tangents(); array = st->commit_to_arrays(); } @@ -2752,11 +2763,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (generate_tangents) { Ref<SurfaceTool> st; - st.instance(); + 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->create_from_triangle_arrays(array_copy); st->deindex(); st->generate_tangents(); array_copy = st->commit_to_arrays(); @@ -2780,7 +2791,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } else if (has_vertex_color) { Ref<StandardMaterial3D> mat3d; - mat3d.instance(); + mat3d.instantiate(); mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); mat = mat3d; } @@ -2802,8 +2813,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } blend_weights.write[j] = weights[j]; } - mesh->set_blend_weights(blend_weights); } + mesh->set_blend_weights(blend_weights); mesh->set_mesh(import_mesh); state->meshes.push_back(mesh); @@ -2821,14 +2832,14 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path ERR_CONTINUE(state->images[i].is_null()); - Ref<Image> image = state->images[i]->get_data(); + Ref<Image> image = state->images[i]->get_image(); ERR_CONTINUE(image.is_null()); if (p_path.to_lower().ends_with("glb")) { GLTFBufferViewIndex bvi; Ref<GLTFBufferView> bv; - bv.instance(); + bv.instantiate(); const GLTFBufferIndex bi = 0; bv->buffer = bi; @@ -2838,14 +2849,14 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path Vector<uint8_t> buffer; Ref<ImageTexture> img_tex = image; if (img_tex.is_valid()) { - image = img_tex->get_data(); + image = img_tex->get_image(); } Error err = PNGDriverCommon::image_to_png(image, buffer); ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG."); bv->byte_length = buffer.size(); state->buffers.write[bi].resize(state->buffers[bi].size() + bv->byte_length); - copymem(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size()); + memcpy(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size()); ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT); state->buffer_views.push_back(bv); @@ -2858,16 +2869,13 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path name = itos(i); } name = _gen_unique_name(state, name); - name = name.pad_zeros(3); - Ref<_Directory> dir; - dir.instance(); + name = name.pad_zeros(3) + ".png"; String texture_dir = "textures"; String new_texture_dir = p_path.get_base_dir() + "/" + texture_dir; - dir->open(p_path.get_base_dir()); - if (!dir->dir_exists(new_texture_dir)) { - dir->make_dir(new_texture_dir); + DirAccessRef da = DirAccess::open(p_path.get_base_dir()); + if (!da->dir_exists(new_texture_dir)) { + da->make_dir(new_texture_dir); } - name = name + ".png"; image->save_png(new_texture_dir.plus_file(name)); d["uri"] = texture_dir.plus_file(name); } @@ -3012,11 +3020,14 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat } } - ERR_FAIL_COND_V_MSG(img.is_null(), ERR_FILE_CORRUPT, - vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype)); + if (img.is_null()) { + ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype)); + state->images.push_back(Ref<Texture2D>()); + continue; + } Ref<ImageTexture> t; - t.instance(); + t.instantiate(); t->create_from_image(img); state->images.push_back(t); @@ -3046,8 +3057,9 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) { } Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { - if (!state->json.has("textures")) + if (!state->json.has("textures")) { return OK; + } const Array &textures = state->json["textures"]; for (GLTFTextureIndex i = 0; i < textures.size(); i++) { @@ -3056,7 +3068,7 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { ERR_FAIL_COND_V(!d.has("source"), ERR_PARSE_ERROR); Ref<GLTFTexture> t; - t.instance(); + t.instantiate(); t->set_src_image(d["source"]); state->textures.push_back(t); } @@ -3067,8 +3079,8 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture) { ERR_FAIL_COND_V(p_texture.is_null(), -1); Ref<GLTFTexture> gltf_texture; - gltf_texture.instance(); - ERR_FAIL_COND_V(p_texture->get_data().is_null(), -1); + gltf_texture.instantiate(); + ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1); GLTFImageIndex gltf_src_image_i = state->images.size(); state->images.push_back(p_texture); gltf_texture->set_src_image(gltf_src_image_i); @@ -3115,7 +3127,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); GLTFTextureIndex gltf_texture_index = -1; - if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) { + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { albedo_texture->set_name(material->get_name() + "_albedo"); gltf_texture_index = _set_texture(state, albedo_texture); } @@ -3128,9 +3140,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { mr["metallicFactor"] = material->get_metallic(); mr["roughnessFactor"] = material->get_roughness(); - bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_data().is_valid(); + bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_data().is_valid(); + bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); if (has_ao || has_roughness || has_metalness) { Dictionary mrt; Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); @@ -3140,19 +3152,19 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel(); Ref<ImageTexture> orm_texture; - orm_texture.instance(); + orm_texture.instantiate(); Ref<Image> orm_image; - orm_image.instance(); + orm_image.instantiate(); int32_t height = 0; int32_t width = 0; Ref<Image> ao_image; if (has_ao) { height = ao_texture->get_height(); width = ao_texture->get_width(); - ao_image = ao_texture->get_data(); + ao_image = ao_texture->get_image(); Ref<ImageTexture> img_tex = ao_image; if (img_tex.is_valid()) { - ao_image = img_tex->get_data(); + ao_image = img_tex->get_image(); } if (ao_image->is_compressed()) { ao_image->decompress(); @@ -3162,10 +3174,10 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (has_roughness) { height = roughness_texture->get_height(); width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_data(); + roughness_image = roughness_texture->get_image(); Ref<ImageTexture> img_tex = roughness_image; if (img_tex.is_valid()) { - roughness_image = img_tex->get_data(); + roughness_image = img_tex->get_image(); } if (roughness_image->is_compressed()) { roughness_image->decompress(); @@ -3175,17 +3187,17 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (has_metalness) { height = metallic_texture->get_height(); width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_data(); + metallness_image = metallic_texture->get_image(); Ref<ImageTexture> img_tex = metallness_image; if (img_tex.is_valid()) { - metallness_image = img_tex->get_data(); + metallness_image = img_tex->get_image(); } if (metallness_image->is_compressed()) { metallness_image->decompress(); } } Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) { + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { height = albedo_texture->get_height(); width = albedo_texture->get_width(); } @@ -3262,17 +3274,18 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { Dictionary nt; Ref<ImageTexture> tex; - tex.instance(); + tex.instantiate(); { Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); // Code for uncompressing RG normal maps - Ref<Image> img = normal_texture->get_data(); + Ref<Image> img = normal_texture->get_image(); Ref<ImageTexture> img_tex = img; if (img_tex.is_valid()) { - img = img_tex->get_data(); + img = img_tex->get_image(); } img->decompress(); img->convert(Image::FORMAT_RGBA8); + img->convert_ra_rgba8_to_rg(); for (int32_t y = 0; y < img->get_height(); y++) { for (int32_t x = 0; x < img->get_width(); x++) { Color c = img->get_pixel(x, y); @@ -3288,7 +3301,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); GLTFTextureIndex gltf_texture_index = -1; - if (tex.is_valid() && tex->get_data().is_valid()) { + if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); gltf_texture_index = _set_texture(state, tex); } @@ -3311,7 +3324,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Dictionary et; Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; - if (emission_texture.is_valid() && emission_texture->get_data().is_valid()) { + if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { emission_texture->set_name(material->get_name() + "_emission"); gltf_texture_index = _set_texture(state, emission_texture); } @@ -3340,15 +3353,16 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { - if (!state->json.has("materials")) + if (!state->json.has("materials")) { return OK; + } const Array &materials = state->json["materials"]; for (GLTFMaterialIndex i = 0; i < materials.size(); i++) { const Dictionary &d = materials[i]; Ref<StandardMaterial3D> material; - material.instance(); + material.instantiate(); if (d.has("name") && !String(d["name"]).is_empty()) { material->set_name(d["name"]); } else { @@ -3364,13 +3378,13 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { Dictionary sgm = pbr_spec_gloss_extensions["KHR_materials_pbrSpecularGlossiness"]; Ref<GLTFSpecGloss> spec_gloss; - spec_gloss.instance(); + spec_gloss.instantiate(); if (sgm.has("diffuseTexture")) { const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"]; if (diffuse_texture_dict.has("index")) { Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]); if (diffuse_texture.is_valid()) { - spec_gloss->diffuse_img = diffuse_texture->get_data(); + spec_gloss->diffuse_img = diffuse_texture->get_image(); material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture); } } @@ -3398,7 +3412,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (spec_gloss_texture.has("index")) { const Ref<Texture2D> orig_texture = _get_texture(state, spec_gloss_texture["index"]); if (orig_texture.is_valid()) { - spec_gloss->spec_gloss_img = orig_texture->get_data(); + spec_gloss->spec_gloss_img = orig_texture->get_image(); } } } @@ -3547,7 +3561,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re return; } Ref<Image> rm_img; - rm_img.instance(); + rm_img.instantiate(); bool has_roughness = false; bool has_metal = false; p_material->set_roughness(1.0f); @@ -3575,7 +3589,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re if (!Math::is_equal_approx(mr.g, 1.0f)) { has_roughness = true; } - if (!Math::is_equal_approx(mr.b, 0.0f)) { + if (!Math::is_zero_approx(mr.b)) { has_metal = true; } mr.g *= r_spec_gloss->gloss_factor; @@ -3589,11 +3603,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re rm_img->generate_mipmaps(); r_spec_gloss->diffuse_img->generate_mipmaps(); Ref<ImageTexture> diffuse_image_texture; - diffuse_image_texture.instance(); + diffuse_image_texture.instantiate(); diffuse_image_texture->create_from_image(r_spec_gloss->diffuse_img); p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_image_texture); Ref<ImageTexture> rm_image_texture; - rm_image_texture.instance(); + rm_image_texture.instantiate(); rm_image_texture->create_from_image(rm_img); if (has_roughness) { p_material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, rm_image_texture); @@ -3858,8 +3872,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { } Error GLTFDocument::_parse_skins(Ref<GLTFState> state) { - if (!state->json.has("skins")) + if (!state->json.has("skins")) { return OK; + } const Array &skins = state->json["skins"]; @@ -3868,7 +3883,7 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) { const Dictionary &d = skins[i]; Ref<GLTFSkin> skin; - skin.instance(); + skin.instantiate(); ERR_FAIL_COND_V(!d.has("joints"), ERR_PARSE_ERROR); @@ -3996,7 +4011,7 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) { const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i]; Ref<GLTFSkeleton> skeleton; - skeleton.instance(); + skeleton.instantiate(); Vector<GLTFNodeIndex> skeleton_nodes; skeleton_sets.get_members(skeleton_nodes, skeleton_owner); @@ -4082,80 +4097,10 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state, subtree_set.get_members(subtree_nodes, subtree_root); for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) { - ERR_FAIL_COND_V(_reparent_to_fake_joint(state, skeleton, subtree_nodes[subtree_i]), FAILED); - - // We modified the tree, recompute all the heights - _compute_node_heights(state); - } - } - - return OK; -} - -Error GLTFDocument::_reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, const GLTFNodeIndex node_index) { - Ref<GLTFNode> node = state->nodes[node_index]; - - // Can we just "steal" this joint if it is just a spatial node? - if (node->skin < 0 && node->mesh < 0 && node->camera < 0) { - node->joint = true; - // Add the joint to the skeletons joints - skeleton->joints.push_back(node_index); - return OK; - } - - GLTFNode *fake_joint = memnew(GLTFNode); - const GLTFNodeIndex fake_joint_index = state->nodes.size(); - state->nodes.push_back(fake_joint); - - // We better not be a joint, or we messed up in our logic - if (node->joint) - return FAILED; - - fake_joint->translation = node->translation; - fake_joint->rotation = node->rotation; - fake_joint->scale = node->scale; - fake_joint->xform = node->xform; - fake_joint->joint = true; - - // We can use the exact same name here, because the joint will be inside a skeleton and not the scene - fake_joint->set_name(node->get_name()); - - // Clear the nodes transforms, since it will be parented to the fake joint - node->translation = Vector3(0, 0, 0); - node->rotation = Quat(); - node->scale = Vector3(1, 1, 1); - node->xform = Transform(); - - // Transfer the node children to the fake joint - for (int child_i = 0; child_i < node->children.size(); ++child_i) { - Ref<GLTFNode> child = state->nodes[node->children[child_i]]; - child->parent = fake_joint_index; - } - - fake_joint->children = node->children; - node->children.clear(); - - // add the fake joint to the parent and remove the original joint - if (node->parent >= 0) { - Ref<GLTFNode> parent = state->nodes[node->parent]; - parent->children.erase(node_index); - parent->children.push_back(fake_joint_index); - fake_joint->parent = node->parent; - } - - // Add the node to the fake joint - fake_joint->children.push_back(node_index); - node->parent = fake_joint_index; - node->fake_joint_parent = fake_joint_index; - - // Add the fake joint to the skeletons joints - skeleton->joints.push_back(fake_joint_index); - - // Replace skin_skeletons with fake joints if we must. - for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) { - Ref<GLTFSkin> skin = state->skins.write[skin_i]; - if (skin->skin_root == node_index) { - skin->skin_root = fake_joint_index; + Ref<GLTFNode> node = state->nodes[subtree_nodes[subtree_i]]; + node->joint = true; + // Add the joint to the skeletons joints + skeleton->joints.push_back(subtree_nodes[subtree_i]); } } @@ -4314,7 +4259,7 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) { Ref<GLTFSkin> gltf_skin = state->skins.write[skin_i]; Ref<Skin> skin; - skin.instance(); + skin.instantiate(); // Some skins don't have IBM's! What absolute monsters! const bool has_ibms = !gltf_skin->inverse_binds.is_empty(); @@ -4323,7 +4268,7 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) { GLTFNodeIndex node = gltf_skin->joints_original[joint_i]; String bone_name = state->nodes[node]->get_name(); - Transform xform; + Transform3D xform; if (has_ibms) { xform = gltf_skin->inverse_binds[joint_i]; } @@ -4363,9 +4308,12 @@ bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_ if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) { return false; } + if (skin_a->get_bind_name(i) != skin_b->get_bind_name(i)) { + return false; + } - Transform a_xform = skin_a->get_bind_pose(i); - Transform b_xform = skin_b->get_bind_pose(i); + Transform3D a_xform = skin_a->get_bind_pose(i); + Transform3D b_xform = skin_b->get_bind_pose(i); if (a_xform != b_xform) { return false; @@ -4493,7 +4441,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { const Dictionary &d = lights[light_i]; Ref<GLTFLight> light; - light.instance(); + light.instantiate(); ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); const String &type = d["type"]; light->type = type; @@ -4528,8 +4476,9 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { } Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { - if (!state->json.has("cameras")) + if (!state->json.has("cameras")) { return OK; + } const Array cameras = state->json["cameras"]; @@ -4537,7 +4486,7 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { const Dictionary &d = cameras[i]; Ref<GLTFCamera> camera; - camera.instance(); + camera.instantiate(); ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); const String &type = d["type"]; if (type == "orthographic") { @@ -4647,8 +4596,8 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { s["interpolation"] = interpolation_to_string(track.rotation_track.interpolation); Vector<real_t> times = Variant(track.rotation_track.times); s["input"] = _encode_accessor_as_floats(state, times, false); - Vector<Quat> values = track.rotation_track.values; - s["output"] = _encode_accessor_as_quats(state, values, false); + Vector<Quaternion> values = track.rotation_track.values; + s["output"] = _encode_accessor_as_quaternions(state, values, false); samplers.push_back(s); @@ -4730,8 +4679,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { } Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { - if (!state->json.has("animations")) + if (!state->json.has("animations")) { return OK; + } const Array &animations = state->json["animations"]; @@ -4739,10 +4689,11 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { const Dictionary &d = animations[i]; Ref<GLTFAnimation> animation; - animation.instance(); + animation.instantiate(); - if (!d.has("channels") || !d.has("samplers")) + if (!d.has("channels") || !d.has("samplers")) { continue; + } Array channels = d["channels"]; Array samplers = d["samplers"]; @@ -4757,8 +4708,9 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { for (int j = 0; j < channels.size(); j++) { const Dictionary &c = channels[j]; - if (!c.has("target")) + if (!c.has("target")) { continue; + } const Dictionary &t = c["target"]; if (!t.has("node") || !t.has("path")) { @@ -4814,7 +4766,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { track->translation_track.times = Variant(times); //convert via variant track->translation_track.values = Variant(translations); //convert via variant } else if (path == "rotation") { - const Vector<Quat> rotations = _decode_accessor_as_quat(state, output, false); + const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(state, output, false); track->rotation_track.interpolation = interp; track->rotation_track.times = Variant(times); //convert via variant track->rotation_track.values = rotations; @@ -4868,8 +4820,9 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) { Ref<GLTFNode> n = state->nodes[i]; // Any joints get unique names generated when the skeleton is made, unique to the skeleton - if (n->skeleton >= 0) + if (n->skeleton >= 0) { continue; + } if (n->get_name().is_empty()) { if (n->mesh >= 0) { @@ -4885,10 +4838,9 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) { } } -BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index) { +BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; - Ref<GLTFNode> bone_node = state->nodes[gltf_node->parent]; - + Ref<GLTFNode> bone_node = state->nodes[bone_index]; BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D); print_verbose("glTF: Creating bone attachment for: " + gltf_node->get_name()); @@ -4905,7 +4857,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns return -1; } Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instance(); + import_mesh.instantiate(); Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh(); if (godot_mesh.is_null()) { return -1; @@ -4930,8 +4882,8 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns if (godot_array_mesh.is_valid()) { surface_name = godot_array_mesh->surface_get_name(surface_i); } - if (p_mesh_instance->get_surface_material(surface_i).is_valid()) { - mat = p_mesh_instance->get_surface_material(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(); @@ -4942,7 +4894,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns blend_weights.write[blend_i] = 0.0f; } Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); gltf_mesh->set_mesh(import_mesh); gltf_mesh->set_blend_weights(blend_weights); GLTFMeshIndex mesh_i = state->meshes.size(); @@ -4973,7 +4925,7 @@ EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFSta return mi; } -Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr); @@ -5022,7 +4974,7 @@ Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation); return light; } - return nullptr; + return memnew(Node3D); } Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { @@ -5047,7 +4999,7 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_ print_verbose("glTF: Converting camera: " + p_camera->get_name()); Ref<GLTFCamera> c; - c.instance(); + c.instantiate(); if (p_camera->get_projection() == Camera3D::Projection::PROJECTION_PERSPECTIVE) { c->set_perspective(true); @@ -5068,7 +5020,7 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig print_verbose("glTF: Converting light: " + p_light->get_name()); Ref<GLTFLight> l; - l.instance(); + l.instantiate(); l->color = p_light->get_color(); if (cast_to<DirectionalLight3D>(p_light)) { l->type = "directional"; @@ -5103,7 +5055,7 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton) { print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name()); Ref<GLTFSkeleton> gltf_skeleton; - gltf_skeleton.instance(); + gltf_skeleton.instantiate(); gltf_skeleton->set_name(_gen_unique_name(state, p_skeleton->get_name())); gltf_skeleton->godot_skeleton = p_skeleton; GLTFSkeletonIndex skeleton_i = state->skeletons.size(); @@ -5112,9 +5064,9 @@ GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton } void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) { - Transform xform = p_spatial->get_transform(); + Transform3D xform = p_spatial->get_transform(); p_node->scale = xform.basis.get_scale(); - p_node->rotation = xform.basis.get_rotation_quat(); + p_node->rotation = xform.basis.get_rotation_quaternion(); p_node->translation = xform.origin; } @@ -5133,7 +5085,7 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, No return; } Ref<GLTFNode> gltf_node; - gltf_node.instance(); + gltf_node.instantiate(); gltf_node->set_name(_gen_unique_name(state, p_current->get_name())); if (cast_to<Node3D>(p_current)) { Node3D *spatial = cast_to<Node3D>(p_current); @@ -5199,9 +5151,9 @@ void GLTFDocument::_convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_g mat = csg->get_material_override(); } Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instance(); + 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)); @@ -5277,7 +5229,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNod Vector3(cell_location.x, cell_location.y, cell_location.z)); EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D); import_mesh_node->set_mesh(grid_map->get_mesh_library()->get_item_mesh(cell)); - Transform cell_xform; + Transform3D cell_xform; cell_xform.basis.set_orthogonal_index( grid_map->get_cell_item_orientation( Vector3(cell_location.x, cell_location.y, cell_location.z))); @@ -5287,7 +5239,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNod cell_xform.set_origin(grid_map->map_to_world( Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); gltf_mesh = import_mesh_node; new_gltf_node->mesh = state->meshes.size(); state->meshes.push_back(gltf_mesh); @@ -5305,15 +5257,15 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); instance_i++) { GLTFNode *new_gltf_node = memnew(GLTFNode); - Transform transform; + 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(); - Quat quat(Vector3(0, 1, 0), rotation); + Quaternion quaternion(Vector3(0, 1, 0), rotation); Size2 scale = xform_2d.get_scale(); - transform.basis.set_quat_scale(quat, + transform.basis.set_quaternion_scale(quaternion, Vector3(scale.x, 0, scale.y)); transform = multi_mesh_instance->get_transform() * transform; @@ -5324,14 +5276,14 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con Ref<ArrayMesh> mm = multi_mesh->get_mesh(); if (mm.is_valid()) { Ref<EditorSceneImporterMesh> mesh; - mesh.instance(); + 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.instance(); + gltf_mesh.instantiate(); gltf_mesh->set_name(multi_mesh->get_name()); gltf_mesh->set_mesh(mesh); new_gltf_node->mesh = state->meshes.size(); @@ -5394,31 +5346,22 @@ void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref<GLTFState> st void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; + if (gltf_node->skeleton >= 0) { + _generate_skeleton_bone_node(state, scene_parent, scene_root, node_index); + return; + } + Node3D *current_node = nullptr; // Is our parent a skeleton Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent); - if (gltf_node->skeleton >= 0) { - Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton; - - if (active_skeleton != skeleton) { - ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons"); - - // Add it to the scene if it has not already been added - if (skeleton->get_parent() == nullptr) { - scene_parent->add_child(skeleton); - skeleton->set_owner(scene_root); - } - } - - active_skeleton = skeleton; - current_node = skeleton; - } + const bool non_bone_parented_to_skeleton = active_skeleton; - // If we have an active skeleton, and the node is node skinned, we need to create a bone attachment - if (current_node == nullptr && active_skeleton != nullptr && gltf_node->skin < 0) { - BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index); + // skinned meshes must not be placed in a bone attachment. + if (non_bone_parented_to_skeleton && gltf_node->skin < 0) { + // Bone Attachment - Parent Case + BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); scene_parent->add_child(bone_attachment); bone_attachment->set_owner(scene_root); @@ -5432,7 +5375,86 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent } // We still have not managed to make a node - if (current_node == nullptr) { + if (gltf_node->mesh >= 0) { + current_node = _generate_mesh_instance(state, scene_parent, node_index); + } else if (gltf_node->camera >= 0) { + current_node = _generate_camera(state, scene_parent, node_index); + } else if (gltf_node->light >= 0) { + current_node = _generate_light(state, scene_parent, node_index); + } else { + current_node = _generate_spatial(state, scene_parent, node_index); + } + + scene_parent->add_child(current_node); + if (current_node != scene_root) { + current_node->set_owner(scene_root); + } + current_node->set_transform(gltf_node->xform); + current_node->set_name(gltf_node->get_name()); + + state->scene_nodes.insert(node_index, current_node); + + for (int i = 0; i < gltf_node->children.size(); ++i) { + _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]); + } +} + +void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) { + Ref<GLTFNode> gltf_node = state->nodes[node_index]; + + Node3D *current_node = nullptr; + + Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton; + // In this case, this node is already a bone in skeleton. + const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0); + const bool requires_extra_node = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0); + + Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent); + if (active_skeleton != skeleton) { + if (active_skeleton) { + // Bone Attachment - Direct Parented Skeleton Case + BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); + + scene_parent->add_child(bone_attachment); + bone_attachment->set_owner(scene_root); + + // There is no gltf_node that represent this, so just directly create a unique name + bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D")); + + // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node + // and attach it to the bone_attachment + scene_parent = bone_attachment; + WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", node_index)); + } + + // Add it to the scene if it has not already been added + if (skeleton->get_parent() == nullptr) { + scene_parent->add_child(skeleton); + skeleton->set_owner(scene_root); + } + } + + active_skeleton = skeleton; + current_node = skeleton; + + if (requires_extra_node) { + // skinned meshes must not be placed in a bone attachment. + if (!is_skinned_mesh) { + // Bone Attachment - Same Node Case + BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, node_index); + + scene_parent->add_child(bone_attachment); + bone_attachment->set_owner(scene_root); + + // There is no gltf_node that represent this, so just directly create a unique name + bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D")); + + // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node + // and attach it to the bone_attachment + scene_parent = bone_attachment; + } + + // We still have not managed to make a node if (gltf_node->mesh >= 0) { current_node = _generate_mesh_instance(state, scene_parent, node_index); } else if (gltf_node->camera >= 0) { @@ -5441,22 +5463,18 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent current_node = _generate_light(state, scene_parent, node_index); } - if (!current_node) { - current_node = _generate_spatial(state, scene_parent, node_index); - } - scene_parent->add_child(current_node); if (current_node != scene_root) { current_node->set_owner(scene_root); } - current_node->set_transform(gltf_node->xform); + // Do not set transform here. Transform is already applied to our bone. current_node->set_name(gltf_node->get_name()); } state->scene_nodes.insert(node_index, current_node); for (int i = 0; i < gltf_node->children.size(); ++i) { - _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]); + _generate_scene_node(state, active_skeleton, scene_root, gltf_node->children[i]); } } @@ -5487,24 +5505,24 @@ struct EditorSceneImporterGLTFInterpolate { // thank you for existing, partial specialization template <> -struct EditorSceneImporterGLTFInterpolate<Quat> { - Quat lerp(const Quat &a, const Quat &b, const float c) const { - ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized."); - ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized."); +struct EditorSceneImporterGLTFInterpolate<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."); return a.slerp(b, c).normalized(); } - Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, const float c) { - ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized."); - ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized."); + Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, const float c) { + ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), "The quaternion \"p1\" must be normalized."); + ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), "The quaternion \"p2\" must be normalized."); return p1.slerp(p2, c).normalized(); } - Quat bezier(const Quat start, const Quat control_1, const Quat control_2, const Quat end, const float t) { - ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized."); + Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) { + ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), "The end quaternion must be normalized."); return start.slerp(end, t).normalized(); } @@ -5512,11 +5530,14 @@ struct EditorSceneImporterGLTFInterpolate<Quat> { 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()); + ERR_FAIL_COND_V(p_times.size() != p_values.size(), p_values[0]); //could use binary search, worth it? int idx = -1; for (int i = 0; i < p_times.size(); i++) { - if (p_times[i] > p_time) + if (p_times[i] > p_time) { break; + } idx++; } @@ -5585,7 +5606,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } Ref<Animation> animation; - animation.instance(); + animation.instantiate(); animation->set_name(name); if (anim->get_loop()) { @@ -5596,28 +5617,30 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (Map<int, GLTFAnimation::Track>::Element *track_i = anim->get_tracks().front(); track_i; track_i = track_i->next()) { const GLTFAnimation::Track &track = track_i->get(); - //need to find the path + //need to find the path: for skeletons, weight tracks will affect the mesh NodePath node_path; + //for skeletons, transform tracks always affect bones + NodePath transform_node_path; GLTFNodeIndex node_index = track_i->key(); - if (state->nodes[node_index]->fake_joint_parent >= 0) { - // Should be same as parent - node_index = state->nodes[node_index]->fake_joint_parent; - } const Ref<GLTFNode> gltf_node = state->nodes[track_i->key()]; + Node *root = ap->get_parent(); + ERR_FAIL_COND(root == nullptr); + Map<GLTFNodeIndex, Node *>::Element *node_element = state->scene_nodes.find(node_index); + ERR_CONTINUE_MSG(node_element == nullptr, vformat("Unable to find node %d for animation", node_index)); + node_path = root->get_path_to(node_element->get()); + if (gltf_node->skeleton >= 0) { - const Skeleton3D *sk = Object::cast_to<Skeleton3D>(state->scene_nodes.find(node_index)->get()); + const Skeleton3D *sk = state->skeletons[gltf_node->skeleton]->godot_skeleton; ERR_FAIL_COND(sk == nullptr); const String path = ap->get_parent()->get_path_to(sk); const String bone = gltf_node->get_name(); - node_path = path + ":" + bone; + transform_node_path = path + ":" + bone; } else { - Node *root = ap->get_parent(); - Node *godot_node = state->scene_nodes.find(node_index)->get(); - node_path = root->get_path_to(godot_node); + transform_node_path = node_path; } for (int i = 0; i < track.rotation_track.times.size(); i++) { @@ -5636,18 +5659,20 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } - if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) { + // Animated TRS properties will not affect a skinned mesh. + const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0; + if ((track.rotation_track.values.size() || track.translation_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_TRANSFORM); - animation->track_set_path(track_idx, node_path); + animation->add_track(Animation::TYPE_TRANSFORM3D); + animation->track_set_path(track_idx, transform_node_path); //first determine animation length const double increment = 1.0 / bake_fps; double time = 0.0; Vector3 base_pos; - Quat base_rot; + Quaternion base_rot; Vector3 base_scale = Vector3(1, 1, 1); if (!track.rotation_track.values.size()) { @@ -5665,7 +5690,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, bool last = false; while (true) { Vector3 pos = base_pos; - Quat rot = base_rot; + Quaternion rot = base_rot; Vector3 scale = base_scale; if (track.translation_track.times.size()) { @@ -5673,7 +5698,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } if (track.rotation_track.times.size()) { - rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); + rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); } if (track.scale_track.times.size()) { @@ -5681,15 +5706,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } if (gltf_node->skeleton >= 0) { - Transform xform; - xform.basis.set_quat_scale(rot, scale); + 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_quat(); + rot = xform.basis.get_rotation_quaternion(); rot.normalize(); scale = xform.basis.get_scale(); pos = xform.origin; @@ -5774,9 +5799,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { } MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); ERR_CONTINUE(!mi); - Transform mi_xform = mi->get_transform(); + Transform3D mi_xform = mi->get_transform(); node->scale = mi_xform.basis.get_scale(); - node->rotation = mi_xform.basis.get_rotation_quat(); + node->rotation = mi_xform.basis.get_rotation_quaternion(); node->translation = mi_xform.origin; Dictionary json_skin; @@ -5792,7 +5817,7 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { skin = skeleton->register_skin(nullptr)->get_skin(); } Ref<GLTFSkin> gltf_skin; - gltf_skin.instance(); + gltf_skin.instantiate(); Array json_joints; GLTFSkeletonIndex skeleton_gltf_i = -1; @@ -5834,13 +5859,13 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { BoneId bone_index = skeleton->find_bone(godot_bone_name); ERR_CONTINUE(bone_index == -1); Ref<GLTFNode> joint_node; - joint_node.instance(); + joint_node.instantiate(); String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name); joint_node->set_name(gltf_bone_name); - Transform bone_rest_xform = skeleton->get_bone_rest(bone_index); + Transform3D bone_rest_xform = skeleton->get_bone_rest(bone_index); joint_node->scale = bone_rest_xform.basis.get_scale(); - joint_node->rotation = bone_rest_xform.basis.get_rotation_quat(); + joint_node->rotation = bone_rest_xform.basis.get_rotation_quaternion(); joint_node->translation = bone_rest_xform.origin; joint_node->joint = true; @@ -5945,13 +5970,15 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo const GLTFSkinIndex skin_i = node->skin; 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_FAIL_COND(mi == nullptr); + ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to EditorSceneImporterMeshNode3D", 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]; Skeleton3D *skeleton = gltf_skeleton->godot_skeleton; - ERR_FAIL_COND(skeleton == nullptr); + ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d", node_i, skin_i)); mi->get_parent()->remove_child(mi); skeleton->add_child(mi); @@ -5959,12 +5986,12 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo mi->set_skin(state->skins.write[skin_i]->godot_skin); mi->set_skeleton_path(mi->get_path_to(skeleton)); - mi->set_transform(Transform()); + mi->set_transform(Transform3D()); } } } -GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform 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, Transform3D p_bone_rest, 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; @@ -5984,7 +6011,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i); } const float BAKE_FPS = 30.0f; - if (track_type == Animation::TYPE_TRANSFORM) { + if (track_type == Animation::TYPE_TRANSFORM3D) { p_track.translation_track.times = times; p_track.translation_track.interpolation = gltf_interpolation; p_track.rotation_track.times = times; @@ -6000,16 +6027,16 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { Vector3 translation; - Quat rotation; + Quaternion rotation; Vector3 scale; Error err = p_animation->transform_track_get_key(p_track_i, key_i, &translation, &rotation, &scale); ERR_CONTINUE(err != OK); - Transform xform; - xform.basis.set_quat_scale(rotation, scale); + Transform3D xform; + xform.basis.set_quaternion_scale(rotation, scale); xform.origin = translation; xform = p_bone_rest * xform; p_track.translation_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat(); + 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(); } } else if (path.find(":transform") != -1) { @@ -6027,9 +6054,9 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state 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++) { - Transform xform = p_animation->track_get_key_value(p_track_i, key_i); + Transform3D xform = p_animation->track_get_key_value(p_track_i, key_i); p_track.translation_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat(); + 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(); } } else if (track_type == Animation::TYPE_VALUE) { @@ -6041,7 +6068,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { - Quat rotation_track = p_animation->track_get_key_value(p_track_i, key_i); + Quaternion rotation_track = p_animation->track_get_key_value(p_track_i, key_i); p_track.rotation_track.values.write[key_i] = rotation_track; } } else if (path.find(":translation") != -1) { @@ -6055,7 +6082,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state Vector3 translation = p_animation->track_get_key_value(p_track_i, key_i); p_track.translation_track.values.write[key_i] = translation; } - } else if (path.find(":rotation_degrees") != -1) { + } else if (path.find(":rotation") != -1) { p_track.rotation_track.times = times; p_track.rotation_track.interpolation = gltf_interpolation; @@ -6063,12 +6090,8 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { - Vector3 rotation_degrees = p_animation->track_get_key_value(p_track_i, key_i); - Vector3 rotation_radian; - rotation_radian.x = Math::deg2rad(rotation_degrees.x); - rotation_radian.y = Math::deg2rad(rotation_degrees.y); - rotation_radian.z = Math::deg2rad(rotation_degrees.z); - p_track.rotation_track.values.write[key_i] = Quat(rotation_radian); + Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i); + p_track.rotation_track.values.write[key_i] = Quaternion(rotation_radian); } } else if (path.find(":scale") != -1) { p_track.scale_track.times = times; @@ -6154,7 +6177,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name) { Ref<Animation> animation = ap->get_animation(p_animation_track_name); Ref<GLTFAnimation> gltf_animation; - gltf_animation.instance(); + gltf_animation.instantiate(); gltf_animation->set_name(_gen_unique_name(state, p_animation_track_name)); for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) { @@ -6174,7 +6197,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (translation_track_i) { track = translation_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6190,7 +6213,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, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6206,7 +6229,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, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6217,7 +6240,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) { if (transform_track_i->get() == node) { GLTFAnimation::Track track; - track = _convert_animation_track(state, track, animation, Transform(), track_i, transform_track_i->key()); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i->key()); gltf_animation->get_tracks().insert(transform_track_i->key(), track); } } @@ -6305,7 +6328,7 @@ 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); - Transform xform = skeleton->get_bone_rest(bone); + Transform3D xform = skeleton->get_bone_rest(bone); if (!skeleton_gltf->godot_bone_node.has(bone)) { continue; } @@ -6332,7 +6355,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (node_track_i) { track = node_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); break; } @@ -6356,13 +6379,15 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar //binary file //text file err = _parse_glb(p_path, state); - if (err) + if (err) { return FAILED; + } } else { //text file err = _parse_json(p_path, state); - if (err) + if (err) { return FAILED; + } } f->close(); @@ -6382,68 +6407,81 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar /* STEP 0 PARSE SCENE */ err = _parse_scenes(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 1 PARSE NODES */ err = _parse_nodes(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 2 PARSE BUFFERS */ err = _parse_buffers(state, p_path.get_base_dir()); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 3 PARSE BUFFER VIEWS */ err = _parse_buffer_views(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 4 PARSE ACCESSORS */ err = _parse_accessors(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 5 PARSE IMAGES */ err = _parse_images(state, p_path.get_base_dir()); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 6 PARSE TEXTURES */ err = _parse_textures(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 7 PARSE TEXTURES */ err = _parse_materials(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 9 PARSE SKINS */ err = _parse_skins(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 10 DETERMINE SKELETONS */ err = _determine_skeletons(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 11 CREATE SKELETONS */ err = _create_skeletons(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 12 CREATE SKINS */ err = _create_skins(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 13 PARSE MESHES (we have enough info now) */ err = _parse_meshes(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 14 PARSE LIGHTS */ err = _parse_lights(state); @@ -6453,13 +6491,15 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar /* STEP 15 PARSE CAMERAS */ err = _parse_cameras(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 16 PARSE ANIMATIONS */ err = _parse_animations(state); - if (err != OK) + if (err != OK) { return Error::FAILED; + } /* STEP 17 ASSIGN SCENE NAMES */ _assign_scene_names(state); @@ -6531,7 +6571,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V(!f, FAILED); - String json = JSON::print(state->json); + String json = Variant(state->json).to_json_string(); const uint32_t magic = 0x46546C67; // GLTF const int32_t header_size = 12; @@ -6572,7 +6612,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { ERR_FAIL_COND_V(!f, FAILED); f->create(FileAccess::ACCESS_RESOURCES); - String json = JSON::print(state->json); + String json = Variant(state->json).to_json_string(); f->store_string(json); f->close(); } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index bda1ce87d6..3e8ea19045 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -31,11 +31,9 @@ #ifndef GLTF_DOCUMENT_H #define GLTF_DOCUMENT_H -#include "editor/import/resource_importer_scene.h" -#include "editor/import/scene_importer_mesh_node_3d.h" #include "gltf_animation.h" -#include "modules/modules_enabled.gen.h" -#include "scene/2d/node_2d.h" + +#include "editor/import/scene_importer_mesh_node_3d.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" @@ -45,6 +43,8 @@ #include "scene/resources/material.h" #include "scene/resources/texture.h" +#include "modules/modules_enabled.gen.h" + class GLTFState; class GLTFSkin; class GLTFNode; @@ -205,7 +205,7 @@ private: Vector<Color> _decode_accessor_as_color(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Quat> _decode_accessor_as_quat(Ref<GLTFState> state, + Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> state, @@ -214,7 +214,7 @@ private: Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Transform> _decode_accessor_as_xform(Ref<GLTFState> state, + Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); Error _parse_meshes(Ref<GLTFState> state); @@ -260,11 +260,12 @@ private: Error _serialize_animations(Ref<GLTFState> state); BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, - const GLTFNodeIndex node_index); + 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); - Light3D *_generate_light(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); void _assign_scene_names(Ref<GLTFState> state); @@ -272,8 +273,8 @@ private: T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp); - GLTFAccessorIndex _encode_accessor_as_quats(Ref<GLTFState> state, - const Vector<Quat> p_attribs, + GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> state, + const Vector<Quaternion> p_attribs, const bool p_for_vertex); GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> state, const Vector<Color> p_attribs, @@ -316,7 +317,7 @@ private: const Vector<int32_t> p_attribs, const bool p_for_vertex); GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> state, - const Vector<Transform> p_attribs, + const Vector<Transform3D> p_attribs, const bool p_for_vertex); Error _encode_buffer_view(Ref<GLTFState> state, const double *src, const int count, const GLTFType type, @@ -332,7 +333,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, Transform p_bone_rest, + Ref<Animation> p_animation, Transform3D p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i); Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path); @@ -365,6 +366,7 @@ public: void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); + void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps); GLTFMeshIndex _convert_mesh_instance(Ref<GLTFState> state, diff --git a/modules/gltf/gltf_node.cpp b/modules/gltf/gltf_node.cpp index 777c6fbd9a..5db7ad66c3 100644 --- a/modules/gltf/gltf_node.cpp +++ b/modules/gltf/gltf_node.cpp @@ -55,24 +55,21 @@ void GLTFNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scale", "scale"), &GLTFNode::set_scale); ClassDB::bind_method(D_METHOD("get_children"), &GLTFNode::get_children); ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children); - ClassDB::bind_method(D_METHOD("get_fake_joint_parent"), &GLTFNode::get_fake_joint_parent); - ClassDB::bind_method(D_METHOD("set_fake_joint_parent", "fake_joint_parent"), &GLTFNode::set_fake_joint_parent); ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light); ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light); ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "xform"), "set_xform", "get_xform"); // Transform + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "xform"), "set_xform", "get_xform"); // Transform3D ADD_PROPERTY(PropertyInfo(Variant::INT, "mesh"), "set_mesh", "get_mesh"); // GLTFMeshIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "camera"), "set_camera", "get_camera"); // GLTFCameraIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "skin"), "set_skin", "get_skin"); // GLTFSkinIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // GLTFSkeletonIndex ADD_PROPERTY(PropertyInfo(Variant::BOOL, "joint"), "set_joint", "get_joint"); // bool ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation"), "set_translation", "get_translation"); // Vector3 - ADD_PROPERTY(PropertyInfo(Variant::QUAT, "rotation"), "set_rotation", "get_rotation"); // Quat + ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "rotation"), "set_rotation", "get_rotation"); // Quaternion ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale"), "set_scale", "get_scale"); // Vector3 ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "children"), "set_children", "get_children"); // Vector<int> - ADD_PROPERTY(PropertyInfo(Variant::INT, "fake_joint_parent"), "set_fake_joint_parent", "get_fake_joint_parent"); // GLTFNodeIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "light"), "set_light", "get_light"); // GLTFLightIndex } @@ -92,11 +89,11 @@ void GLTFNode::set_height(int p_height) { height = p_height; } -Transform GLTFNode::get_xform() { +Transform3D GLTFNode::get_xform() { return xform; } -void GLTFNode::set_xform(Transform p_xform) { +void GLTFNode::set_xform(Transform3D p_xform) { xform = p_xform; } @@ -148,11 +145,11 @@ void GLTFNode::set_translation(Vector3 p_translation) { translation = p_translation; } -Quat GLTFNode::get_rotation() { +Quaternion GLTFNode::get_rotation() { return rotation; } -void GLTFNode::set_rotation(Quat p_rotation) { +void GLTFNode::set_rotation(Quaternion p_rotation) { rotation = p_rotation; } @@ -172,14 +169,6 @@ void GLTFNode::set_children(Vector<int> p_children) { children = p_children; } -GLTFNodeIndex GLTFNode::get_fake_joint_parent() { - return fake_joint_parent; -} - -void GLTFNode::set_fake_joint_parent(GLTFNodeIndex p_fake_joint_parent) { - fake_joint_parent = p_fake_joint_parent; -} - GLTFLightIndex GLTFNode::get_light() { return light; } diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h index ce8aff8944..378b6da8bf 100644 --- a/modules/gltf/gltf_node.h +++ b/modules/gltf/gltf_node.h @@ -43,17 +43,16 @@ private: // matrices need to be transformed to this GLTFNodeIndex parent = -1; int height = -1; - Transform xform; + Transform3D xform; GLTFMeshIndex mesh = -1; GLTFCameraIndex camera = -1; GLTFSkinIndex skin = -1; GLTFSkeletonIndex skeleton = -1; bool joint = false; Vector3 translation; - Quat rotation; + Quaternion rotation; Vector3 scale = Vector3(1, 1, 1); Vector<int> children; - GLTFNodeIndex fake_joint_parent = -1; GLTFLightIndex light = -1; protected: @@ -66,8 +65,8 @@ public: int get_height(); void set_height(int p_height); - Transform get_xform(); - void set_xform(Transform p_xform); + Transform3D get_xform(); + void set_xform(Transform3D p_xform); GLTFMeshIndex get_mesh(); void set_mesh(GLTFMeshIndex p_mesh); @@ -87,8 +86,8 @@ public: Vector3 get_translation(); void set_translation(Vector3 p_translation); - Quat get_rotation(); - void set_rotation(Quat p_rotation); + Quaternion get_rotation(); + void set_rotation(Quaternion p_rotation); Vector3 get_scale(); void set_scale(Vector3 p_scale); @@ -96,9 +95,6 @@ public: Vector<int> get_children(); void set_children(Vector<int> p_children); - GLTFNodeIndex get_fake_joint_parent(); - void set_fake_joint_parent(GLTFNodeIndex p_fake_joint_parent); - GLTFLightIndex get_light(); void set_light(GLTFLightIndex p_light); }; diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp index 5a61e5778c..5cf17135ac 100644 --- a/modules/gltf/gltf_skin.cpp +++ b/modules/gltf/gltf_skin.cpp @@ -54,7 +54,7 @@ void GLTFSkin::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "skin_root"), "set_skin_root", "get_skin_root"); // GLTFNodeIndex ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints_original"), "set_joints_original", "get_joints_original"); // Vector<GLTFNodeIndex> - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform> + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform3D> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "non_joints"), "set_non_joints", "get_non_joints"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex> diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h index 7cc09d85bc..e32e2d397c 100644 --- a/modules/gltf/gltf_skin.h +++ b/modules/gltf/gltf_skin.h @@ -43,7 +43,7 @@ private: GLTFNodeIndex skin_root = -1; Vector<GLTFNodeIndex> joints_original; - Vector<Transform> inverse_binds; + Vector<Transform3D> inverse_binds; // Note: joints + non_joints should form a complete subtree, or subtrees // with a common parent diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index ba6bf8a533..d8209523c5 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -31,9 +31,6 @@ #ifndef GLTF_STATE_H #define GLTF_STATE_H -#include "core/io/resource.h" -#include "core/templates/vector.h" -#include "editor_scene_importer_gltf.h" #include "gltf_accessor.h" #include "gltf_animation.h" #include "gltf_buffer_view.h" @@ -45,6 +42,9 @@ #include "gltf_skeleton.h" #include "gltf_skin.h" #include "gltf_texture.h" + +#include "core/io/resource.h" +#include "core/templates/vector.h" #include "scene/animation/animation_player.h" #include "scene/resources/texture.h" diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index dc995c9249..85921490d2 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -51,7 +51,7 @@ #ifdef TOOLS_ENABLED static void _editor_init() { Ref<EditorSceneImporterGLTF> import_gltf; - import_gltf.instance(); + import_gltf.instantiate(); ResourceImporterScene::get_singleton()->add_importer(import_gltf); } #endif @@ -62,25 +62,25 @@ void register_gltf_types() { #ifdef TOOLS_ENABLED ClassDB::APIType prev_api = ClassDB::get_current_api(); ClassDB::set_current_api(ClassDB::API_EDITOR); - ClassDB::register_class<EditorSceneImporterGLTF>(); - ClassDB::register_class<GLTFMesh>(); + GDREGISTER_CLASS(EditorSceneImporterGLTF); + GDREGISTER_CLASS(GLTFMesh); EditorPlugins::add_by_type<SceneExporterGLTFPlugin>(); ClassDB::set_current_api(prev_api); EditorNode::add_init_callback(_editor_init); #endif - ClassDB::register_class<GLTFSpecGloss>(); - ClassDB::register_class<GLTFNode>(); - ClassDB::register_class<GLTFAnimation>(); - ClassDB::register_class<GLTFBufferView>(); - ClassDB::register_class<GLTFAccessor>(); - ClassDB::register_class<GLTFTexture>(); - ClassDB::register_class<GLTFSkeleton>(); - ClassDB::register_class<GLTFSkin>(); - ClassDB::register_class<GLTFCamera>(); - ClassDB::register_class<GLTFLight>(); - ClassDB::register_class<GLTFState>(); - ClassDB::register_class<GLTFDocument>(); - ClassDB::register_class<PackedSceneGLTF>(); + GDREGISTER_CLASS(GLTFSpecGloss); + GDREGISTER_CLASS(GLTFNode); + GDREGISTER_CLASS(GLTFAnimation); + GDREGISTER_CLASS(GLTFBufferView); + GDREGISTER_CLASS(GLTFAccessor); + GDREGISTER_CLASS(GLTFTexture); + GDREGISTER_CLASS(GLTFSkeleton); + GDREGISTER_CLASS(GLTFSkin); + GDREGISTER_CLASS(GLTFCamera); + GDREGISTER_CLASS(GLTFLight); + GDREGISTER_CLASS(GLTFState); + GDREGISTER_CLASS(GLTFDocument); + GDREGISTER_CLASS(PackedSceneGLTF); #endif } diff --git a/modules/gridmap/config.py b/modules/gridmap/config.py index a6319fe1ea..720401b92d 100644 --- a/modules/gridmap/config.py +++ b/modules/gridmap/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 9b6fa138e5..a2c8e8eabf 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -41,7 +41,7 @@ <return type="Array"> </return> <description> - Returns an array of [ArrayMesh]es and [Transform] references of all bake meshes that exist within the current GridMap. + Returns an array of [ArrayMesh]es and [Transform3D] references of all bake meshes that exist within the current GridMap. </description> </method> <method name="get_cell_item" qualifiers="const"> @@ -84,7 +84,7 @@ <return type="Array"> </return> <description> - Returns an array of [Transform] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space. + Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space. </description> </method> <method name="get_used_cells" qualifiers="const"> @@ -203,7 +203,7 @@ The scale of the cell items. This does not affect the size of the grid cells themselves, only the items in them. This can be used to make cell items overlap their neighbors. </member> - <member name="cell_size" type="Vector3" setter="set_cell_size" getter="get_cell_size" default="Vector3( 2, 2, 2 )"> + <member name="cell_size" type="Vector3" setter="set_cell_size" getter="get_cell_size" default="Vector3(2, 2, 2)"> The dimensions of the grid's cells. This does not affect the size of the meshes. See [member cell_scale]. </member> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 4e4f88ed6a..e9134b32d9 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -152,6 +152,7 @@ uint32_t GridMap::get_collision_mask() const { } void GridMap::set_collision_mask_bit(int p_bit, bool p_value) { + ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive."); uint32_t mask = get_collision_mask(); if (p_value) { mask |= 1 << p_bit; @@ -162,20 +163,23 @@ void GridMap::set_collision_mask_bit(int p_bit, bool p_value) { } bool GridMap::get_collision_mask_bit(int p_bit) const { + ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive."); return get_collision_mask() & (1 << p_bit); } void GridMap::set_collision_layer_bit(int p_bit, bool p_value) { - uint32_t mask = get_collision_layer(); + ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive."); + uint32_t layer = get_collision_layer(); if (p_value) { - mask |= 1 << p_bit; + layer |= 1 << p_bit; } else { - mask &= ~(1 << p_bit); + layer &= ~(1 << p_bit); } - set_collision_layer(mask); + set_collision_layer(layer); } bool GridMap::get_collision_layer_bit(int p_bit) const { + ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive."); return get_collision_layer() & (1 << p_bit); } @@ -442,7 +446,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { * and set said multimesh bounding box to one containing all cells which have this item */ - Map<int, List<Pair<Transform, IndexKey>>> multimesh_items; + Map<int, List<Pair<Transform3D, IndexKey>>> multimesh_items; for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) { ERR_CONTINUE(!cell_map.has(E->get())); @@ -455,7 +459,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z); Vector3 ofs = _get_offset(); - Transform xform; + Transform3D xform; xform.basis.set_orthogonal_index(c.rot); xform.set_origin(cellpos * cell_size + ofs); @@ -463,10 +467,10 @@ bool GridMap::_octant_update(const OctantKey &p_key) { if (baked_meshes.size() == 0) { if (mesh_library->get_item_mesh(c.item).is_valid()) { if (!multimesh_items.has(c.item)) { - multimesh_items[c.item] = List<Pair<Transform, IndexKey>>(); + multimesh_items[c.item] = List<Pair<Transform3D, IndexKey>>(); } - Pair<Transform, IndexKey> p; + Pair<Transform3D, IndexKey> p; p.first = xform; p.second = E->get(); multimesh_items[c.item].push_back(p); @@ -507,7 +511,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { //update multimeshes, only if not baked if (baked_meshes.size() == 0) { - for (Map<int, List<Pair<Transform, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) { + for (Map<int, List<Pair<Transform3D, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) { Octant::MultimeshInstance mmi; RID mm = RS::get_singleton()->multimesh_create(); @@ -515,7 +519,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid()); int idx = 0; - for (List<Pair<Transform, IndexKey>>::Element *F = E->get().front(); F; F = F->next()) { + for (List<Pair<Transform3D, IndexKey>>::Element *F = E->get().front(); F; F = F->next()) { RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first); #ifdef TOOLS_ENABLED @@ -668,7 +672,7 @@ void GridMap::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - Transform new_xform = get_global_transform(); + Transform3D new_xform = get_global_transform(); if (new_xform == last_transform) { break; } @@ -682,7 +686,6 @@ void GridMap::_notification(int p_what) { for (int i = 0; i < baked_meshes.size(); i++) { RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform()); } - } break; case NOTIFICATION_EXIT_WORLD: { for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) { @@ -777,7 +780,7 @@ void GridMap::_update_octants_callback() { while (to_delete.front()) { octant_map.erase(to_delete.front()->get()); - to_delete.pop_back(); + to_delete.pop_front(); } _update_visibility(); @@ -930,7 +933,7 @@ Array GridMap::get_meshes() { Vector3 cellpos = Vector3(ik.x, ik.y, ik.z); - Transform xform; + Transform3D xform; xform.basis.set_orthogonal_index(E->get().rot); @@ -984,7 +987,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe Vector3 cellpos = Vector3(key.x, key.y, key.z); Vector3 ofs = _get_offset(); - Transform xform; + Transform3D xform; xform.basis.set_orthogonal_index(E->get().rot); xform.set_origin(cellpos * cell_size + ofs); @@ -1009,7 +1012,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe Ref<Material> surf_mat = mesh->surface_get_material(i); if (!mat_map.has(surf_mat)) { Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->begin(Mesh::PRIMITIVE_TRIANGLES); st->set_material(surf_mat); mat_map[surf_mat] = st; @@ -1021,7 +1024,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>>::Element *E = surface_map.front(); E; E = E->next()) { Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); for (Map<Ref<Material>, Ref<SurfaceTool>>::Element *F = E->get().front(); F; F = F->next()) { F->get()->commit(mesh); } @@ -1053,7 +1056,7 @@ Array GridMap::get_bake_meshes() { Array arr; for (int i = 0; i < baked_meshes.size(); i++) { arr.push_back(baked_meshes[i].mesh); - arr.push_back(Transform()); + arr.push_back(Transform3D()); } return arr; diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 4c04d492f7..8cd82e1f4c 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -89,7 +89,7 @@ class GridMap : public Node3D { struct Octant { struct NavMesh { RID region; - Transform xform; + Transform3D xform; }; struct MultimeshInstance { @@ -97,7 +97,7 @@ class GridMap : public Node3D { RID multimesh; struct Item { int index = 0; - Transform transform; + Transform3D transform; IndexKey key; }; @@ -137,7 +137,7 @@ class GridMap : public Node3D { bool bake_navigation = false; uint32_t navigation_layers = 1; - Transform last_transform; + Transform3D last_transform; bool _in_tree = false; Vector3 cell_size = Vector3(2, 2, 2); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 74ae45a46e..d894425ce8 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -62,12 +62,6 @@ void GridMapEditor::_menu_option(int p_option) { floor->set_value(floor->get_value() + 1); } break; - case MENU_OPTION_LOCK_VIEW: { - int index = options->get_popup()->get_item_index(MENU_OPTION_LOCK_VIEW); - lock_view = !options->get_popup()->is_item_checked(index); - - options->get_popup()->set_item_checked(index, lock_view); - } break; case MENU_OPTION_CLIP_DISABLED: case MENU_OPTION_CLIP_ABOVE: case MENU_OPTION_CLIP_BELOW: { @@ -255,7 +249,7 @@ void GridMapEditor::_menu_option(int p_option) { } void GridMapEditor::_update_cursor_transform() { - cursor_transform = Transform(); + cursor_transform = Transform3D(); cursor_transform.origin = cursor_origin; cursor_transform.basis.set_orthogonal_index(cursor_rot); cursor_transform.basis *= node->get_cell_scale(); @@ -268,7 +262,7 @@ void GridMapEditor::_update_cursor_transform() { } void GridMapEditor::_update_selection_transform() { - Transform xf_zero; + Transform3D xf_zero; xf_zero.basis.set_zero(); if (!selection.active) { @@ -279,7 +273,7 @@ void GridMapEditor::_update_selection_transform() { return; } - Transform xf; + Transform3D xf; xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size()); xf.origin = selection.begin * node->get_cell_size(); @@ -297,7 +291,7 @@ void GridMapEditor::_update_selection_transform() { scale *= node->get_cell_size(); position *= node->get_cell_size(); - Transform xf2; + Transform3D xf2; xf2.basis.scale(scale); xf2.origin = position; @@ -362,7 +356,7 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b Camera3D *camera = p_camera; Vector3 from = camera->project_ray_origin(p_point); Vector3 normal = camera->project_ray_normal(p_point); - Transform local_xform = node->get_global_transform().affine_inverse(); + Transform3D local_xform = node->get_global_transform().affine_inverse(); Vector<Plane> planes = camera->get_frustum(); from = local_xform.xform(from); normal = local_xform.basis.xform(normal).normalized(); @@ -540,7 +534,7 @@ void GridMapEditor::_set_clipboard_data() { void GridMapEditor::_update_paste_indicator() { if (input_action != INPUT_PASTE) { - Transform xf; + Transform3D xf; xf.basis.set_zero(); RenderingServer::get_singleton()->instance_set_transform(paste_instance, xf); return; @@ -548,7 +542,7 @@ void GridMapEditor::_update_paste_indicator() { Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z())); Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size(); - Transform xf; + Transform3D xf; xf.scale(scale); xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size(); Basis rot; @@ -561,7 +555,7 @@ void GridMapEditor::_update_paste_indicator() { for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) { ClipboardItem &item = E->get(); - xf = Transform(); + xf = Transform3D(); xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size(); xf.basis = rot * xf.basis; xf.translate(item.grid_offset * node->get_cell_size()); @@ -615,13 +609,13 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && (mb->get_command() || mb->get_shift())) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && (mb->is_command_pressed() || mb->is_shift_pressed())) { if (mb->is_pressed()) { floor->set_value(floor->get_value() + mb->get_factor()); } return true; // Eaten. - } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->get_command() || mb->get_shift())) { + } 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()); } @@ -630,7 +624,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In if (mb->is_pressed()) { Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); - if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->get_alt()) { + if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->is_alt_pressed()) { input_action = INPUT_NONE; } else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { bool can_edit = (node && node->get_mesh_library().is_valid()); @@ -638,10 +632,10 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In _do_paste(); input_action = INPUT_NONE; _update_paste_indicator(); - } else if (mb->get_shift() && can_edit) { + } else if (mb->is_shift_pressed() && can_edit) { input_action = INPUT_SELECT; last_selection = selection; - } else if (mb->get_command() && can_edit) { + } else if (mb->is_command_pressed() && can_edit) { input_action = INPUT_PICK; } else { input_action = INPUT_PAINT; @@ -732,7 +726,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In } } - if (k->get_shift() && selection.active && input_action != INPUT_PASTE) { + if (k->is_shift_pressed() && selection.active && input_action != INPUT_PASTE) { 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(); @@ -749,7 +743,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { - if (pan_gesture->get_alt() && (pan_gesture->get_command() || pan_gesture->get_shift())) { + if (pan_gesture->is_alt_pressed() && (pan_gesture->is_command_pressed() || pan_gesture->is_shift_pressed())) { const real_t delta = pan_gesture->get_delta().y * 0.5; accumulated_floor_delta += delta; int step = 0; @@ -810,7 +804,7 @@ void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) { const Ref<InputEventMouseButton> mb = p_ie; // Zoom in/out using Ctrl + mouse wheel - if (mb.is_valid() && mb->is_pressed() && mb->get_command()) { + if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed()) { if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { size_slider->set_value(size_slider->get_value() + 0.2); } @@ -1068,7 +1062,7 @@ void GridMapEditor::_notification(int p_what) { return; } - Transform xf = node->get_global_transform(); + Transform3D xf = node->get_global_transform(); if (xf != grid_xform) { for (int i = 0; i < 3; i++) { @@ -1080,26 +1074,22 @@ void GridMapEditor::_notification(int p_what) { if (cgmt.operator->() != last_mesh_library) { update_palette(); } - - if (lock_view) { - EditorNode *editor = Object::cast_to<EditorNode>(get_tree()->get_root()->get_child(0)); - - Plane p; - p.normal[edit_axis] = 1.0; - p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis]; - p = node->get_transform().xform(p); // plane to snap - - Node3DEditorPlugin *sep = Object::cast_to<Node3DEditorPlugin>(editor->get_editor_plugin_screen()); - if (sep) { - sep->snap_cursor_to_plane(p); - } - } } break; case NOTIFICATION_THEME_CHANGED: { options->set_icon(get_theme_icon("GridMap", "EditorIcons")); search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); } break; + + case NOTIFICATION_APPLICATION_FOCUS_OUT: { + if (input_action == INPUT_PAINT) { + // Simulate mouse released event to stop drawing when editor focus exists. + Ref<InputEventMouseButton> release; + release.instantiate(); + release->set_button_index(MOUSE_BUTTON_LEFT); + forward_spatial_input_event(nullptr, release); + } + } break; } } @@ -1187,8 +1177,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { spatial_editor_hb->hide(); options->set_text(TTR("Grid Map")); - options->get_popup()->add_check_item(TTR("Snap View"), MENU_OPTION_LOCK_VIEW); - options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Previous Floor"), MENU_OPTION_PREV_LEVEL, KEY_Q); options->get_popup()->add_item(TTR("Next Floor"), MENU_OPTION_NEXT_LEVEL, KEY_E); options->get_popup()->add_separator(); @@ -1283,7 +1271,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { info_message->set_text(TTR("Give a MeshLibrary resource to this GridMap to use its meshes.")); info_message->set_valign(Label::VALIGN_CENTER); info_message->set_align(Label::ALIGN_CENTER); - info_message->set_autowrap(true); + info_message->set_autowrap_mode(Label::AUTOWRAP_WORD_SMART); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); mesh_library_palette->add_child(info_message); @@ -1368,7 +1356,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { Array d; d.resize(RS::ARRAY_MAX); - inner_mat.instance(); + inner_mat.instantiate(); inner_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.2)); inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); @@ -1377,14 +1365,14 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_TRIANGLES, d); RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid()); - outer_mat.instance(); + outer_mat.instantiate(); outer_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.8)); outer_mat->set_on_top_of_alpha(); outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - selection_floor_mat.instance(); + selection_floor_mat.instantiate(); selection_floor_mat->set_albedo(Color(0.80, 0.80, 1.0, 1)); selection_floor_mat->set_on_top_of_alpha(); selection_floor_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); @@ -1411,7 +1399,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { _set_selection(false); - indicator_mat.instance(); + indicator_mat.instantiate(); indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); indicator_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 6c7f0bedf6..4bc849e071 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -94,9 +94,8 @@ class GridMapEditor : public VBoxContainer { MeshLibrary *last_mesh_library; ClipMode clip_mode = CLIP_DISABLED; - bool lock_view = false; - Transform grid_xform; - Transform edit_grid_xform; + Transform3D grid_xform; + Transform3D edit_grid_xform; Vector3::Axis edit_axis; int edit_floor[3]; Vector3 grid_ofs; @@ -146,7 +145,7 @@ class GridMapEditor : public VBoxContainer { PasteIndicator paste_indicator; bool cursor_visible = false; - Transform cursor_transform; + Transform3D cursor_transform; Vector3 cursor_origin; diff --git a/modules/gridmap/icons/GridMap.svg b/modules/gridmap/icons/GridMap.svg index 7a36fd888c..e208257855 100644 --- a/modules/gridmap/icons/GridMap.svg +++ b/modules/gridmap/icons/GridMap.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc9c9c" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg> diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp index 5680664213..85739d202e 100644 --- a/modules/gridmap/register_types.cpp +++ b/modules/gridmap/register_types.cpp @@ -37,7 +37,7 @@ void register_gridmap_types() { #ifndef _3D_DISABLED - ClassDB::register_class<GridMap>(); + GDREGISTER_CLASS(GridMap); #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<GridMapEditorPlugin>(); #endif diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index 7daf6a3a57..b5e4753e8d 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -105,7 +105,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; - int src_image_len = f->get_len(); + uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); src_image.resize(src_image_len); @@ -127,7 +127,7 @@ void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const static Ref<Image> _jpegd_mem_loader_func(const uint8_t *p_png, int p_size) { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = jpeg_load_image_from_buffer(img.ptr(), p_png, p_size); ERR_FAIL_COND_V(err, Ref<Image>()); return img; diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp index 306c0ff087..3d0759d83e 100644 --- a/modules/jsonrpc/jsonrpc.cpp +++ b/modules/jsonrpc/jsonrpc.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "jsonrpc.h" + #include "core/io/json.h" JSONRPC::JSONRPC() { @@ -156,19 +157,17 @@ String JSONRPC::process_string(const String &p_input) { } Variant ret; - Variant input; - String err_message; - int err_line; - if (OK != JSON::parse(p_input, input, err_message, err_line)) { - ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error"); + JSON json; + if (json.parse(p_input) == OK) { + ret = process_action(json.get_data(), true); } else { - ret = process_action(input, true); + ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error"); } if (ret.get_type() == Variant::NIL) { return ""; } - return JSON::print(ret); + return ret.to_json_string(); } void JSONRPC::set_scope(const String &p_scope, Object *p_obj) { diff --git a/modules/jsonrpc/register_types.cpp b/modules/jsonrpc/register_types.cpp index d6b565ba84..8fdf6fe1aa 100644 --- a/modules/jsonrpc/register_types.cpp +++ b/modules/jsonrpc/register_types.cpp @@ -33,7 +33,7 @@ #include "jsonrpc.h" void register_jsonrpc_types() { - ClassDB::register_class<JSONRPC>(); + GDREGISTER_CLASS(JSONRPC); } void unregister_jsonrpc_types() { diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 61ebabdfb6..b75cf6502e 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -162,8 +162,8 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ MeshInstance &mi = mesh_instances.write[m_i]; Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height()); sizes.push_back(s); - atlas_size.width = MAX(atlas_size.width, s.width); - atlas_size.height = MAX(atlas_size.height, s.height); + atlas_size.width = MAX(atlas_size.width, s.width + 2); + atlas_size.height = MAX(atlas_size.height, s.height + 2); } int max = nearest_power_of_2_templated(atlas_size.width); @@ -186,10 +186,12 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ //determine best texture array atlas size by bruteforce fitting while (atlas_size.x <= p_max_texture_size && atlas_size.y <= p_max_texture_size) { - Vector<Vector2i> source_sizes = sizes; + Vector<Vector2i> source_sizes; Vector<int> source_indices; - source_indices.resize(source_sizes.size()); + source_sizes.resize(sizes.size()); + source_indices.resize(sizes.size()); for (int i = 0; i < source_indices.size(); i++) { + source_sizes.write[i] = sizes[i] + Vector2i(2, 2); // Add padding between lightmaps source_indices.write[i] = i; } Vector<Vector3i> atlas_offsets; @@ -207,7 +209,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ if (ofs.z > 0) { //valid ofs.z = slices; - atlas_offsets.write[sidx] = ofs; + atlas_offsets.write[sidx] = ofs + Vector3i(1, 1, 0); // Center lightmap in the reserved oversized region } else { new_indices.push_back(sidx); new_sources.push_back(source_sizes[i]); @@ -246,13 +248,13 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ for (int i = 0; i < atlas_slices; i++) { Ref<Image> albedo; - albedo.instance(); + albedo.instantiate(); albedo->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBA8); albedo->set_as_black(); albedo_images.write[i] = albedo; Ref<Image> emission; - emission.instance(); + emission.instantiate(); emission->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH); emission->set_as_black(); emission_images.write[i] = emission; @@ -272,7 +274,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ return BAKE_OK; } -void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) { +void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) { HashMap<Vertex, uint32_t, VertexHash> vertex_map; //fill triangles array and vertex array @@ -432,10 +434,10 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i triangle_indices.resize(triangle_sort.size()); Vector<uint32_t> grid_indices; grid_indices.resize(grid_size * grid_size * grid_size * 2); - zeromem(grid_indices.ptrw(), grid_indices.size() * sizeof(uint32_t)); + memset(grid_indices.ptrw(), 0, grid_indices.size() * sizeof(uint32_t)); Vector<bool> solid; solid.resize(grid_size * grid_size * grid_size); - zeromem(solid.ptrw(), solid.size() * sizeof(bool)); + memset(solid.ptrw(), 0, solid.size() * sizeof(bool)); { uint32_t *tiw = triangle_indices.ptrw(); @@ -477,19 +479,11 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i } Ref<Image> img; - img.instance(); + img.instantiate(); img->create(grid_size, grid_size, false, Image::FORMAT_L8, grid_usage); img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png"); } #endif - if (p_step_function) { - p_step_function(0.45, TTR("Generating Signed Distance Field"), p_bake_userdata, true); - } - - //generate SDF for raytracing - Vector<uint32_t> euclidean_pos = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), false); - Vector<uint32_t> euclidean_neg = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), true); - Vector<int8_t> sdf8 = Geometry3D::generate_sdf8(euclidean_pos, euclidean_neg); /*****************************/ /*** CREATE GPU STRUCTURES ***/ @@ -551,10 +545,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i tf.format = RD::DATA_FORMAT_R32G32_UINT; texdata.write[0] = grid_indices.to_byte_array(); grid_texture = rd->texture_create(tf, RD::TextureView(), texdata); - //sdf - tf.format = RD::DATA_FORMAT_R8_SNORM; - texdata.write[0] = sdf8.to_byte_array(); - grid_texture_sdf = rd->texture_create(tf, RD::TextureView(), texdata); } } @@ -735,7 +725,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d panorama_tex = p_environment_panorama; panorama_tex->convert(Image::FORMAT_RGBAF); } else { - panorama_tex.instance(); + panorama_tex.instantiate(); panorama_tex->create(8, 8, false, Image::FORMAT_RGBAF); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { @@ -755,8 +745,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d light_environment_tex = rd->texture_create(tfp, RD::TextureView(), tdata); #ifdef DEBUG_TEXTURES - panorama_tex->convert(Image::FORMAT_RGB8); - panorama_tex->save_png("res://0_panorama.png"); + panorama_tex->save_exr("res://0_panorama.exr", false); #endif } } @@ -770,7 +759,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RID lights_buffer; RID triangle_cell_indices_buffer; RID grid_texture; - RID grid_texture_sdf; RID seams_buffer; RID probe_positions_buffer; @@ -783,11 +771,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d rd->free(lights_buffer); \ rd->free(triangle_cell_indices_buffer); \ rd->free(grid_texture); \ - rd->free(grid_texture_sdf); \ rd->free(seams_buffer); \ rd->free(probe_positions_buffer); - _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, grid_texture_sdf, seams_buffer, p_step_function, p_bake_userdata); + _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata); if (p_step_function) { p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true); @@ -795,7 +782,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d //shaders Ref<RDShaderFile> raster_shader; - raster_shader.instance(); + raster_shader.instantiate(); Error err = raster_shader->parse_versions_from_text(lm_raster_shader_glsl); if (err != OK) { raster_shader->print_errors("raster_shader"); @@ -883,27 +870,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; - u.ids.push_back(grid_texture_sdf); - base_uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 10; u.ids.push_back(albedo_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 11; + u.binding = 10; u.ids.push_back(emission_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 12; + u.binding = 11; u.ids.push_back(sampler); base_uniforms.push_back(u); } @@ -935,15 +915,13 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices; i++) { Vector<uint8_t> s = rd->texture_get_data(position_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s); - img->convert(Image::FORMAT_RGBA8); - img->save_png("res://1_position_" + itos(i) + ".png"); + img->save_exr("res://1_position_" + itos(i) + ".exr", false); s = rd->texture_get_data(normal_tex, i); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); - img->convert(Image::FORMAT_RGBA8); - img->save_png("res://1_normal_" + itos(i) + ".png"); + img->save_exr("res://1_normal_" + itos(i) + ".exr", false); } #endif @@ -955,7 +933,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d /* Plot direct light */ Ref<RDShaderFile> compute_shader; - compute_shader.instance(); + compute_shader.instantiate(); err = compute_shader->parse_versions_from_text(lm_compute_shader_glsl, p_bake_sh ? "\n#define USE_SH_LIGHTMAPS\n" : ""); if (err != OK) { FREE_TEXTURES @@ -966,27 +944,27 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); - //unoccluder + // Unoccluder RID compute_shader_unocclude = rd->shader_create_from_bytecode(compute_shader->get_bytecode("unocclude")); ERR_FAIL_COND_V(compute_shader_unocclude.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen RID compute_shader_unocclude_pipeline = rd->compute_pipeline_create(compute_shader_unocclude); - //direct light + // Direct light RID compute_shader_primary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("primary")); ERR_FAIL_COND_V(compute_shader_primary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen RID compute_shader_primary_pipeline = rd->compute_pipeline_create(compute_shader_primary); - //indirect light + // Indirect light RID compute_shader_secondary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("secondary")); ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary); - //dilate + // Dilate RID compute_shader_dilate = rd->shader_create_from_bytecode(compute_shader->get_bytecode("dilate")); ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate); - //dilate + // Light probes RID compute_shader_light_probes = rd->shader_create_from_bytecode(compute_shader->get_bytecode("light_probes")); ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen RID compute_shader_light_probes_pipeline = rd->compute_pipeline_create(compute_shader_light_probes); @@ -1151,10 +1129,9 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices; i++) { Vector<uint8_t> s = rd->texture_get_data(light_source_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); - img->convert(Image::FORMAT_RGBA8); - img->save_png("res://2_light_primary_" + itos(i) + ".png"); + img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false); } #endif @@ -1212,7 +1189,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; - u.ids.push_back(light_environment_tex); //reuse unocclude tex + u.ids.push_back(light_environment_tex); uniforms.push_back(u); } } @@ -1298,7 +1275,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } } } + + if (b == 0) { + // This disables the environment for subsequent bounces + push_constant.environment_xform[3] = -99.0f; + } } + + // Restore the correct environment transform + push_constant.environment_xform[3] = 0.0f; } /* LIGHPROBES */ @@ -1394,12 +1379,12 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d #if 0 for (int i = 0; i < probe_positions.size(); i++) { Ref<Image> img; - img.instance(); + img.instantiate(); img->create(6, 4, false, Image::FORMAT_RGB8); for (int j = 0; j < 6; j++) { Vector<uint8_t> s = rd->texture_get_data(lightprobe_tex, i * 6 + j); Ref<Image> img2; - img2.instance(); + img2.instantiate(); img2->create(2, 2, false, Image::FORMAT_RGBAF, s); img2->convert(Image::FORMAT_RGB8); img->blit_rect(img2, Rect2(0, 0, 2, 2), Point2((j % 3) * 2, (j / 3) * 2)); @@ -1420,7 +1405,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); Ref<Image> denoised = denoiser->denoise_image(img); @@ -1447,10 +1432,9 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); - img->convert(Image::FORMAT_RGBA8); - img->save_png("res://4_light_secondary_" + itos(i) + ".png"); + img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false); } #endif @@ -1500,7 +1484,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->convert(Image::FORMAT_RGBA8); img->save_png("res://5_dilated_" + itos(i) + ".png"); @@ -1510,7 +1494,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d /* BLEND SEAMS */ //shaders Ref<RDShaderFile> blendseams_shader; - blendseams_shader.instance(); + blendseams_shader.instantiate(); err = blendseams_shader->parse_versions_from_text(lm_blendseams_shader_glsl); if (err != OK) { FREE_TEXTURES @@ -1582,6 +1566,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d clear_colors.push_back(Color(0, 0, 0, 1)); for (int i = 0; i < atlas_slices; i++) { int subslices = (p_bake_sh ? 4 : 1); + + if (slice_seam_count[i] == 0) { + continue; + } + for (int k = 0; k < subslices; k++) { RasterSeamsPushConstant seams_push_constant; seams_push_constant.slice = uint32_t(i * subslices + k); @@ -1652,10 +1641,9 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); - img->convert(Image::FORMAT_RGBA8); - img->save_png("res://5_blendseams" + itos(i) + ".png"); + img->save_exr("res://5_blendseams" + itos(i) + ".exr", false); } #endif if (p_step_function) { @@ -1665,7 +1653,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->convert(Image::FORMAT_RGBH); //remove alpha bake_textures.push_back(img); @@ -1674,15 +1662,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d if (probe_positions.size() > 0) { probe_values.resize(probe_positions.size() * 9); Vector<uint8_t> probe_data = rd->buffer_get_data(light_probe_buffer); - copymem(probe_values.ptrw(), probe_data.ptr(), probe_data.size()); + memcpy(probe_values.ptrw(), probe_data.ptr(), probe_data.size()); rd->free(light_probe_buffer); #ifdef DEBUG_TEXTURES { Ref<Image> img2; - img2.instance(); + img2.instantiate(); img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data); - img2->save_png("res://6_lightprobes.png"); + img2->save_exr("res://6_lightprobes.exr", false); } #endif } @@ -1743,7 +1731,7 @@ Vector<Color> LightmapperRD::get_bake_probe_sh(int p_probe) const { ERR_FAIL_INDEX_V(p_probe, probe_positions.size(), Vector<Color>()); Vector<Color> ret; ret.resize(9); - copymem(ret.ptrw(), &probe_values[p_probe * 9], sizeof(Color) * 9); + memcpy(ret.ptrw(), &probe_values[p_probe * 9], sizeof(Color) * 9); return ret; } diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h index f2a826a447..7ab7f34464 100644 --- a/modules/lightmapper_rd/lightmapper_rd.h +++ b/modules/lightmapper_rd/lightmapper_rd.h @@ -231,7 +231,7 @@ class LightmapperRD : public Lightmapper { Vector<Color> probe_values; BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata); - void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata); + void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata); void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform); public: diff --git a/modules/lightmapper_rd/lm_blendseams.glsl b/modules/lightmapper_rd/lm_blendseams.glsl index e47e5fcc51..374c48082e 100644 --- a/modules/lightmapper_rd/lm_blendseams.glsl +++ b/modules/lightmapper_rd/lm_blendseams.glsl @@ -7,7 +7,7 @@ triangles = "#define MODE_TRIANGLES"; #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "lm_common_inc.glsl" @@ -74,7 +74,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "lm_common_inc.glsl" diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl index f8a0cd16de..1581639036 100644 --- a/modules/lightmapper_rd/lm_common_inc.glsl +++ b/modules/lightmapper_rd/lm_common_inc.glsl @@ -84,9 +84,8 @@ layout(set = 0, binding = 7, std430) restrict readonly buffer Probes { probe_positions; layout(set = 0, binding = 8) uniform utexture3D grid; -layout(set = 0, binding = 9) uniform texture3D grid_sdf; -layout(set = 0, binding = 10) uniform texture2DArray albedo_tex; -layout(set = 0, binding = 11) uniform texture2DArray emission_tex; +layout(set = 0, binding = 9) uniform texture2DArray albedo_tex; +layout(set = 0, binding = 10) uniform texture2DArray emission_tex; -layout(set = 0, binding = 12) uniform sampler linear_sampler; +layout(set = 0, binding = 11) uniform sampler linear_sampler; diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index eb9d817f99..9ca40535f9 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -10,7 +10,7 @@ light_probes = "#define MODE_LIGHT_PROBES"; #version 450 -VERSION_DEFINES +#VERSION_DEFINES // One 2D local group focusing in one layer at a time, though all // in parallel (no barriers) makes more sense than a 3D local group @@ -96,15 +96,22 @@ params; 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 vec3 e0 = p1 - p0; const vec3 e1 = p0 - p2; - vec3 triangleNormal = cross(e1, e0); + vec3 triangle_normal = cross(e1, e0); - const vec3 e2 = (1.0 / dot(triangleNormal, dir)) * (p0 - from); + float n_dot_dir = dot(triangle_normal, dir); + + if (abs(n_dot_dir) < 0.01) { + return false; + } + + const vec3 e2 = (p0 - from) / n_dot_dir; const vec3 i = cross(dir, e2); r_barycentric.y = dot(i, e1); r_barycentric.z = dot(i, e0); r_barycentric.x = 1.0 - (r_barycentric.z + r_barycentric.y); - r_distance = dot(triangleNormal, e2); + r_distance = dot(triangle_normal, e2); + return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0))); } @@ -307,8 +314,6 @@ void main() { continue; } - d /= lights.data[i].range; - attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation); if (lights.data[i].type == LIGHT_TYPE_SPOT) { @@ -410,7 +415,7 @@ void main() { uint tidx; vec3 barycentric; - vec3 light; + vec3 light = vec3(0.0); if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) { //hit a triangle vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv; @@ -419,8 +424,8 @@ void main() { vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice)); light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb; - } else { - //did not hit a triangle, reach out for the sky + } else 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( diff --git a/modules/lightmapper_rd/lm_raster.glsl b/modules/lightmapper_rd/lm_raster.glsl index 6c2904192b..55ca193cc1 100644 --- a/modules/lightmapper_rd/lm_raster.glsl +++ b/modules/lightmapper_rd/lm_raster.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "lm_common_inc.glsl" @@ -56,7 +56,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "lm_common_inc.glsl" diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp index 191bb3d765..ae9c5fc390 100644 --- a/modules/lightmapper_rd/register_types.cpp +++ b/modules/lightmapper_rd/register_types.cpp @@ -54,7 +54,7 @@ void register_lightmapper_rd_types() { GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048); GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64); #ifndef _3D_DISABLED - ClassDB::register_class<LightmapperRD>(); + GDREGISTER_CLASS(LightmapperRD); Lightmapper::create_gpu = create_lightmapper_rd; #endif } diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index 73931b0365..2522f1bb11 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -30,7 +30,7 @@ #include "crypto_mbedtls.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/config/engine.h" #include "core/config/project_settings.h" @@ -58,7 +58,7 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { FileAccess *f = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); - int flen = f->get_len(); + uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator @@ -146,7 +146,7 @@ Error X509CertificateMbedTLS::load(String p_path) { FileAccess *f = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); - int flen = f->get_len(); + uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator @@ -249,6 +249,13 @@ PackedByteArray HMACContextMbedTLS::finish() { return out; } +HMACContextMbedTLS::~HMACContextMbedTLS() { + if (ctx != nullptr) { + mbedtls_md_free((mbedtls_md_context_t *)ctx); + memfree((mbedtls_md_context_t *)ctx); + } +} + Crypto *CryptoMbedTLS::create() { return memnew(CryptoMbedTLS); } @@ -324,7 +331,7 @@ void CryptoMbedTLS::load_default_certificates(String p_path) { Ref<CryptoKey> CryptoMbedTLS::generate_rsa(int p_bytes) { Ref<CryptoKeyMbedTLS> out; - out.instance(); + out.instantiate(); int ret = mbedtls_pk_setup(&(out->pkey), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); ERR_FAIL_COND_V(ret != 0, nullptr); ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(out->pkey), mbedtls_ctr_drbg_random, &ctr_drbg, p_bytes, 65537); @@ -366,7 +373,7 @@ Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoK buf[4095] = '\0'; // Make sure strlen can't fail. Ref<X509CertificateMbedTLS> out; - out.instance(); + out.instantiate(); out->load_from_memory(buf, strlen((char *)buf) + 1); // Use strlen to find correct output size. return out; } @@ -409,7 +416,7 @@ Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector int ret = mbedtls_pk_sign(&(key->pkey), type, p_hash.ptr(), size, buf, &sig_size, mbedtls_ctr_drbg_random, &ctr_drbg); ERR_FAIL_COND_V_MSG(ret, out, "Error while signing: " + itos(ret)); out.resize(sig_size); - copymem(out.ptrw(), buf, sig_size); + memcpy(out.ptrw(), buf, sig_size); return out; } @@ -432,7 +439,7 @@ Vector<uint8_t> CryptoMbedTLS::encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_p int ret = mbedtls_pk_encrypt(&(key->pkey), p_plaintext.ptr(), p_plaintext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg); ERR_FAIL_COND_V_MSG(ret, out, "Error while encrypting: " + itos(ret)); out.resize(size); - copymem(out.ptrw(), buf, size); + memcpy(out.ptrw(), buf, size); return out; } @@ -446,6 +453,6 @@ Vector<uint8_t> CryptoMbedTLS::decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_c int ret = mbedtls_pk_decrypt(&(key->pkey), p_ciphertext.ptr(), p_ciphertext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg); ERR_FAIL_COND_V_MSG(ret, out, "Error while decrypting: " + itos(ret)); out.resize(size); - copymem(out.ptrw(), buf, size); + memcpy(out.ptrw(), buf, size); return out; } diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h index 5ced4d136c..afa1ea7a64 100644 --- a/modules/mbedtls/crypto_mbedtls.h +++ b/modules/mbedtls/crypto_mbedtls.h @@ -119,6 +119,7 @@ public: virtual PackedByteArray finish(); HMACContextMbedTLS() {} + ~HMACContextMbedTLS(); }; class CryptoMbedTLS : public Crypto { diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp index 5d895d8579..b1b6b3844b 100644 --- a/modules/mbedtls/dtls_server_mbedtls.cpp +++ b/modules/mbedtls/dtls_server_mbedtls.cpp @@ -45,7 +45,7 @@ void DTLSServerMbedTLS::stop() { Ref<PacketPeerDTLS> DTLSServerMbedTLS::take_connection(Ref<PacketPeerUDP> p_udp_peer) { Ref<PacketPeerMbedDTLS> out; - out.instance(); + out.instantiate(); ERR_FAIL_COND_V(!out.is_valid(), out); ERR_FAIL_COND_V(!p_udp_peer.is_valid(), out); @@ -68,7 +68,7 @@ void DTLSServerMbedTLS::finalize() { } DTLSServerMbedTLS::DTLSServerMbedTLS() { - _cookies.instance(); + _cookies.instantiate(); } DTLSServerMbedTLS::~DTLSServerMbedTLS() { diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp index 8a6cdfb131..114bf49e9e 100644 --- a/modules/mbedtls/packet_peer_mbed_dtls.cpp +++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp @@ -31,8 +31,8 @@ #include "packet_peer_mbed_dtls.h" #include "mbedtls/platform_util.h" +#include "core/io/file_access.h" #include "core/io/stream_peer_ssl.h" -#include "core/os/file_access.h" int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { if (buf == nullptr || len <= 0) { @@ -74,7 +74,7 @@ int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) { if (err != OK) { return MBEDTLS_ERR_SSL_INTERNAL_ERROR; } - copymem(buf, buffer, buffer_size); + memcpy(buf, buffer, buffer_size); return buffer_size; } @@ -87,10 +87,10 @@ void PacketPeerMbedDTLS::_cleanup() { int PacketPeerMbedDTLS::_set_cookie() { // Setup DTLS session cookie for this client uint8_t client_id[18]; - IP_Address addr = base->get_packet_address(); + IPAddress addr = base->get_packet_address(); uint16_t port = base->get_packet_port(); - copymem(client_id, addr.get_ipv6(), 16); - copymem(&client_id[16], (uint8_t *)&port, 2); + memcpy(client_id, addr.get_ipv6(), 16); + memcpy(&client_id[16], (uint8_t *)&port, 2); return mbedtls_ssl_set_client_transport_id(ssl_ctx->get_context(), client_id, 18); } @@ -245,7 +245,7 @@ int PacketPeerMbedDTLS::get_max_packet_size() const { } PacketPeerMbedDTLS::PacketPeerMbedDTLS() { - ssl_ctx.instance(); + ssl_ctx.instantiate(); } PacketPeerMbedDTLS::~PacketPeerMbedDTLS() { diff --git a/modules/mbedtls/ssl_context_mbedtls.h b/modules/mbedtls/ssl_context_mbedtls.h index 30632018a8..1b55a54a10 100644 --- a/modules/mbedtls/ssl_context_mbedtls.h +++ b/modules/mbedtls/ssl_context_mbedtls.h @@ -33,9 +33,9 @@ #include "crypto_mbedtls.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include <mbedtls/config.h> #include <mbedtls/ctr_drbg.h> @@ -46,7 +46,7 @@ class SSLContextMbedTLS; -class CookieContextMbedTLS : public Reference { +class CookieContextMbedTLS : public RefCounted { friend class SSLContextMbedTLS; protected: @@ -63,7 +63,7 @@ public: ~CookieContextMbedTLS(); }; -class SSLContextMbedTLS : public Reference { +class SSLContextMbedTLS : public RefCounted { protected: bool inited = false; diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp index b39a6ecc2f..5727f5f82f 100644 --- a/modules/mbedtls/stream_peer_mbedtls.cpp +++ b/modules/mbedtls/stream_peer_mbedtls.cpp @@ -30,8 +30,8 @@ #include "stream_peer_mbedtls.h" +#include "core/io/file_access.h" #include "core/io/stream_peer_tcp.h" -#include "core/os/file_access.h" int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { if (buf == nullptr || len <= 0) { @@ -242,7 +242,7 @@ void StreamPeerMbedTLS::poll() { return; } - // We could pass NULL as second parameter, but some behaviour sanitizers don't seem to like that. + // We could pass nullptr as second parameter, but some behaviour sanitizers don't seem to like that. // Passing a 1 byte buffer to workaround it. uint8_t byte; int ret = mbedtls_ssl_read(ssl_ctx->get_context(), &byte, 0); @@ -273,7 +273,7 @@ int StreamPeerMbedTLS::get_available_bytes() const { } StreamPeerMbedTLS::StreamPeerMbedTLS() { - ssl_ctx.instance(); + ssl_ctx.instantiate(); } StreamPeerMbedTLS::~StreamPeerMbedTLS() { diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.cpp b/modules/mbedtls/tests/test_crypto_mbedtls.cpp index 4217497082..8762838883 100644 --- a/modules/mbedtls/tests/test_crypto_mbedtls.cpp +++ b/modules/mbedtls/tests/test_crypto_mbedtls.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "modules/mbedtls/tests/test_crypto_mbedtls.h" +#include "test_crypto_mbedtls.h" #include "modules/mbedtls/crypto_mbedtls.h" #include "tests/test_macros.h" diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py index 82e4e43397..b7e69569b9 100644 --- a/modules/meshoptimizer/config.py +++ b/modules/meshoptimizer/config.py @@ -1,6 +1,6 @@ def can_build(env, platform): # Having this on release by default, it's small and a lot of users like to do procedural stuff - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp index a03310f518..77cc82a4e2 100644 --- a/modules/meshoptimizer/register_types.cpp +++ b/modules/meshoptimizer/register_types.cpp @@ -35,6 +35,7 @@ void register_meshoptimizer_types() { SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache; SurfaceTool::simplify_func = meshopt_simplify; + SurfaceTool::simplify_with_attrib_func = meshopt_simplifyWithAttributes; SurfaceTool::simplify_scale_func = meshopt_simplifyScale; SurfaceTool::simplify_sloppy_func = meshopt_simplifySloppy; } diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index b128b81000..2cc974322d 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -35,7 +35,7 @@ #include "audio_stream_mp3.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { ERR_FAIL_COND(!active); @@ -99,8 +99,9 @@ float AudioStreamPlaybackMP3::get_playback_position() const { } void AudioStreamPlaybackMP3::seek(float p_time) { - if (!active) + if (!active) { return; + } if (p_time >= mp3_stream->get_length()) { p_time = 0; @@ -125,7 +126,7 @@ Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() { "to it. AudioStreamMP3 should not be created from the " "inspector or with `.new()`. Instead, load an audio file."); - mp3s.instance(); + mp3s.instantiate(); mp3s->mp3_stream = Ref<AudioStreamMP3>(this); mp3s->mp3d = (mp3dec_ex_t *)memalloc(sizeof(mp3dec_ex_t)); @@ -171,7 +172,7 @@ void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) { clear_data(); data = memalloc(src_data_len); - copymem(data, src_datar, src_data_len); + memcpy(data, src_datar, src_data_len); data_len = src_data_len; } @@ -182,7 +183,7 @@ Vector<uint8_t> AudioStreamMP3::get_data() const { vdata.resize(data_len); { uint8_t *w = vdata.ptrw(); - copymem(w, data, data_len); + memcpy(w, data, data_len); } } diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml index 92e777ca0f..5507329a18 100644 --- a/modules/minimp3/doc_classes/AudioStreamMP3.xml +++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()"> Contains the audio data in bytes. </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp index 4ab4c743d6..63f2589f42 100644 --- a/modules/minimp3/register_types.cpp +++ b/modules/minimp3/register_types.cpp @@ -41,11 +41,11 @@ void register_minimp3_types() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { Ref<ResourceImporterMP3> mp3_import; - mp3_import.instance(); + mp3_import.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(mp3_import); } #endif - ClassDB::register_class<AudioStreamMP3>(); + GDREGISTER_CLASS(AudioStreamMP3); } void unregister_minimp3_types() { diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index afd26fb79e..dc360c12ba 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -30,8 +30,8 @@ #include "resource_importer_mp3.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "scene/resources/texture.h" String ResourceImporterMP3::get_importer_name() const { @@ -79,7 +79,7 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); - size_t len = f->get_len(); + uint64_t len = f->get_length(); Vector<uint8_t> data; data.resize(len); @@ -90,7 +90,7 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s memdelete(f); Ref<AudioStreamMP3> mp3_stream; - mp3_stream.instance(); + mp3_stream.instantiate(); mp3_stream->set_data(data); ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT); diff --git a/modules/mobile_vr/config.py b/modules/mobile_vr/config.py index ee401c1a2a..f6b64fb690 100644 --- a/modules/mobile_vr/config.py +++ b/modules/mobile_vr/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 5140cfbbaf..590b95ab79 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -185,8 +185,8 @@ void MobileVRInterface::set_position_from_sensors() { // if you have a gyro + accelerometer that combo tends to be better than combining all three but without a gyro you need the magnetometer.. if (has_magneto && has_grav && !has_gyro) { // convert to quaternions, easier to smooth those out - Quat transform_quat(orientation); - Quat acc_mag_quat(combine_acc_mag(grav, magneto)); + Quaternion transform_quat(orientation); + Quaternion acc_mag_quat(combine_acc_mag(grav, magneto)); transform_quat = transform_quat.slerp(acc_mag_quat, 0.1); orientation = Basis(transform_quat); @@ -300,9 +300,9 @@ real_t MobileVRInterface::get_k2() const { return k2; }; -bool MobileVRInterface::is_stereo() { +uint32_t MobileVRInterface::get_view_count() { // needs stereo... - return true; + return 2; }; bool MobileVRInterface::is_initialized() const { @@ -361,10 +361,32 @@ Size2 MobileVRInterface::get_render_targetsize() { return target_size; }; -Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { +Transform3D MobileVRInterface::get_camera_transform() { _THREAD_SAFE_METHOD_ - Transform transform_for_eye; + Transform3D transform_for_eye; + + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, transform_for_eye); + + if (initialized) { + float world_scale = xr_server->get_world_scale(); + + // just scale our origin point of our transform + Transform3D hmd_transform; + hmd_transform.basis = orientation; + hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0); + + transform_for_eye = (xr_server->get_reference_frame()) * hmd_transform; + } + + return transform_for_eye; +}; + +Transform3D MobileVRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + _THREAD_SAFE_METHOD_ + + Transform3D transform_for_eye; XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, transform_for_eye); @@ -374,16 +396,16 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons // we don't need to check for the existence of our HMD, doesn't affect our values... // note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction... - if (p_eye == XRInterface::EYE_LEFT) { + if (p_view == 0) { transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale); - } else if (p_eye == XRInterface::EYE_RIGHT) { + } else if (p_view == 1) { transform_for_eye.origin.x = intraocular_dist * 0.01 * 0.5 * world_scale; } else { - // for mono we don't reposition, we want our center position. + // should not have any other values.. }; // just scale our origin point of our transform - Transform hmd_transform; + Transform3D hmd_transform; hmd_transform.basis = orientation; hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0); @@ -396,21 +418,13 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons return transform_for_eye; }; -CameraMatrix MobileVRInterface::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { _THREAD_SAFE_METHOD_ CameraMatrix eye; - if (p_eye == XRInterface::EYE_MONO) { - ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real camera's properties - // which probably means implementing a specific class for iOS and Android. For now this is purely here as an example. - // Note also that if you use a normal viewport with AR/VR turned off you can still use the tracker output of this interface - // to position a stock standard Godot camera and have control over this. - // This will make more sense when we implement ARkit on iOS (probably a separate interface). - eye.set_perspective(60.0, p_aspect, p_z_near, p_z_far, false); - } else { - eye.set_for_hmd(p_eye == XRInterface::EYE_LEFT ? 1 : 2, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far); - }; + aspect = p_aspect; + eye.set_for_hmd(p_view + 1, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far); return eye; }; @@ -440,6 +454,45 @@ void MobileVRInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_tar eye_center.y = 0.0; } +Vector<BlitToScreen> MobileVRInterface::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { + _THREAD_SAFE_METHOD_ + + Vector<BlitToScreen> blit_to_screen; + + // We must have a valid render target + ERR_FAIL_COND_V(!p_render_target.is_valid(), blit_to_screen); + + // Because we are rendering to our device we must use our main viewport! + ERR_FAIL_COND_V(p_screen_rect == Rect2(), blit_to_screen); + + // and add our blits + BlitToScreen blit; + blit.render_target = p_render_target; + blit.multi_view.use_layer = true; + blit.lens_distortion.apply = true; + blit.lens_distortion.k1 = k1; + blit.lens_distortion.k2 = k2; + blit.lens_distortion.upscale = oversample; + blit.lens_distortion.aspect_ratio = aspect; + + // left eye + blit.rect = p_screen_rect; + blit.rect.size.width *= 0.5; + blit.multi_view.layer = 0; + blit.lens_distortion.eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0); + blit_to_screen.push_back(blit); + + // right eye + blit.rect = p_screen_rect; + blit.rect.size.width *= 0.5; + blit.rect.position.x = blit.rect.size.width; + blit.multi_view.layer = 1; + blit.lens_distortion.eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0); + blit_to_screen.push_back(blit); + + return blit_to_screen; +} + void MobileVRInterface::process() { _THREAD_SAFE_METHOD_ diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index d28c2196af..29ce0f92c8 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -63,9 +63,9 @@ private: real_t display_to_lens = 4.0; real_t oversample = 1.5; - //@TODO not yet used, these are needed in our distortion shader... real_t k1 = 0.215; real_t k2 = 0.215; + real_t aspect = 1.0; /* logic for processing our sensor data, this was originally in our positional tracker logic but I think @@ -138,16 +138,20 @@ public: virtual void uninitialize() override; virtual Size2 get_render_targetsize() override; - virtual bool is_stereo() override; - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; - virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void process() override; virtual void notification(int p_what) override {} MobileVRInterface(); ~MobileVRInterface(); + + // deprecated + virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; }; #endif // !MOBILE_VR_INTERFACE_H diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp index e7d33ba8a7..47d1fe482c 100644 --- a/modules/mobile_vr/register_types.cpp +++ b/modules/mobile_vr/register_types.cpp @@ -33,11 +33,11 @@ #include "mobile_vr_interface.h" void register_mobile_vr_types() { - ClassDB::register_class<MobileVRInterface>(); + GDREGISTER_CLASS(MobileVRInterface); if (XRServer::get_singleton()) { Ref<MobileVRInterface> mobile_vr; - mobile_vr.instance(); + mobile_vr.instantiate(); XRServer::get_singleton()->add_interface(mobile_vr); } } diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 309abfbff7..8e441e7e07 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -101,12 +101,6 @@ def configure(env, env_mono): mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"] - is_travis = os.environ.get("TRAVIS") == "true" - - if is_travis: - # Travis CI may have a Mono version lower than 5.12 - env_mono.Append(CPPDEFINES=["NO_PENDING_EXCEPTIONS"]) - if is_android and not env["android_arch"] in android_arch_dirs: raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"]) diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 553c6eca53..25193a1352 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -33,8 +33,8 @@ #ifdef DEBUG_METHODS_ENABLED #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/json.h" -#include "core/os/file_access.h" #include "core/version.h" void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { @@ -240,7 +240,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE); ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'."); - f->store_string(JSON::print(classes_dict, /*indent: */ "\t")); + JSON json; + f->store_string(json.stringify(classes_dict, "\t")); f->close(); print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 43f57a7caa..ff6a47f59b 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -37,8 +37,7 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/io/json.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/mutex.h" #include "core/os/os.h" #include "core/os/thread.h" @@ -304,6 +303,26 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const { } } +bool CSharpLanguage::is_control_flow_keyword(String p_keyword) const { + return p_keyword == "break" || + p_keyword == "case" || + p_keyword == "catch" || + p_keyword == "continue" || + p_keyword == "default" || + p_keyword == "do" || + p_keyword == "else" || + p_keyword == "finally" || + p_keyword == "for" || + p_keyword == "foreach" || + p_keyword == "goto" || + p_keyword == "if" || + p_keyword == "return" || + p_keyword == "switch" || + p_keyword == "throw" || + p_keyword == "try" || + p_keyword == "while"; +} + void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("//"); // single-line comment p_delimiters->push_back("/* */"); // delimited comment @@ -348,7 +367,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin "}\n"; // Replaces all spaces in p_class_name with underscores to prevent - // erronous C# Script templates from being generated when the object name + // invalid C# Script templates from being generated when the object name // has spaces in it. String class_name_no_spaces = p_class_name.replace(" ", "_"); String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces); @@ -356,7 +375,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin .replace("%CLASS%", class_name_no_spaces); Ref<CSharpScript> script; - script.instance(); + script.instantiate(); script->set_source_code(script_template); script->set_name(class_name_no_spaces); @@ -476,10 +495,10 @@ static String variant_type_to_managed_name(const String &p_var_type_name) { Variant::VECTOR3I, Variant::TRANSFORM2D, Variant::PLANE, - Variant::QUAT, + Variant::QUATERNION, Variant::AABB, Variant::BASIS, - Variant::TRANSFORM, + Variant::TRANSFORM3D, Variant::COLOR, Variant::STRING_NAME, Variant::NODE_PATH, @@ -843,13 +862,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { List<Ref<CSharpScript>> to_reload; // We need to keep reference instances alive during reloading - List<Ref<Reference>> ref_instances; + List<Ref<RefCounted>> rc_instances; for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { CSharpScriptBinding &script_binding = E->value(); - Reference *ref = Object::cast_to<Reference>(script_binding.owner); - if (ref) { - ref_instances.push_back(Ref<Reference>(ref)); + RefCounted *rc = Object::cast_to<RefCounted>(script_binding.owner); + if (rc) { + rc_instances.push_back(Ref<RefCounted>(rc)); } } @@ -872,9 +891,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { Object *obj = F->get(); script->pending_reload_instances.insert(obj->get_instance_id()); - Reference *ref = Object::cast_to<Reference>(obj); - if (ref) { - ref_instances.push_back(Ref<Reference>(ref)); + RefCounted *rc = Object::cast_to<RefCounted>(obj); + if (rc) { + rc_instances.push_back(Ref<RefCounted>(rc)); } } @@ -883,9 +902,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { Object *obj = F->get()->get_owner(); script->pending_reload_instances.insert(obj->get_instance_id()); - Reference *ref = Object::cast_to<Reference>(obj); - if (ref) { - ref_instances.push_back(Ref<Reference>(ref)); + RefCounted *rc = Object::cast_to<RefCounted>(obj); + if (rc) { + rc_instances.push_back(Ref<RefCounted>(rc)); } } #endif @@ -1418,16 +1437,16 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b r_script_binding.owner = p_object; // Tie managed to unmanaged - Reference *ref = Object::cast_to<Reference>(p_object); + RefCounted *rc = Object::cast_to<RefCounted>(p_object); - if (ref) { + if (rc) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) + // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) - ref->reference(); - CSharpLanguage::get_singleton()->post_unsafe_reference(ref); + rc->reference(); + CSharpLanguage::get_singleton()->post_unsafe_reference(rc); } return true; @@ -1491,10 +1510,11 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { } void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { - Reference *ref_owner = Object::cast_to<Reference>(p_object); +#if 0 + RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object); #ifdef DEBUG_ENABLED - CRASH_COND(!ref_owner); + CRASH_COND(!rc_owner); CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif @@ -1508,7 +1528,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { return; } - if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 GD_MONO_SCOPE_THREAD_ATTACH; // The reference count was increased after the managed side was the only one referencing our owner. @@ -1525,13 +1545,15 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { gchandle.release(); gchandle = strong_gchandle; } +#endif } bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { - Reference *ref_owner = Object::cast_to<Reference>(p_object); +#if 0 + RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object); #ifdef DEBUG_ENABLED - CRASH_COND(!ref_owner); + CRASH_COND(!rc_owner); CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif @@ -1541,7 +1563,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); MonoGCHandleData &gchandle = script_binding.gchandle; - int refcount = ref_owner->reference_get_count(); + int refcount = rc_owner->reference_get_count(); if (!script_binding.inited) { return refcount == 0; @@ -1567,18 +1589,20 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { } return refcount == 0; +#endif + return false; } CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) { CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script))); - Reference *ref = Object::cast_to<Reference>(p_owner); + RefCounted *rc = Object::cast_to<RefCounted>(p_owner); - instance->base_ref = ref != nullptr; + instance->base_ref_counted = rc != nullptr; instance->owner = p_owner; instance->gchandle = p_gchandle; - if (instance->base_ref) { + if (instance->base_ref_counted) { instance->_reference_owner_unsafe(); } @@ -1880,7 +1904,7 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, bool CSharpInstance::_reference_owner_unsafe() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); CRASH_COND(unsafe_referenced); // already referenced #endif @@ -1891,7 +1915,7 @@ bool CSharpInstance::_reference_owner_unsafe() { // See: _unreference_owner_unsafe() // May not me referenced yet, so we must use init_ref() instead of reference() - if (static_cast<Reference *>(owner)->init_ref()) { + if (static_cast<RefCounted *>(owner)->init_ref()) { CSharpLanguage::get_singleton()->post_unsafe_reference(owner); unsafe_referenced = true; } @@ -1901,7 +1925,7 @@ bool CSharpInstance::_reference_owner_unsafe() { bool CSharpInstance::_unreference_owner_unsafe() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); #endif @@ -1918,7 +1942,7 @@ bool CSharpInstance::_unreference_owner_unsafe() { // Destroying the owner here means self destructing, so we defer the owner destruction to the caller. CSharpLanguage::get_singleton()->pre_unsafe_unreference(owner); - return static_cast<Reference *>(owner)->unreference(); + return static_cast<RefCounted *>(owner)->unreference(); } MonoObject *CSharpInstance::_internal_new_managed() { @@ -1950,7 +1974,7 @@ MonoObject *CSharpInstance::_internal_new_managed() { // Tie managed to unmanaged gchandle = MonoGCHandleData::new_strong_handle(mono_object); - if (base_ref) { + if (base_ref_counted) { _reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback) } @@ -1967,7 +1991,7 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) { disconnect_event_signals(); #ifdef DEBUG_ENABLED - CRASH_COND(base_ref); + CRASH_COND(base_ref_counted); CRASH_COND(gchandle.is_released()); #endif CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle); @@ -1975,7 +1999,7 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) { void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(gchandle.is_released()); #endif @@ -2016,7 +2040,7 @@ void CSharpInstance::connect_event_signals() { StringName signal_name = event_signal.field->get_name(); // TODO: Use pooling for ManagedCallable instances. - auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal)); + EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, &event_signal)); Callable callable(event_signal_callable); connected_event_signals.push_back(callable); @@ -2027,7 +2051,7 @@ void CSharpInstance::connect_event_signals() { void CSharpInstance::disconnect_event_signals() { for (const List<Callable>::Element *E = connected_event_signals.front(); E; E = E->next()) { const Callable &callable = E->get(); - auto event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom()); + const EventSignalCallable *event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom()); owner->disconnect(event_signal_callable->get_signal(), callable); } @@ -2036,13 +2060,13 @@ void CSharpInstance::disconnect_event_signals() { void CSharpInstance::refcount_incremented() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); #endif - Reference *ref_owner = Object::cast_to<Reference>(owner); + RefCounted *rc_owner = Object::cast_to<RefCounted>(owner); - if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 GD_MONO_SCOPE_THREAD_ATTACH; // The reference count was increased after the managed side was the only one referencing our owner. @@ -2058,13 +2082,13 @@ void CSharpInstance::refcount_incremented() { bool CSharpInstance::refcount_decremented() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); #endif - Reference *ref_owner = Object::cast_to<Reference>(owner); + RefCounted *rc_owner = Object::cast_to<RefCounted>(owner); - int refcount = ref_owner->reference_get_count(); + int refcount = rc_owner->reference_get_count(); if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 GD_MONO_SCOPE_THREAD_ATTACH; @@ -2085,46 +2109,10 @@ bool CSharpInstance::refcount_decremented() { return ref_dying; } -Vector<ScriptNetData> CSharpInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> CSharpInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t CSharpInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName CSharpInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { - return script->get_rpc_method(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - return script->get_rpc_mode_by_id(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> CSharpInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t CSharpInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName CSharpInstance::get_rset_property(const uint16_t p_rset_member_id) const { - return script->get_rset_property(p_rset_member_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - return script->get_rset_mode_by_id(p_rset_member_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - void CSharpInstance::notification(int p_notification) { GD_MONO_SCOPE_THREAD_ATTACH; @@ -2135,12 +2123,12 @@ void CSharpInstance::notification(int p_notification) { predelete_notified = true; - if (base_ref) { - // It's not safe to proceed if the owner derives Reference and the refcount reached 0. + if (base_ref_counted) { + // It's not safe to proceed if the owner derives RefCounted and the refcount reached 0. // At this point, Dispose() was already called (manually or from the finalizer) so // that's not a problem. The refcount wouldn't have reached 0 otherwise, since the // managed side references it and Dispose() needs to be called to release it. - // However, this means C# Reference scripts can't receive NOTIFICATION_PREDELETE, but + // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784 return; } @@ -2266,23 +2254,25 @@ CSharpInstance::~CSharpInstance() { } // If not being called from the owner's destructor, and we still hold a reference to the owner - if (base_ref && !ref_dying && owner && unsafe_referenced) { + if (base_ref_counted && !ref_dying && owner && unsafe_referenced) { // The owner's script or script instance is being replaced (or removed) // Transfer ownership to an "instance binding" - Reference *ref_owner = static_cast<Reference *>(owner); + RefCounted *rc_owner = static_cast<RefCounted *>(owner); // We will unreference the owner before referencing it again, so we need to keep it alive - Ref<Reference> scope_keep_owner_alive(ref_owner); + Ref<RefCounted> scope_keep_owner_alive(rc_owner); (void)scope_keep_owner_alive; // Unreference the owner here, before the new "instance binding" references it. // Otherwise, the unsafe reference debug checks will incorrectly detect a bug. bool die = _unreference_owner_unsafe(); CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die - +#if 0 void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + + CRASH_COND(data == nullptr); CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -2299,7 +2289,8 @@ CSharpInstance::~CSharpInstance() { #ifdef DEBUG_ENABLED // The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope - CRASH_COND(ref_owner->reference_get_count() <= 1); + CRASH_COND(rc_owner->reference_get_count() <= 1); +#endif #endif } @@ -2386,7 +2377,7 @@ void CSharpScript::_update_member_info_no_exports() { } #endif -bool CSharpScript::_update_exports() { +bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_update) { #ifdef TOOLS_ENABLED bool is_editor = Engine::get_singleton()->is_editor_hint(); if (is_editor) { @@ -2527,7 +2518,7 @@ bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED if (is_editor) { // Need to check this here, before disposal - bool base_ref = Object::cast_to<Reference>(tmp_native) != nullptr; + bool base_ref_counted = Object::cast_to<RefCounted>(tmp_native) != nullptr; // Dispose the temporary managed instance @@ -2542,7 +2533,7 @@ bool CSharpScript::_update_exports() { GDMonoUtils::free_gchandle(tmp_pinned_gchandle); tmp_object = nullptr; - if (tmp_native && !base_ref) { + if (tmp_native && !base_ref_counted) { Node *node = Object::cast_to<Node>(tmp_native); if (node && node->is_inside_tree()) { ERR_PRINT("Temporary instance was added to the scene tree."); @@ -2558,14 +2549,18 @@ bool CSharpScript::_update_exports() { if (is_editor) { placeholder_fallback_enabled = false; - if (placeholders.size()) { + if ((changed || p_instance_to_update) && placeholders.size()) { // Update placeholders if any Map<StringName, Variant> values; List<PropertyInfo> propnames; _update_exports_values(values, propnames); - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); + if (changed) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->update(propnames, values); + } + } else { + p_instance_to_update->update(propnames, values); } } } @@ -3026,7 +3021,6 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native); p_script->rpc_functions.clear(); - p_script->rpc_variables.clear(); GDMonoClass *top = p_script->script_class; while (top && top != p_script->native) { @@ -3040,9 +3034,12 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { if (!methods[i]->is_static()) { MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]); if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = methods[i]->get_name(); - nd.mode = mode; + nd.rpc_mode = mode; + // TODO Transfer mode, channel + nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + nd.channel = 0; if (-1 == p_script->rpc_functions.find(nd)) { p_script->rpc_functions.push_back(nd); } @@ -3051,51 +3048,16 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { } } - { - Vector<GDMonoField *> fields = top->get_all_fields(); - for (int i = 0; i < fields.size(); i++) { - if (!fields[i]->is_static()) { - MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(fields[i]); - if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - ScriptNetData nd; - nd.name = fields[i]->get_name(); - nd.mode = mode; - if (-1 == p_script->rpc_variables.find(nd)) { - p_script->rpc_variables.push_back(nd); - } - } - } - } - } - - { - Vector<GDMonoProperty *> properties = top->get_all_properties(); - for (int i = 0; i < properties.size(); i++) { - if (!properties[i]->is_static()) { - MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(properties[i]); - if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - ScriptNetData nd; - nd.name = properties[i]->get_name(); - nd.mode = mode; - if (-1 == p_script->rpc_variables.find(nd)) { - p_script->rpc_variables.push_back(nd); - } - } - } - } - } - top = top->get_parent_class(); } // Sort so we are 100% that they are always the same. - p_script->rpc_functions.sort_custom<SortNetData>(); - p_script->rpc_variables.sort_custom<SortNetData>(); + p_script->rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); p_script->load_script_signals(p_script->script_class, p_script->native); } -bool CSharpScript::can_instance() const { +bool CSharpScript::can_instantiate() const { #ifdef TOOLS_ENABLED bool extra_cond = tool || ScriptServer::is_scripting_enabled(); #else @@ -3126,7 +3088,7 @@ StringName CSharpScript::get_instance_base_type() const { } } -CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) { +CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) { GD_MONO_ASSERT_THREAD_ATTACHED; /* STEP 1, CREATE */ @@ -3142,12 +3104,12 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg ERR_FAIL_V_MSG(nullptr, "Constructor not found."); } - Ref<Reference> ref; - if (p_isref) { + Ref<RefCounted> ref; + if (p_is_ref_counted) { // Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance. - ref = Ref<Reference>(static_cast<Reference *>(p_owner)); + ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner)); } - +#if 0 // If the object had a script instance binding, dispose it before adding the CSharpInstance if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) { void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); @@ -3169,9 +3131,9 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg script_binding.inited = false; } } - +#endif CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this))); - instance->base_ref = p_isref; + instance->base_ref_counted = p_is_ref_counted; instance->owner = p_owner; instance->owner->set_script_instance(instance); @@ -3196,7 +3158,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg // Tie managed to unmanaged instance->gchandle = MonoGCHandleData::new_strong_handle(mono_object); - if (instance->base_ref) { + if (instance->base_ref_counted) { instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback) } @@ -3228,10 +3190,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal GD_MONO_SCOPE_THREAD_ATTACH; - Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); + Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native)); REF ref; - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -3262,24 +3224,24 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { if (EngineDebugger::is_active()) { CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + String(native_name) + - "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + - "', so it can't be instanced in object of type: '" + p_this->get_class() + "'."); + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'."); } } GD_MONO_SCOPE_THREAD_ATTACH; Callable::CallError unchecked_error; - return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error); + return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error); } PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) { #ifdef TOOLS_ENABLED PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); placeholders.insert(si); - _update_exports(); + _update_exports(si); return si; #else return nullptr; @@ -3523,60 +3485,10 @@ MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_m return MultiplayerAPI::RPC_MODE_DISABLED; } -Vector<ScriptNetData> CSharpScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> CSharpScript::get_rpc_methods() const { return rpc_functions; } -uint16_t CSharpScript::get_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < rpc_functions.size(); i++) { - if (rpc_functions[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName CSharpScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName()); - return rpc_functions[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode(const StringName &p_method) const { - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> CSharpScript::get_rset_properties() const { - return rpc_variables; -} - -uint16_t CSharpScript::get_rset_property_id(const StringName &p_variable) const { - for (int i = 0; i < rpc_variables.size(); i++) { - if (rpc_variables[i].name == p_variable) { - return i; - } - } - return UINT16_MAX; -} - -StringName CSharpScript::get_rset_property(const uint16_t p_rset_member_id) const { - ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName()); - return rpc_variables[p_rset_member_id].name; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rset_member_id].mode; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rset_mode(const StringName &p_variable) const { - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - Error CSharpScript::load_source_code(const String &p_path) { Error ferr = read_all_file_utf8(p_path, source); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index dd93a86d7a..da6b60aee2 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -136,8 +136,7 @@ private: Map<StringName, EventSignal> event_signals; bool signals_invalidated = true; - Vector<ScriptNetData> rpc_functions; - Vector<ScriptNetData> rpc_variables; + Vector<MultiplayerAPI::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED List<PropertyInfo> exported_members_cache; // members_cache @@ -164,14 +163,14 @@ private: void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class); bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> ¶ms); - bool _update_exports(); + bool _update_exports(PlaceHolderScriptInstance *p_instance_to_update = nullptr); bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported); #ifdef TOOLS_ENABLED static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string); #endif - CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error); + CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error); Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); // Do not use unless you know what you are doing @@ -192,7 +191,7 @@ protected: void _get_property_list(List<PropertyInfo> *p_properties) const; public: - bool can_instance() const override; + bool can_instantiate() const override; StringName get_instance_base_type() const override; ScriptInstance *instance_create(Object *p_this) override; PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) override; @@ -235,17 +234,7 @@ public: int get_member_line(const StringName &p_member) const override; - Vector<ScriptNetData> get_rpc_methods() const override; - uint16_t get_rpc_method_id(const StringName &p_method) const override; - StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - Vector<ScriptNetData> get_rset_properties() const override; - uint16_t get_rset_property_id(const StringName &p_variable) const override; - StringName get_rset_property(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; } @@ -262,7 +251,7 @@ class CSharpInstance : public ScriptInstance { friend class CSharpLanguage; Object *owner = nullptr; - bool base_ref = false; + bool base_ref_counted = false; bool ref_dying = false; bool unsafe_referenced = false; bool predelete_notified = false; @@ -322,17 +311,7 @@ public: void refcount_incremented() override; bool refcount_decremented() override; - Vector<ScriptNetData> get_rpc_methods() const override; - uint16_t get_rpc_method_id(const StringName &p_method) const override; - StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - Vector<ScriptNetData> get_rset_properties() const override; - uint16_t get_rset_property_id(const StringName &p_variable) const override; - StringName get_rset_property(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; void notification(int p_notification) override; void _call_notification(int p_notification); @@ -470,14 +449,14 @@ public: /* EDITOR FUNCTIONS */ void get_reserved_words(List<String> *p_words) const override; + bool is_control_flow_keyword(String p_keyword) const override; void get_comment_delimiters(List<String> *p_delimiters) const override; void get_string_delimiters(List<String> *p_delimiters) const override; Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const override; bool is_using_templates() override; void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) override; - /* TODO */ bool validate(const String &p_script, int &r_line_error, int &r_col_error, - String &r_test_error, const String &p_path, List<String> *r_functions, - List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override { + /* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions, + List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override { return true; } String validate_path(const String &p_path) const override; diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs index 51055dc9b9..27737c3da0 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs @@ -7,7 +7,7 @@ using Path = System.IO.Path; namespace GodotTools.Build { [Serializable] - public sealed class BuildInfo : Reference // TODO Remove Reference once we have proper serialization + public sealed class BuildInfo : RefCounted // TODO Remove RefCounted once we have proper serialization { public string Solution { get; } public string[] Targets { get; } diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index 1a1639aac7..c380707587 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -11,7 +11,7 @@ namespace GodotTools.Build public class BuildOutputView : VBoxContainer, ISerializationListener { [Serializable] - private class BuildIssue : Reference // TODO Remove Reference once we have proper serialization + private class BuildIssue : RefCounted // TODO Remove RefCounted once we have proper serialization { public bool Warning { get; set; } public string File { get; set; } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 58561c5097..1faa6eeac0 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -26,8 +26,6 @@ namespace GodotTools private PopupMenu menuPopup; private AcceptDialog errorDialog; - private AcceptDialog aboutDialog; - private CheckBox aboutDialogCheckBox; private Button bottomPanelBtn; private Button toolBarBuildButton; @@ -130,13 +128,6 @@ namespace GodotTools toolBarBuildButton.Show(); } - private void _ShowAboutDialog() - { - bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start"); - aboutDialogCheckBox.Pressed = showOnStart; - aboutDialog.PopupCentered(); - } - private void _MenuOptionPressed(int id) { switch ((MenuOptions)id) @@ -144,9 +135,6 @@ namespace GodotTools case MenuOptions.CreateSln: CreateProjectSolution(); break; - case MenuOptions.AboutCSharp: - _ShowAboutDialog(); - break; case MenuOptions.SetupGodotNugetFallbackFolder: { try @@ -183,21 +171,11 @@ namespace GodotTools base._Ready(); MSBuildPanel.BuildOutputView.BuildStateChanged += BuildStateChanged; - - bool showInfoDialog = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start"); - if (showInfoDialog) - { - aboutDialog.Exclusive = true; - _ShowAboutDialog(); - // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on. - aboutDialog.Exclusive = false; - } } private enum MenuOptions { CreateSln, - AboutCSharp, SetupGodotNugetFallbackFolder, } @@ -371,7 +349,7 @@ namespace GodotTools return (ExternalEditorId)editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None; } - public override bool Build() + public override bool _Build() { return BuildManager.EditorBuildCallback(); } @@ -413,9 +391,9 @@ namespace GodotTools bottomPanelBtn.Icon = MSBuildPanel.BuildOutputView.BuildStateIcon; } - public override void EnablePlugin() + public override void _EnablePlugin() { - base.EnablePlugin(); + base._EnablePlugin(); if (Instance != null) throw new InvalidOperationException(); @@ -439,57 +417,6 @@ namespace GodotTools AddToolSubmenuItem("C#", menuPopup); - // TODO: Remove or edit this info dialog once Mono support is no longer in alpha - { - menuPopup.AddItem("About C# support".TTR(), (int)MenuOptions.AboutCSharp); - menuPopup.AddItem("Setup Godot NuGet Offline Packages".TTR(), (int)MenuOptions.SetupGodotNugetFallbackFolder); - aboutDialog = new AcceptDialog(); - editorBaseControl.AddChild(aboutDialog); - aboutDialog.Title = "Important: C# support is not feature-complete"; - - // We don't use DialogText as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox - // we'll add. Instead we add containers and a new autowrapped Label inside. - - // Main VBoxContainer (icon + label on top, checkbox at bottom) - var aboutVBox = new VBoxContainer(); - aboutDialog.AddChild(aboutVBox); - - // HBoxContainer for icon + label - var aboutHBox = new HBoxContainer(); - aboutVBox.AddChild(aboutHBox); - - var aboutIcon = new TextureRect(); - aboutIcon.Texture = aboutIcon.GetThemeIcon("NodeWarning", "EditorIcons"); - aboutHBox.AddChild(aboutIcon); - - var aboutLabel = new Label(); - aboutHBox.AddChild(aboutLabel); - aboutLabel.RectMinSize = new Vector2(600, 150) * EditorScale; - aboutLabel.SizeFlagsVertical = (int)Control.SizeFlags.ExpandFill; - aboutLabel.Autowrap = true; - aboutLabel.Text = - "C# support in Godot Engine is in late alpha stage and, while already usable, " + - "it is not meant for use in production.\n\n" + - "Projects can be exported to Linux, macOS, Windows, Android, iOS and HTML5, but not yet to UWP. " + - "Bugs and usability issues will be addressed gradually over future releases, " + - "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + - "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" + - " https://github.com/godotengine/godot/issues\n\n" + - "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!"; - - EditorDef("mono/editor/show_info_on_start", true); - - // CheckBox in main container - aboutDialogCheckBox = new CheckBox {Text = "Show this warning when starting the editor"}; - aboutDialogCheckBox.Toggled += enabled => - { - bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start"); - if (showOnStart != enabled) - editorSettings.SetSetting("mono/editor/show_info_on_start", enabled); - }; - aboutVBox.AddChild(aboutDialogCheckBox); - } - toolBarBuildButton = new Button { Text = "Build", diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index b48e5df9eb..620b031ddb 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -35,8 +35,8 @@ #include "core/config/engine.h" #include "core/core_constants.h" #include "core/io/compression.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "core/string/ucaps.h" #include "main/main.h" @@ -1260,7 +1260,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str CRASH_COND(itype.cname != name_cache.type_Object); CRASH_COND(!itype.is_instantiable); CRASH_COND(itype.api_type != ClassDB::API_CORE); - CRASH_COND(itype.is_reference); + CRASH_COND(itype.is_ref_counted); CRASH_COND(itype.is_singleton); } @@ -2284,8 +2284,8 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } if (return_type->is_object_type) { - ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type; - initialization = return_type->is_reference ? "" : " = nullptr"; + ptrcall_return_type = return_type->is_ref_counted ? "Ref<RefCounted>" : return_type->c_type; + initialization = return_type->is_ref_counted ? "" : " = nullptr"; } else { ptrcall_return_type = return_type->c_type; } @@ -2520,10 +2520,10 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant & p_arg_type.name == name_cache.type_NodePath; case Variant::NODE_PATH: return p_arg_type.name == name_cache.type_NodePath; - case Variant::TRANSFORM: case Variant::TRANSFORM2D: + case Variant::TRANSFORM3D: case Variant::BASIS: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::PLANE: case Variant::AABB: case Variant::COLOR: @@ -2600,12 +2600,12 @@ bool BindingsGenerator::_populate_object_type_interfaces() { itype.base_name = ClassDB::get_parent_class(type_cname); itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name); itype.is_instantiable = class_info->creation_func && !itype.is_singleton; - itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference); - itype.memory_own = itype.is_reference; + itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted); + itype.memory_own = itype.is_ref_counted; itype.c_out = "\treturn "; itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED; - itype.c_out += itype.is_reference ? "(%1.ptr());\n" : "(%1);\n"; + itype.c_out += itype.is_ref_counted ? "(%1.ptr());\n" : "(%1);\n"; itype.cs_in = itype.is_singleton ? BINDINGS_PTR_FIELD : "Object." CS_SMETHOD_GETINSTANCE "(%0)"; @@ -2741,7 +2741,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { imethod.return_type.cname = return_info.class_name; bool bad_reference_hint = !imethod.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE && - ClassDB::is_parent_class(return_info.class_name, name_cache.type_Reference); + ClassDB::is_parent_class(return_info.class_name, name_cache.type_RefCounted); ERR_FAIL_COND_V_MSG(bad_reference_hint, false, String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." + " Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'."); @@ -3053,28 +3053,25 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar break; case Variant::PLANE: { Plane plane = p_val.operator Plane(); - r_iarg.default_argument = "new Plane(new Vector3(" + plane.normal.operator String() + "), " + rtos(plane.d) + ")"; + r_iarg.default_argument = "new Plane(new Vector3" + plane.normal.operator String() + ", " + rtos(plane.d) + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::AABB: { AABB aabb = p_val.operator ::AABB(); - r_iarg.default_argument = "new AABB(new Vector3(" + aabb.position.operator String() + "), new Vector3(" + aabb.position.operator String() + "))"; + r_iarg.default_argument = "new AABB(new Vector3" + aabb.position.operator String() + ", new Vector3" + aabb.size.operator String() + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::RECT2: { Rect2 rect = p_val.operator Rect2(); - r_iarg.default_argument = "new Rect2(new Vector2(" + rect.position.operator String() + "), new Vector2(" + rect.position.operator String() + "))"; + r_iarg.default_argument = "new Rect2(new Vector2" + rect.position.operator String() + ", new Vector2" + rect.size.operator String() + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::RECT2I: { Rect2i rect = p_val.operator Rect2i(); - r_iarg.default_argument = "new Rect2i(new Vector2i(" + rect.position.operator String() + "), new Vector2i(" + rect.position.operator String() + "))"; + r_iarg.default_argument = "new Rect2i(new Vector2i" + rect.position.operator String() + ", new Vector2i" + rect.size.operator String() + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::COLOR: - r_iarg.default_argument = "new %s(" + r_iarg.default_argument + ")"; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; - break; case Variant::VECTOR2: case Variant::VECTOR2I: case Variant::VECTOR3: @@ -3123,13 +3120,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; - case Variant::TRANSFORM: { - Transform transform = p_val.operator Transform(); - if (transform == Transform()) { - r_iarg.default_argument = "Transform.Identity"; + case Variant::TRANSFORM3D: { + Transform3D transform = p_val.operator Transform3D(); + if (transform == Transform3D()) { + r_iarg.default_argument = "Transform3D.Identity"; } else { Basis basis = transform.basis; - r_iarg.default_argument = "new Transform(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")"; + r_iarg.default_argument = "new Transform3D(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")"; } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; @@ -3142,12 +3139,12 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; - case Variant::QUAT: { - Quat quat = p_val.operator Quat(); - if (quat == Quat()) { - r_iarg.default_argument = "Quat.Identity"; + case Variant::QUATERNION: { + Quaternion quaternion = p_val.operator Quaternion(); + if (quaternion == Quaternion()) { + r_iarg.default_argument = "Quaternion.Identity"; } else { - r_iarg.default_argument = "new Quat" + quat.operator String(); + r_iarg.default_argument = "new Quaternion" + quaternion.operator String(); } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; @@ -3196,8 +3193,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { INSERT_STRUCT_TYPE(Vector3) INSERT_STRUCT_TYPE(Vector3i) INSERT_STRUCT_TYPE(Basis) - INSERT_STRUCT_TYPE(Quat) - INSERT_STRUCT_TYPE(Transform) + INSERT_STRUCT_TYPE(Quaternion) + INSERT_STRUCT_TYPE(Transform3D) INSERT_STRUCT_TYPE(AABB) INSERT_STRUCT_TYPE(Color) INSERT_STRUCT_TYPE(Plane) diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 876046176b..48c0e02723 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -216,7 +216,7 @@ class BindingsGenerator { bool is_enum = false; bool is_object_type = false; bool is_singleton = false; - bool is_reference = false; + bool is_ref_counted = false; /** * Used only by Object-derived types. @@ -228,7 +228,7 @@ class BindingsGenerator { /** * Used only by Object-derived types. * Determines if the C# class owns the native handle and must free it somehow when disposed. - * e.g.: Reference types must notify when the C# instance is disposed, for proper refcounting. + * e.g.: RefCounted types must notify when the C# instance is disposed, for proper refcounting. */ bool memory_own = false; @@ -295,7 +295,7 @@ class BindingsGenerator { * VarArg (fictitious type to represent variable arguments): Array * float: double (because ptrcall only supports double) * int: int64_t (because ptrcall only supports int64_t and uint64_t) - * Reference types override this for the type of the return variable: Ref<Reference> + * RefCounted types override this for the type of the return variable: Ref<RefCounted> */ String c_type; @@ -534,7 +534,7 @@ class BindingsGenerator { StringName type_Variant = StaticCString::create("Variant"); StringName type_VarArg = StaticCString::create("VarArg"); StringName type_Object = StaticCString::create("Object"); - StringName type_Reference = StaticCString::create("Reference"); + StringName type_RefCounted = StaticCString::create("RefCounted"); StringName type_RID = StaticCString::create("RID"); StringName type_String = StaticCString::create("String"); StringName type_StringName = StaticCString::create("StringName"); @@ -623,7 +623,7 @@ class BindingsGenerator { } inline String get_unique_sig(const TypeInterface &p_type) { - if (p_type.is_reference) { + if (p_type.is_ref_counted) { return "Ref"; } else if (p_type.is_object_type) { return "Obj"; diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index 4b858c0e82..54dbaebf38 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -91,7 +91,7 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *re mono_assembly_get_assemblyref(image, i, reusable_aname); - GDMonoAssembly *ref_assembly = NULL; + GDMonoAssembly *ref_assembly = nullptr; if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) { ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'."); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index 3aecce50f5..2b641a8937 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs @@ -676,7 +676,7 @@ namespace Godot public override string ToString() { - return String.Format("{0} - {1}", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(), _size.ToString() @@ -685,7 +685,7 @@ namespace Godot public string ToString(string format) { - return String.Format("{0} - {1}", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(format), _size.ToString(format) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 3f1120575f..5dbf5d5657 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -207,7 +207,7 @@ namespace Godot } } - public Quat RotationQuat() + public Quaternion RotationQuaternion() { Basis orthonormalizedBasis = Orthonormalized(); real_t det = orthonormalizedBasis.Determinant(); @@ -218,18 +218,18 @@ namespace Godot orthonormalizedBasis = orthonormalizedBasis.Scaled(-Vector3.One); } - return orthonormalizedBasis.Quat(); + return orthonormalizedBasis.Quaternion(); } - internal void SetQuatScale(Quat quat, Vector3 scale) + internal void SetQuaternionScale(Quaternion quaternion, Vector3 scale) { SetDiagonal(scale); - Rotate(quat); + Rotate(quaternion); } - private void Rotate(Quat quat) + private void Rotate(Quaternion quaternion) { - this *= new Basis(quat); + this *= new Basis(quaternion); } private void SetDiagonal(Vector3 diagonal) @@ -263,8 +263,8 @@ namespace Godot /// The returned vector contains the rotation angles in /// the format (X angle, Y angle, Z angle). /// - /// Consider using the <see cref="Basis.Quat()"/> method instead, which - /// returns a <see cref="Godot.Quat"/> quaternion instead of Euler angles. + /// Consider using the <see cref="Basis.Quaternion()"/> method instead, which + /// returns a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles. /// </summary> /// <returns>A Vector3 representing the basis rotation in Euler angles.</returns> public Vector3 GetEuler() @@ -486,8 +486,8 @@ namespace Godot /// <returns>The resulting basis matrix of the interpolation.</returns> public Basis Slerp(Basis target, real_t weight) { - Quat from = new Quat(this); - Quat to = new Quat(target); + Quaternion from = new Quaternion(this); + Quaternion to = new Quaternion(target); Basis b = new Basis(from.Slerp(to, weight)); b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), weight); @@ -588,8 +588,8 @@ namespace Godot /// See <see cref="GetEuler()"/> if you need Euler angles, but keep in /// mind that quaternions should generally be preferred to Euler angles. /// </summary> - /// <returns>A <see cref="Godot.Quat"/> representing the basis's rotation.</returns> - public Quat Quat() + /// <returns>A <see cref="Godot.Quaternion"/> representing the basis's rotation.</returns> + public Quaternion Quaternion() { real_t trace = Row0[0] + Row1[1] + Row2[2]; @@ -597,7 +597,7 @@ namespace Godot { real_t s = Mathf.Sqrt(trace + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row2[1] - Row1[2]) * inv_s, (Row0[2] - Row2[0]) * inv_s, (Row1[0] - Row0[1]) * inv_s, @@ -609,7 +609,7 @@ namespace Godot { real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( s * 0.25f, (Row0[1] + Row1[0]) * inv_s, (Row0[2] + Row2[0]) * inv_s, @@ -621,7 +621,7 @@ namespace Godot { real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row0[1] + Row1[0]) * inv_s, s * 0.25f, (Row1[2] + Row2[1]) * inv_s, @@ -632,7 +632,7 @@ namespace Godot { real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row0[2] + Row2[0]) * inv_s, (Row1[2] + Row2[1]) * inv_s, s * 0.25f, @@ -699,23 +699,23 @@ namespace Godot /// <summary> /// Constructs a pure rotation basis matrix from the given quaternion. /// </summary> - /// <param name="quat">The quaternion to create the basis from.</param> - public Basis(Quat quat) + /// <param name="quaternion">The quaternion to create the basis from.</param> + public Basis(Quaternion quaternion) { - real_t s = 2.0f / quat.LengthSquared; + real_t s = 2.0f / quaternion.LengthSquared; - real_t xs = quat.x * s; - real_t ys = quat.y * s; - real_t zs = quat.z * s; - real_t wx = quat.w * xs; - real_t wy = quat.w * ys; - real_t wz = quat.w * zs; - real_t xx = quat.x * xs; - real_t xy = quat.x * ys; - real_t xz = quat.x * zs; - real_t yy = quat.y * ys; - real_t yz = quat.y * zs; - real_t zz = quat.z * zs; + real_t xs = quaternion.x * s; + real_t ys = quaternion.y * s; + real_t zs = quaternion.z * s; + real_t wx = quaternion.w * xs; + real_t wy = quaternion.w * ys; + real_t wz = quaternion.w * zs; + real_t xx = quaternion.x * xs; + real_t xy = quaternion.x * ys; + real_t xz = quaternion.x * zs; + real_t yy = quaternion.y * ys; + real_t yz = quaternion.y * zs; + real_t zz = quaternion.z * zs; Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy); Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx); @@ -727,8 +727,8 @@ namespace Godot /// (in the YXZ convention: when *composing*, first Y, then X, and Z last), /// given in the vector format as (X angle, Y angle, Z angle). /// - /// Consider using the <see cref="Basis(Quat)"/> constructor instead, which - /// uses a <see cref="Godot.Quat"/> quaternion instead of Euler angles. + /// Consider using the <see cref="Basis(Quaternion)"/> constructor instead, which + /// uses a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles. /// </summary> /// <param name="eulerYXZ">The Euler angles to create the basis from.</param> public Basis(Vector3 eulerYXZ) @@ -863,22 +863,16 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - Row0.ToString(), - Row1.ToString(), - Row2.ToString() - }); + return "[X: " + x.ToString() + + ", Y: " + y.ToString() + + ", Z: " + z.ToString() + "]"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - Row0.ToString(format), - Row1.ToString(format), - Row2.ToString(format) - }); + return "[X: " + x.ToString(format) + + ", Y: " + y.ToString(format) + + ", Z: " + z.ToString(format) + "]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 0c333d06ef..155ffcff32 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -257,6 +257,27 @@ namespace Godot } /// <summary> + /// Returns a new color with all components clamped between the + /// components of `min` and `max` using + /// <see cref="Mathf.Clamp(float, float, float)"/>. + /// </summary> + /// <param name="min">The color with minimum allowed values.</param> + /// <param name="max">The color with maximum allowed values.</param> + /// <returns>The color with all components clamped.</returns> + public Color Clamp(Color? min = null, Color? max = null) + { + Color minimum = min ?? new Color(0, 0, 0, 0); + Color maximum = max ?? new Color(1, 1, 1, 1); + return new Color + ( + (float)Mathf.Clamp(r, minimum.r, maximum.r), + (float)Mathf.Clamp(g, minimum.g, maximum.g), + (float)Mathf.Clamp(b, minimum.b, maximum.b), + (float)Mathf.Clamp(a, minimum.a, maximum.a) + ); + } + + /// <summary> /// Returns a new color resulting from making this color darker /// by the specified ratio (on the range of 0 to 1). /// </summary> @@ -681,7 +702,7 @@ namespace Godot name = name.Replace("_", String.Empty); name = name.Replace("'", String.Empty); name = name.Replace(".", String.Empty); - name = name.ToLower(); + name = name.ToUpper(); if (!Colors.namedColors.ContainsKey(name)) { @@ -989,12 +1010,12 @@ namespace Godot public override string ToString() { - return String.Format("{0},{1},{2},{3}", r.ToString(), g.ToString(), b.ToString(), a.ToString()); + return String.Format("({0}, {1}, {2}, {3})", r.ToString(), g.ToString(), b.ToString(), a.ToString()); } public string ToString(string format) { - return String.Format("{0},{1},{2},{3}", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format)); + return String.Format("({0}, {1}, {2}, {3})", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs index d05a0414aa..4bb727bd35 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs @@ -9,301 +9,301 @@ namespace Godot /// </summary> public static class Colors { - // Color names and values are derived from core/color_names.inc + // Color names and values are derived from core/math/color_names.inc internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> { - {"aliceblue", new Color(0.94f, 0.97f, 1.00f)}, - {"antiquewhite", new Color(0.98f, 0.92f, 0.84f)}, - {"aqua", new Color(0.00f, 1.00f, 1.00f)}, - {"aquamarine", new Color(0.50f, 1.00f, 0.83f)}, - {"azure", new Color(0.94f, 1.00f, 1.00f)}, - {"beige", new Color(0.96f, 0.96f, 0.86f)}, - {"bisque", new Color(1.00f, 0.89f, 0.77f)}, - {"black", new Color(0.00f, 0.00f, 0.00f)}, - {"blanchedalmond", new Color(1.00f, 0.92f, 0.80f)}, - {"blue", new Color(0.00f, 0.00f, 1.00f)}, - {"blueviolet", new Color(0.54f, 0.17f, 0.89f)}, - {"brown", new Color(0.65f, 0.16f, 0.16f)}, - {"burlywood", new Color(0.87f, 0.72f, 0.53f)}, - {"cadetblue", new Color(0.37f, 0.62f, 0.63f)}, - {"chartreuse", new Color(0.50f, 1.00f, 0.00f)}, - {"chocolate", new Color(0.82f, 0.41f, 0.12f)}, - {"coral", new Color(1.00f, 0.50f, 0.31f)}, - {"cornflower", new Color(0.39f, 0.58f, 0.93f)}, - {"cornsilk", new Color(1.00f, 0.97f, 0.86f)}, - {"crimson", new Color(0.86f, 0.08f, 0.24f)}, - {"cyan", new Color(0.00f, 1.00f, 1.00f)}, - {"darkblue", new Color(0.00f, 0.00f, 0.55f)}, - {"darkcyan", new Color(0.00f, 0.55f, 0.55f)}, - {"darkgoldenrod", new Color(0.72f, 0.53f, 0.04f)}, - {"darkgray", new Color(0.66f, 0.66f, 0.66f)}, - {"darkgreen", new Color(0.00f, 0.39f, 0.00f)}, - {"darkkhaki", new Color(0.74f, 0.72f, 0.42f)}, - {"darkmagenta", new Color(0.55f, 0.00f, 0.55f)}, - {"darkolivegreen", new Color(0.33f, 0.42f, 0.18f)}, - {"darkorange", new Color(1.00f, 0.55f, 0.00f)}, - {"darkorchid", new Color(0.60f, 0.20f, 0.80f)}, - {"darkred", new Color(0.55f, 0.00f, 0.00f)}, - {"darksalmon", new Color(0.91f, 0.59f, 0.48f)}, - {"darkseagreen", new Color(0.56f, 0.74f, 0.56f)}, - {"darkslateblue", new Color(0.28f, 0.24f, 0.55f)}, - {"darkslategray", new Color(0.18f, 0.31f, 0.31f)}, - {"darkturquoise", new Color(0.00f, 0.81f, 0.82f)}, - {"darkviolet", new Color(0.58f, 0.00f, 0.83f)}, - {"deeppink", new Color(1.00f, 0.08f, 0.58f)}, - {"deepskyblue", new Color(0.00f, 0.75f, 1.00f)}, - {"dimgray", new Color(0.41f, 0.41f, 0.41f)}, - {"dodgerblue", new Color(0.12f, 0.56f, 1.00f)}, - {"firebrick", new Color(0.70f, 0.13f, 0.13f)}, - {"floralwhite", new Color(1.00f, 0.98f, 0.94f)}, - {"forestgreen", new Color(0.13f, 0.55f, 0.13f)}, - {"fuchsia", new Color(1.00f, 0.00f, 1.00f)}, - {"gainsboro", new Color(0.86f, 0.86f, 0.86f)}, - {"ghostwhite", new Color(0.97f, 0.97f, 1.00f)}, - {"gold", new Color(1.00f, 0.84f, 0.00f)}, - {"goldenrod", new Color(0.85f, 0.65f, 0.13f)}, - {"gray", new Color(0.75f, 0.75f, 0.75f)}, - {"green", new Color(0.00f, 1.00f, 0.00f)}, - {"greenyellow", new Color(0.68f, 1.00f, 0.18f)}, - {"honeydew", new Color(0.94f, 1.00f, 0.94f)}, - {"hotpink", new Color(1.00f, 0.41f, 0.71f)}, - {"indianred", new Color(0.80f, 0.36f, 0.36f)}, - {"indigo", new Color(0.29f, 0.00f, 0.51f)}, - {"ivory", new Color(1.00f, 1.00f, 0.94f)}, - {"khaki", new Color(0.94f, 0.90f, 0.55f)}, - {"lavender", new Color(0.90f, 0.90f, 0.98f)}, - {"lavenderblush", new Color(1.00f, 0.94f, 0.96f)}, - {"lawngreen", new Color(0.49f, 0.99f, 0.00f)}, - {"lemonchiffon", new Color(1.00f, 0.98f, 0.80f)}, - {"lightblue", new Color(0.68f, 0.85f, 0.90f)}, - {"lightcoral", new Color(0.94f, 0.50f, 0.50f)}, - {"lightcyan", new Color(0.88f, 1.00f, 1.00f)}, - {"lightgoldenrod", new Color(0.98f, 0.98f, 0.82f)}, - {"lightgray", new Color(0.83f, 0.83f, 0.83f)}, - {"lightgreen", new Color(0.56f, 0.93f, 0.56f)}, - {"lightpink", new Color(1.00f, 0.71f, 0.76f)}, - {"lightsalmon", new Color(1.00f, 0.63f, 0.48f)}, - {"lightseagreen", new Color(0.13f, 0.70f, 0.67f)}, - {"lightskyblue", new Color(0.53f, 0.81f, 0.98f)}, - {"lightslategray", new Color(0.47f, 0.53f, 0.60f)}, - {"lightsteelblue", new Color(0.69f, 0.77f, 0.87f)}, - {"lightyellow", new Color(1.00f, 1.00f, 0.88f)}, - {"lime", new Color(0.00f, 1.00f, 0.00f)}, - {"limegreen", new Color(0.20f, 0.80f, 0.20f)}, - {"linen", new Color(0.98f, 0.94f, 0.90f)}, - {"magenta", new Color(1.00f, 0.00f, 1.00f)}, - {"maroon", new Color(0.69f, 0.19f, 0.38f)}, - {"mediumaquamarine", new Color(0.40f, 0.80f, 0.67f)}, - {"mediumblue", new Color(0.00f, 0.00f, 0.80f)}, - {"mediumorchid", new Color(0.73f, 0.33f, 0.83f)}, - {"mediumpurple", new Color(0.58f, 0.44f, 0.86f)}, - {"mediumseagreen", new Color(0.24f, 0.70f, 0.44f)}, - {"mediumslateblue", new Color(0.48f, 0.41f, 0.93f)}, - {"mediumspringgreen", new Color(0.00f, 0.98f, 0.60f)}, - {"mediumturquoise", new Color(0.28f, 0.82f, 0.80f)}, - {"mediumvioletred", new Color(0.78f, 0.08f, 0.52f)}, - {"midnightblue", new Color(0.10f, 0.10f, 0.44f)}, - {"mintcream", new Color(0.96f, 1.00f, 0.98f)}, - {"mistyrose", new Color(1.00f, 0.89f, 0.88f)}, - {"moccasin", new Color(1.00f, 0.89f, 0.71f)}, - {"navajowhite", new Color(1.00f, 0.87f, 0.68f)}, - {"navyblue", new Color(0.00f, 0.00f, 0.50f)}, - {"oldlace", new Color(0.99f, 0.96f, 0.90f)}, - {"olive", new Color(0.50f, 0.50f, 0.00f)}, - {"olivedrab", new Color(0.42f, 0.56f, 0.14f)}, - {"orange", new Color(1.00f, 0.65f, 0.00f)}, - {"orangered", new Color(1.00f, 0.27f, 0.00f)}, - {"orchid", new Color(0.85f, 0.44f, 0.84f)}, - {"palegoldenrod", new Color(0.93f, 0.91f, 0.67f)}, - {"palegreen", new Color(0.60f, 0.98f, 0.60f)}, - {"paleturquoise", new Color(0.69f, 0.93f, 0.93f)}, - {"palevioletred", new Color(0.86f, 0.44f, 0.58f)}, - {"papayawhip", new Color(1.00f, 0.94f, 0.84f)}, - {"peachpuff", new Color(1.00f, 0.85f, 0.73f)}, - {"peru", new Color(0.80f, 0.52f, 0.25f)}, - {"pink", new Color(1.00f, 0.75f, 0.80f)}, - {"plum", new Color(0.87f, 0.63f, 0.87f)}, - {"powderblue", new Color(0.69f, 0.88f, 0.90f)}, - {"purple", new Color(0.63f, 0.13f, 0.94f)}, - {"rebeccapurple", new Color(0.40f, 0.20f, 0.60f)}, - {"red", new Color(1.00f, 0.00f, 0.00f)}, - {"rosybrown", new Color(0.74f, 0.56f, 0.56f)}, - {"royalblue", new Color(0.25f, 0.41f, 0.88f)}, - {"saddlebrown", new Color(0.55f, 0.27f, 0.07f)}, - {"salmon", new Color(0.98f, 0.50f, 0.45f)}, - {"sandybrown", new Color(0.96f, 0.64f, 0.38f)}, - {"seagreen", new Color(0.18f, 0.55f, 0.34f)}, - {"seashell", new Color(1.00f, 0.96f, 0.93f)}, - {"sienna", new Color(0.63f, 0.32f, 0.18f)}, - {"silver", new Color(0.75f, 0.75f, 0.75f)}, - {"skyblue", new Color(0.53f, 0.81f, 0.92f)}, - {"slateblue", new Color(0.42f, 0.35f, 0.80f)}, - {"slategray", new Color(0.44f, 0.50f, 0.56f)}, - {"snow", new Color(1.00f, 0.98f, 0.98f)}, - {"springgreen", new Color(0.00f, 1.00f, 0.50f)}, - {"steelblue", new Color(0.27f, 0.51f, 0.71f)}, - {"tan", new Color(0.82f, 0.71f, 0.55f)}, - {"teal", new Color(0.00f, 0.50f, 0.50f)}, - {"thistle", new Color(0.85f, 0.75f, 0.85f)}, - {"tomato", new Color(1.00f, 0.39f, 0.28f)}, - {"transparent", new Color(1.00f, 1.00f, 1.00f, 0.00f)}, - {"turquoise", new Color(0.25f, 0.88f, 0.82f)}, - {"violet", new Color(0.93f, 0.51f, 0.93f)}, - {"webgreen", new Color(0.00f, 0.50f, 0.00f)}, - {"webgray", new Color(0.50f, 0.50f, 0.50f)}, - {"webmaroon", new Color(0.50f, 0.00f, 0.00f)}, - {"webpurple", new Color(0.50f, 0.00f, 0.50f)}, - {"wheat", new Color(0.96f, 0.87f, 0.70f)}, - {"white", new Color(1.00f, 1.00f, 1.00f)}, - {"whitesmoke", new Color(0.96f, 0.96f, 0.96f)}, - {"yellow", new Color(1.00f, 1.00f, 0.00f)}, - {"yellowgreen", new Color(0.60f, 0.80f, 0.20f)}, + {"ALICEBLUE", new Color(0.94f, 0.97f, 1.00f)}, + {"ANTIQUEWHITE", new Color(0.98f, 0.92f, 0.84f)}, + {"AQUA", new Color(0.00f, 1.00f, 1.00f)}, + {"AQUAMARINE", new Color(0.50f, 1.00f, 0.83f)}, + {"AZURE", new Color(0.94f, 1.00f, 1.00f)}, + {"BEIGE", new Color(0.96f, 0.96f, 0.86f)}, + {"BISQUE", new Color(1.00f, 0.89f, 0.77f)}, + {"BLACK", new Color(0.00f, 0.00f, 0.00f)}, + {"BLANCHEDALMOND", new Color(1.00f, 0.92f, 0.80f)}, + {"BLUE", new Color(0.00f, 0.00f, 1.00f)}, + {"BLUEVIOLET", new Color(0.54f, 0.17f, 0.89f)}, + {"BROWN", new Color(0.65f, 0.16f, 0.16f)}, + {"BURLYWOOD", new Color(0.87f, 0.72f, 0.53f)}, + {"CADETBLUE", new Color(0.37f, 0.62f, 0.63f)}, + {"CHARTREUSE", new Color(0.50f, 1.00f, 0.00f)}, + {"CHOCOLATE", new Color(0.82f, 0.41f, 0.12f)}, + {"CORAL", new Color(1.00f, 0.50f, 0.31f)}, + {"CORNFLOWERBLUE", new Color(0.39f, 0.58f, 0.93f)}, + {"CORNSILK", new Color(1.00f, 0.97f, 0.86f)}, + {"CRIMSON", new Color(0.86f, 0.08f, 0.24f)}, + {"CYAN", new Color(0.00f, 1.00f, 1.00f)}, + {"DARKBLUE", new Color(0.00f, 0.00f, 0.55f)}, + {"DARKCYAN", new Color(0.00f, 0.55f, 0.55f)}, + {"DARKGOLDENROD", new Color(0.72f, 0.53f, 0.04f)}, + {"DARKGRAY", new Color(0.66f, 0.66f, 0.66f)}, + {"DARKGREEN", new Color(0.00f, 0.39f, 0.00f)}, + {"DARKKHAKI", new Color(0.74f, 0.72f, 0.42f)}, + {"DARKMAGENTA", new Color(0.55f, 0.00f, 0.55f)}, + {"DARKOLIVEGREEN", new Color(0.33f, 0.42f, 0.18f)}, + {"DARKORANGE", new Color(1.00f, 0.55f, 0.00f)}, + {"DARKORCHID", new Color(0.60f, 0.20f, 0.80f)}, + {"DARKRED", new Color(0.55f, 0.00f, 0.00f)}, + {"DARKSALMON", new Color(0.91f, 0.59f, 0.48f)}, + {"DARKSEAGREEN", new Color(0.56f, 0.74f, 0.56f)}, + {"DARKSLATEBLUE", new Color(0.28f, 0.24f, 0.55f)}, + {"DARKSLATEGRAY", new Color(0.18f, 0.31f, 0.31f)}, + {"DARKTURQUOISE", new Color(0.00f, 0.81f, 0.82f)}, + {"DARKVIOLET", new Color(0.58f, 0.00f, 0.83f)}, + {"DEEPPINK", new Color(1.00f, 0.08f, 0.58f)}, + {"DEEPSKYBLUE", new Color(0.00f, 0.75f, 1.00f)}, + {"DIMGRAY", new Color(0.41f, 0.41f, 0.41f)}, + {"DODGERBLUE", new Color(0.12f, 0.56f, 1.00f)}, + {"FIREBRICK", new Color(0.70f, 0.13f, 0.13f)}, + {"FLORALWHITE", new Color(1.00f, 0.98f, 0.94f)}, + {"FORESTGREEN", new Color(0.13f, 0.55f, 0.13f)}, + {"FUCHSIA", new Color(1.00f, 0.00f, 1.00f)}, + {"GAINSBORO", new Color(0.86f, 0.86f, 0.86f)}, + {"GHOSTWHITE", new Color(0.97f, 0.97f, 1.00f)}, + {"GOLD", new Color(1.00f, 0.84f, 0.00f)}, + {"GOLDENROD", new Color(0.85f, 0.65f, 0.13f)}, + {"GRAY", new Color(0.75f, 0.75f, 0.75f)}, + {"GREEN", new Color(0.00f, 1.00f, 0.00f)}, + {"GREENYELLOW", new Color(0.68f, 1.00f, 0.18f)}, + {"HONEYDEW", new Color(0.94f, 1.00f, 0.94f)}, + {"HOTPINK", new Color(1.00f, 0.41f, 0.71f)}, + {"INDIANRED", new Color(0.80f, 0.36f, 0.36f)}, + {"INDIGO", new Color(0.29f, 0.00f, 0.51f)}, + {"IVORY", new Color(1.00f, 1.00f, 0.94f)}, + {"KHAKI", new Color(0.94f, 0.90f, 0.55f)}, + {"LAVENDER", new Color(0.90f, 0.90f, 0.98f)}, + {"LAVENDERBLUSH", new Color(1.00f, 0.94f, 0.96f)}, + {"LAWNGREEN", new Color(0.49f, 0.99f, 0.00f)}, + {"LEMONCHIFFON", new Color(1.00f, 0.98f, 0.80f)}, + {"LIGHTBLUE", new Color(0.68f, 0.85f, 0.90f)}, + {"LIGHTCORAL", new Color(0.94f, 0.50f, 0.50f)}, + {"LIGHTCYAN", new Color(0.88f, 1.00f, 1.00f)}, + {"LIGHTGOLDENROD", new Color(0.98f, 0.98f, 0.82f)}, + {"LIGHTGRAY", new Color(0.83f, 0.83f, 0.83f)}, + {"LIGHTGREEN", new Color(0.56f, 0.93f, 0.56f)}, + {"LIGHTPINK", new Color(1.00f, 0.71f, 0.76f)}, + {"LIGHTSALMON", new Color(1.00f, 0.63f, 0.48f)}, + {"LIGHTSEAGREEN", new Color(0.13f, 0.70f, 0.67f)}, + {"LIGHTSKYBLUE", new Color(0.53f, 0.81f, 0.98f)}, + {"LIGHTSLATEGRAY", new Color(0.47f, 0.53f, 0.60f)}, + {"LIGHTSTEELBLUE", new Color(0.69f, 0.77f, 0.87f)}, + {"LIGHTYELLOW", new Color(1.00f, 1.00f, 0.88f)}, + {"LIME", new Color(0.00f, 1.00f, 0.00f)}, + {"LIMEGREEN", new Color(0.20f, 0.80f, 0.20f)}, + {"LINEN", new Color(0.98f, 0.94f, 0.90f)}, + {"MAGENTA", new Color(1.00f, 0.00f, 1.00f)}, + {"MAROON", new Color(0.69f, 0.19f, 0.38f)}, + {"MEDIUMAQUAMARINE", new Color(0.40f, 0.80f, 0.67f)}, + {"MEDIUMBLUE", new Color(0.00f, 0.00f, 0.80f)}, + {"MEDIUMORCHID", new Color(0.73f, 0.33f, 0.83f)}, + {"MEDIUMPURPLE", new Color(0.58f, 0.44f, 0.86f)}, + {"MEDIUMSEAGREEN", new Color(0.24f, 0.70f, 0.44f)}, + {"MEDIUMSLATEBLUE", new Color(0.48f, 0.41f, 0.93f)}, + {"MEDIUMSPRINGGREEN", new Color(0.00f, 0.98f, 0.60f)}, + {"MEDIUMTURQUOISE", new Color(0.28f, 0.82f, 0.80f)}, + {"MEDIUMVIOLETRED", new Color(0.78f, 0.08f, 0.52f)}, + {"MIDNIGHTBLUE", new Color(0.10f, 0.10f, 0.44f)}, + {"MINTCREAM", new Color(0.96f, 1.00f, 0.98f)}, + {"MISTYROSE", new Color(1.00f, 0.89f, 0.88f)}, + {"MOCCASIN", new Color(1.00f, 0.89f, 0.71f)}, + {"NAVAJOWHITE", new Color(1.00f, 0.87f, 0.68f)}, + {"NAVYBLUE", new Color(0.00f, 0.00f, 0.50f)}, + {"OLDLACE", new Color(0.99f, 0.96f, 0.90f)}, + {"OLIVE", new Color(0.50f, 0.50f, 0.00f)}, + {"OLIVEDRAB", new Color(0.42f, 0.56f, 0.14f)}, + {"ORANGE", new Color(1.00f, 0.65f, 0.00f)}, + {"ORANGERED", new Color(1.00f, 0.27f, 0.00f)}, + {"ORCHID", new Color(0.85f, 0.44f, 0.84f)}, + {"PALEGOLDENROD", new Color(0.93f, 0.91f, 0.67f)}, + {"PALEGREEN", new Color(0.60f, 0.98f, 0.60f)}, + {"PALETURQUOISE", new Color(0.69f, 0.93f, 0.93f)}, + {"PALEVIOLETRED", new Color(0.86f, 0.44f, 0.58f)}, + {"PAPAYAWHIP", new Color(1.00f, 0.94f, 0.84f)}, + {"PEACHPUFF", new Color(1.00f, 0.85f, 0.73f)}, + {"PERU", new Color(0.80f, 0.52f, 0.25f)}, + {"PINK", new Color(1.00f, 0.75f, 0.80f)}, + {"PLUM", new Color(0.87f, 0.63f, 0.87f)}, + {"POWDERBLUE", new Color(0.69f, 0.88f, 0.90f)}, + {"PURPLE", new Color(0.63f, 0.13f, 0.94f)}, + {"REBECCAPURPLE", new Color(0.40f, 0.20f, 0.60f)}, + {"RED", new Color(1.00f, 0.00f, 0.00f)}, + {"ROSYBROWN", new Color(0.74f, 0.56f, 0.56f)}, + {"ROYALBLUE", new Color(0.25f, 0.41f, 0.88f)}, + {"SADDLEBROWN", new Color(0.55f, 0.27f, 0.07f)}, + {"SALMON", new Color(0.98f, 0.50f, 0.45f)}, + {"SANDYBROWN", new Color(0.96f, 0.64f, 0.38f)}, + {"SEAGREEN", new Color(0.18f, 0.55f, 0.34f)}, + {"SEASHELL", new Color(1.00f, 0.96f, 0.93f)}, + {"SIENNA", new Color(0.63f, 0.32f, 0.18f)}, + {"SILVER", new Color(0.75f, 0.75f, 0.75f)}, + {"SKYBLUE", new Color(0.53f, 0.81f, 0.92f)}, + {"SLATEBLUE", new Color(0.42f, 0.35f, 0.80f)}, + {"SLATEGRAY", new Color(0.44f, 0.50f, 0.56f)}, + {"SNOW", new Color(1.00f, 0.98f, 0.98f)}, + {"SPRINGGREEN", new Color(0.00f, 1.00f, 0.50f)}, + {"STEELBLUE", new Color(0.27f, 0.51f, 0.71f)}, + {"TAN", new Color(0.82f, 0.71f, 0.55f)}, + {"TEAL", new Color(0.00f, 0.50f, 0.50f)}, + {"THISTLE", new Color(0.85f, 0.75f, 0.85f)}, + {"TOMATO", new Color(1.00f, 0.39f, 0.28f)}, + {"TRANSPARENT", new Color(1.00f, 1.00f, 1.00f, 0.00f)}, + {"TURQUOISE", new Color(0.25f, 0.88f, 0.82f)}, + {"VIOLET", new Color(0.93f, 0.51f, 0.93f)}, + {"WEBGRAY", new Color(0.50f, 0.50f, 0.50f)}, + {"WEBGREEN", new Color(0.00f, 0.50f, 0.00f)}, + {"WEBMAROON", new Color(0.50f, 0.00f, 0.00f)}, + {"WEBPURPLE", new Color(0.50f, 0.00f, 0.50f)}, + {"WHEAT", new Color(0.96f, 0.87f, 0.70f)}, + {"WHITE", new Color(1.00f, 1.00f, 1.00f)}, + {"WHITESMOKE", new Color(0.96f, 0.96f, 0.96f)}, + {"YELLOW", new Color(1.00f, 1.00f, 0.00f)}, + {"YELLOWGREEN", new Color(0.60f, 0.80f, 0.20f)}, }; - public static Color AliceBlue { get { return namedColors["aliceblue"]; } } - public static Color AntiqueWhite { get { return namedColors["antiquewhite"]; } } - public static Color Aqua { get { return namedColors["aqua"]; } } - public static Color Aquamarine { get { return namedColors["aquamarine"]; } } - public static Color Azure { get { return namedColors["azure"]; } } - public static Color Beige { get { return namedColors["beige"]; } } - public static Color Bisque { get { return namedColors["bisque"]; } } - public static Color Black { get { return namedColors["black"]; } } - public static Color BlanchedAlmond { get { return namedColors["blanchedalmond"]; } } - public static Color Blue { get { return namedColors["blue"]; } } - public static Color BlueViolet { get { return namedColors["blueviolet"]; } } - public static Color Brown { get { return namedColors["brown"]; } } - public static Color BurlyWood { get { return namedColors["burlywood"]; } } - public static Color CadetBlue { get { return namedColors["cadetblue"]; } } - public static Color Chartreuse { get { return namedColors["chartreuse"]; } } - public static Color Chocolate { get { return namedColors["chocolate"]; } } - public static Color Coral { get { return namedColors["coral"]; } } - public static Color Cornflower { get { return namedColors["cornflower"]; } } - public static Color Cornsilk { get { return namedColors["cornsilk"]; } } - public static Color Crimson { get { return namedColors["crimson"]; } } - public static Color Cyan { get { return namedColors["cyan"]; } } - public static Color DarkBlue { get { return namedColors["darkblue"]; } } - public static Color DarkCyan { get { return namedColors["darkcyan"]; } } - public static Color DarkGoldenrod { get { return namedColors["darkgoldenrod"]; } } - public static Color DarkGray { get { return namedColors["darkgray"]; } } - public static Color DarkGreen { get { return namedColors["darkgreen"]; } } - public static Color DarkKhaki { get { return namedColors["darkkhaki"]; } } - public static Color DarkMagenta { get { return namedColors["darkmagenta"]; } } - public static Color DarkOliveGreen { get { return namedColors["darkolivegreen"]; } } - public static Color DarkOrange { get { return namedColors["darkorange"]; } } - public static Color DarkOrchid { get { return namedColors["darkorchid"]; } } - public static Color DarkRed { get { return namedColors["darkred"]; } } - public static Color DarkSalmon { get { return namedColors["darksalmon"]; } } - public static Color DarkSeaGreen { get { return namedColors["darkseagreen"]; } } - public static Color DarkSlateBlue { get { return namedColors["darkslateblue"]; } } - public static Color DarkSlateGray { get { return namedColors["darkslategray"]; } } - public static Color DarkTurquoise { get { return namedColors["darkturquoise"]; } } - public static Color DarkViolet { get { return namedColors["darkviolet"]; } } - public static Color DeepPink { get { return namedColors["deeppink"]; } } - public static Color DeepSkyBlue { get { return namedColors["deepskyblue"]; } } - public static Color DimGray { get { return namedColors["dimgray"]; } } - public static Color DodgerBlue { get { return namedColors["dodgerblue"]; } } - public static Color Firebrick { get { return namedColors["firebrick"]; } } - public static Color FloralWhite { get { return namedColors["floralwhite"]; } } - public static Color ForestGreen { get { return namedColors["forestgreen"]; } } - public static Color Fuchsia { get { return namedColors["fuchsia"]; } } - public static Color Gainsboro { get { return namedColors["gainsboro"]; } } - public static Color GhostWhite { get { return namedColors["ghostwhite"]; } } - public static Color Gold { get { return namedColors["gold"]; } } - public static Color Goldenrod { get { return namedColors["goldenrod"]; } } - public static Color Gray { get { return namedColors["gray"]; } } - public static Color Green { get { return namedColors["green"]; } } - public static Color GreenYellow { get { return namedColors["greenyellow"]; } } - public static Color Honeydew { get { return namedColors["honeydew"]; } } - public static Color HotPink { get { return namedColors["hotpink"]; } } - public static Color IndianRed { get { return namedColors["indianred"]; } } - public static Color Indigo { get { return namedColors["indigo"]; } } - public static Color Ivory { get { return namedColors["ivory"]; } } - public static Color Khaki { get { return namedColors["khaki"]; } } - public static Color Lavender { get { return namedColors["lavender"]; } } - public static Color LavenderBlush { get { return namedColors["lavenderblush"]; } } - public static Color LawnGreen { get { return namedColors["lawngreen"]; } } - public static Color LemonChiffon { get { return namedColors["lemonchiffon"]; } } - public static Color LightBlue { get { return namedColors["lightblue"]; } } - public static Color LightCoral { get { return namedColors["lightcoral"]; } } - public static Color LightCyan { get { return namedColors["lightcyan"]; } } - public static Color LightGoldenrod { get { return namedColors["lightgoldenrod"]; } } - public static Color LightGray { get { return namedColors["lightgray"]; } } - public static Color LightGreen { get { return namedColors["lightgreen"]; } } - public static Color LightPink { get { return namedColors["lightpink"]; } } - public static Color LightSalmon { get { return namedColors["lightsalmon"]; } } - public static Color LightSeaGreen { get { return namedColors["lightseagreen"]; } } - public static Color LightSkyBlue { get { return namedColors["lightskyblue"]; } } - public static Color LightSlateGray { get { return namedColors["lightslategray"]; } } - public static Color LightSteelBlue { get { return namedColors["lightsteelblue"]; } } - public static Color LightYellow { get { return namedColors["lightyellow"]; } } - public static Color Lime { get { return namedColors["lime"]; } } - public static Color Limegreen { get { return namedColors["limegreen"]; } } - public static Color Linen { get { return namedColors["linen"]; } } - public static Color Magenta { get { return namedColors["magenta"]; } } - public static Color Maroon { get { return namedColors["maroon"]; } } - public static Color MediumAquamarine { get { return namedColors["mediumaquamarine"]; } } - public static Color MediumBlue { get { return namedColors["mediumblue"]; } } - public static Color MediumOrchid { get { return namedColors["mediumorchid"]; } } - public static Color MediumPurple { get { return namedColors["mediumpurple"]; } } - public static Color MediumSeaGreen { get { return namedColors["mediumseagreen"]; } } - public static Color MediumSlateBlue { get { return namedColors["mediumslateblue"]; } } - public static Color MediumSpringGreen { get { return namedColors["mediumspringgreen"]; } } - public static Color MediumTurquoise { get { return namedColors["mediumturquoise"]; } } - public static Color MediumVioletRed { get { return namedColors["mediumvioletred"]; } } - public static Color MidnightBlue { get { return namedColors["midnightblue"]; } } - public static Color MintCream { get { return namedColors["mintcream"]; } } - public static Color MistyRose { get { return namedColors["mistyrose"]; } } - public static Color Moccasin { get { return namedColors["moccasin"]; } } - public static Color NavajoWhite { get { return namedColors["navajowhite"]; } } - public static Color NavyBlue { get { return namedColors["navyblue"]; } } - public static Color OldLace { get { return namedColors["oldlace"]; } } - public static Color Olive { get { return namedColors["olive"]; } } - public static Color OliveDrab { get { return namedColors["olivedrab"]; } } - public static Color Orange { get { return namedColors["orange"]; } } - public static Color OrangeRed { get { return namedColors["orangered"]; } } - public static Color Orchid { get { return namedColors["orchid"]; } } - public static Color PaleGoldenrod { get { return namedColors["palegoldenrod"]; } } - public static Color PaleGreen { get { return namedColors["palegreen"]; } } - public static Color PaleTurquoise { get { return namedColors["paleturquoise"]; } } - public static Color PaleVioletRed { get { return namedColors["palevioletred"]; } } - public static Color PapayaWhip { get { return namedColors["papayawhip"]; } } - public static Color PeachPuff { get { return namedColors["peachpuff"]; } } - public static Color Peru { get { return namedColors["peru"]; } } - public static Color Pink { get { return namedColors["pink"]; } } - public static Color Plum { get { return namedColors["plum"]; } } - public static Color PowderBlue { get { return namedColors["powderblue"]; } } - public static Color Purple { get { return namedColors["purple"]; } } - public static Color RebeccaPurple { get { return namedColors["rebeccapurple"]; } } - public static Color Red { get { return namedColors["red"]; } } - public static Color RosyBrown { get { return namedColors["rosybrown"]; } } - public static Color RoyalBlue { get { return namedColors["royalblue"]; } } - public static Color SaddleBrown { get { return namedColors["saddlebrown"]; } } - public static Color Salmon { get { return namedColors["salmon"]; } } - public static Color SandyBrown { get { return namedColors["sandybrown"]; } } - public static Color SeaGreen { get { return namedColors["seagreen"]; } } - public static Color SeaShell { get { return namedColors["seashell"]; } } - public static Color Sienna { get { return namedColors["sienna"]; } } - public static Color Silver { get { return namedColors["silver"]; } } - public static Color SkyBlue { get { return namedColors["skyblue"]; } } - public static Color SlateBlue { get { return namedColors["slateblue"]; } } - public static Color SlateGray { get { return namedColors["slategray"]; } } - public static Color Snow { get { return namedColors["snow"]; } } - public static Color SpringGreen { get { return namedColors["springgreen"]; } } - public static Color SteelBlue { get { return namedColors["steelblue"]; } } - public static Color Tan { get { return namedColors["tan"]; } } - public static Color Teal { get { return namedColors["teal"]; } } - public static Color Thistle { get { return namedColors["thistle"]; } } - public static Color Tomato { get { return namedColors["tomato"]; } } - public static Color Transparent { get { return namedColors["transparent"]; } } - public static Color Turquoise { get { return namedColors["turquoise"]; } } - public static Color Violet { get { return namedColors["violet"]; } } - public static Color WebGreen { get { return namedColors["webgreen"]; } } - public static Color WebGray { get { return namedColors["webgray"]; } } - public static Color WebMaroon { get { return namedColors["webmaroon"]; } } - public static Color WebPurple { get { return namedColors["webpurple"]; } } - public static Color Wheat { get { return namedColors["wheat"]; } } - public static Color White { get { return namedColors["white"]; } } - public static Color WhiteSmoke { get { return namedColors["whitesmoke"]; } } - public static Color Yellow { get { return namedColors["yellow"]; } } - public static Color YellowGreen { get { return namedColors["yellowgreen"]; } } + public static Color AliceBlue { get { return namedColors["ALICEBLUE"]; } } + public static Color AntiqueWhite { get { return namedColors["ANTIQUEWHITE"]; } } + public static Color Aqua { get { return namedColors["AQUA"]; } } + public static Color Aquamarine { get { return namedColors["AQUAMARINE"]; } } + public static Color Azure { get { return namedColors["AZURE"]; } } + public static Color Beige { get { return namedColors["BEIGE"]; } } + public static Color Bisque { get { return namedColors["BISQUE"]; } } + public static Color Black { get { return namedColors["BLACK"]; } } + public static Color BlanchedAlmond { get { return namedColors["BLANCHEDALMOND"]; } } + public static Color Blue { get { return namedColors["BLUE"]; } } + public static Color BlueViolet { get { return namedColors["BLUEVIOLET"]; } } + public static Color Brown { get { return namedColors["BROWN"]; } } + public static Color Burlywood { get { return namedColors["BURLYWOOD"]; } } + public static Color CadetBlue { get { return namedColors["CADETBLUE"]; } } + public static Color Chartreuse { get { return namedColors["CHARTREUSE"]; } } + public static Color Chocolate { get { return namedColors["CHOCOLATE"]; } } + public static Color Coral { get { return namedColors["CORAL"]; } } + public static Color CornflowerBlue { get { return namedColors["CORNFLOWERBLUE"]; } } + public static Color Cornsilk { get { return namedColors["CORNSILK"]; } } + public static Color Crimson { get { return namedColors["CRIMSON"]; } } + public static Color Cyan { get { return namedColors["CYAN"]; } } + public static Color DarkBlue { get { return namedColors["DARKBLUE"]; } } + public static Color DarkCyan { get { return namedColors["DARKCYAN"]; } } + public static Color DarkGoldenrod { get { return namedColors["DARKGOLDENROD"]; } } + public static Color DarkGray { get { return namedColors["DARKGRAY"]; } } + public static Color DarkGreen { get { return namedColors["DARKGREEN"]; } } + public static Color DarkKhaki { get { return namedColors["DARKKHAKI"]; } } + public static Color DarkMagenta { get { return namedColors["DARKMAGENTA"]; } } + public static Color DarkOliveGreen { get { return namedColors["DARKOLIVEGREEN"]; } } + public static Color DarkOrange { get { return namedColors["DARKORANGE"]; } } + public static Color DarkOrchid { get { return namedColors["DARKORCHID"]; } } + public static Color DarkRed { get { return namedColors["DARKRED"]; } } + public static Color DarkSalmon { get { return namedColors["DARKSALMON"]; } } + public static Color DarkSeaGreen { get { return namedColors["DARKSEAGREEN"]; } } + public static Color DarkSlateBlue { get { return namedColors["DARKSLATEBLUE"]; } } + public static Color DarkSlateGray { get { return namedColors["DARKSLATEGRAY"]; } } + public static Color DarkTurquoise { get { return namedColors["DARKTURQUOISE"]; } } + public static Color DarkViolet { get { return namedColors["DARKVIOLET"]; } } + public static Color DeepPink { get { return namedColors["DEEPPINK"]; } } + public static Color DeepSkyBlue { get { return namedColors["DEEPSKYBLUE"]; } } + public static Color DimGray { get { return namedColors["DIMGRAY"]; } } + public static Color DodgerBlue { get { return namedColors["DODGERBLUE"]; } } + public static Color Firebrick { get { return namedColors["FIREBRICK"]; } } + public static Color FloralWhite { get { return namedColors["FLORALWHITE"]; } } + public static Color ForestGreen { get { return namedColors["FORESTGREEN"]; } } + public static Color Fuchsia { get { return namedColors["FUCHSIA"]; } } + public static Color Gainsboro { get { return namedColors["GAINSBORO"]; } } + public static Color GhostWhite { get { return namedColors["GHOSTWHITE"]; } } + public static Color Gold { get { return namedColors["GOLD"]; } } + public static Color Goldenrod { get { return namedColors["GOLDENROD"]; } } + public static Color Gray { get { return namedColors["GRAY"]; } } + public static Color Green { get { return namedColors["GREEN"]; } } + public static Color GreenYellow { get { return namedColors["GREENYELLOW"]; } } + public static Color Honeydew { get { return namedColors["HONEYDEW"]; } } + public static Color HotPink { get { return namedColors["HOTPINK"]; } } + public static Color IndianRed { get { return namedColors["INDIANRED"]; } } + public static Color Indigo { get { return namedColors["INDIGO"]; } } + public static Color Ivory { get { return namedColors["IVORY"]; } } + public static Color Khaki { get { return namedColors["KHAKI"]; } } + public static Color Lavender { get { return namedColors["LAVENDER"]; } } + public static Color LavenderBlush { get { return namedColors["LAVENDERBLUSH"]; } } + public static Color LawnGreen { get { return namedColors["LAWNGREEN"]; } } + public static Color LemonChiffon { get { return namedColors["LEMONCHIFFON"]; } } + public static Color LightBlue { get { return namedColors["LIGHTBLUE"]; } } + public static Color LightCoral { get { return namedColors["LIGHTCORAL"]; } } + public static Color LightCyan { get { return namedColors["LIGHTCYAN"]; } } + public static Color LightGoldenrod { get { return namedColors["LIGHTGOLDENROD"]; } } + public static Color LightGray { get { return namedColors["LIGHTGRAY"]; } } + public static Color LightGreen { get { return namedColors["LIGHTGREEN"]; } } + public static Color LightPink { get { return namedColors["LIGHTPINK"]; } } + public static Color LightSalmon { get { return namedColors["LIGHTSALMON"]; } } + public static Color LightSeaGreen { get { return namedColors["LIGHTSEAGREEN"]; } } + public static Color LightSkyBlue { get { return namedColors["LIGHTSKYBLUE"]; } } + public static Color LightSlateGray { get { return namedColors["LIGHTSLATEGRAY"]; } } + public static Color LightSteelBlue { get { return namedColors["LIGHTSTEELBLUE"]; } } + public static Color LightYellow { get { return namedColors["LIGHTYELLOW"]; } } + public static Color Lime { get { return namedColors["LIME"]; } } + public static Color LimeGreen { get { return namedColors["LIMEGREEN"]; } } + public static Color Linen { get { return namedColors["LINEN"]; } } + public static Color Magenta { get { return namedColors["MAGENTA"]; } } + public static Color Maroon { get { return namedColors["MAROON"]; } } + public static Color MediumAquamarine { get { return namedColors["MEDIUMAQUAMARINE"]; } } + public static Color MediumBlue { get { return namedColors["MEDIUMBLUE"]; } } + public static Color MediumOrchid { get { return namedColors["MEDIUMORCHID"]; } } + public static Color MediumPurple { get { return namedColors["MEDIUMPURPLE"]; } } + public static Color MediumSeaGreen { get { return namedColors["MEDIUMSEAGREEN"]; } } + public static Color MediumSlateBlue { get { return namedColors["MEDIUMSLATEBLUE"]; } } + public static Color MediumSpringGreen { get { return namedColors["MEDIUMSPRINGGREEN"]; } } + public static Color MediumTurquoise { get { return namedColors["MEDIUMTURQUOISE"]; } } + public static Color MediumVioletRed { get { return namedColors["MEDIUMVIOLETRED"]; } } + public static Color MidnightBlue { get { return namedColors["MIDNIGHTBLUE"]; } } + public static Color MintCream { get { return namedColors["MINTCREAM"]; } } + public static Color MistyRose { get { return namedColors["MISTYROSE"]; } } + public static Color Moccasin { get { return namedColors["MOCCASIN"]; } } + public static Color NavajoWhite { get { return namedColors["NAVAJOWHITE"]; } } + public static Color NavyBlue { get { return namedColors["NAVYBLUE"]; } } + public static Color OldLace { get { return namedColors["OLDLACE"]; } } + public static Color Olive { get { return namedColors["OLIVE"]; } } + public static Color OliveDrab { get { return namedColors["OLIVEDRAB"]; } } + public static Color Orange { get { return namedColors["ORANGE"]; } } + public static Color OrangeRed { get { return namedColors["ORANGERED"]; } } + public static Color Orchid { get { return namedColors["ORCHID"]; } } + public static Color PaleGoldenrod { get { return namedColors["PALEGOLDENROD"]; } } + public static Color PaleGreen { get { return namedColors["PALEGREEN"]; } } + public static Color PaleTurquoise { get { return namedColors["PALETURQUOISE"]; } } + public static Color PaleVioletRed { get { return namedColors["PALEVIOLETRED"]; } } + public static Color PapayaWhip { get { return namedColors["PAPAYAWHIP"]; } } + public static Color PeachPuff { get { return namedColors["PEACHPUFF"]; } } + public static Color Peru { get { return namedColors["PERU"]; } } + public static Color Pink { get { return namedColors["PINK"]; } } + public static Color Plum { get { return namedColors["PLUM"]; } } + public static Color PowderBlue { get { return namedColors["POWDERBLUE"]; } } + public static Color Purple { get { return namedColors["PURPLE"]; } } + public static Color RebeccaPurple { get { return namedColors["REBECCAPURPLE"]; } } + public static Color Red { get { return namedColors["RED"]; } } + public static Color RosyBrown { get { return namedColors["ROSYBROWN"]; } } + public static Color RoyalBlue { get { return namedColors["ROYALBLUE"]; } } + public static Color SaddleBrown { get { return namedColors["SADDLEBROWN"]; } } + public static Color Salmon { get { return namedColors["SALMON"]; } } + public static Color SandyBrown { get { return namedColors["SANDYBROWN"]; } } + public static Color SeaGreen { get { return namedColors["SEAGREEN"]; } } + public static Color Seashell { get { return namedColors["SEASHELL"]; } } + public static Color Sienna { get { return namedColors["SIENNA"]; } } + public static Color Silver { get { return namedColors["SILVER"]; } } + public static Color SkyBlue { get { return namedColors["SKYBLUE"]; } } + public static Color SlateBlue { get { return namedColors["SLATEBLUE"]; } } + public static Color SlateGray { get { return namedColors["SLATEGRAY"]; } } + public static Color Snow { get { return namedColors["SNOW"]; } } + public static Color SpringGreen { get { return namedColors["SPRINGGREEN"]; } } + public static Color SteelBlue { get { return namedColors["STEELBLUE"]; } } + public static Color Tan { get { return namedColors["TAN"]; } } + public static Color Teal { get { return namedColors["TEAL"]; } } + public static Color Thistle { get { return namedColors["THISTLE"]; } } + public static Color Tomato { get { return namedColors["TOMATO"]; } } + public static Color Transparent { get { return namedColors["TRANSPARENT"]; } } + public static Color Turquoise { get { return namedColors["TURQUOISE"]; } } + public static Color Violet { get { return namedColors["VIOLET"]; } } + public static Color WebGray { get { return namedColors["WEBGRAY"]; } } + public static Color WebGreen { get { return namedColors["WEBGREEN"]; } } + public static Color WebMaroon { get { return namedColors["WEBMAROON"]; } } + public static Color WebPurple { get { return namedColors["WEBPURPLE"]; } } + public static Color Wheat { get { return namedColors["WHEAT"]; } } + public static Color White { get { return namedColors["WHITE"]; } } + public static Color WhiteSmoke { get { return namedColors["WHITESMOKE"]; } } + public static Color Yellow { get { return namedColors["YELLOW"]; } } + public static Color YellowGreen { get { return namedColors["YELLOWGREEN"]; } } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs index 763f470504..214bbf5179 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs @@ -8,9 +8,9 @@ namespace Godot /// `Node.NotificationInstanced` notification on the root node. /// </summary> /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam> - public T Instance<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class + public T Instantiate<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class { - return (T)(object)Instance(editState); + return (T)(object)Instantiate(editState); } /// <summary> @@ -19,9 +19,9 @@ namespace Godot /// `Node.NotificationInstanced` notification on the root node. /// </summary> /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam> - public T InstanceOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class + public T InstantiateOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class { - return Instance(editState) as T; + return Instantiate(editState) as T; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 48582d5ad8..d486d79557 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -66,7 +66,7 @@ namespace Godot if (memoryOwn) { memoryOwn = false; - godot_icall_Reference_Disposed(this, ptr, !disposing); + godot_icall_RefCounted_Disposed(this, ptr, !disposing); } else { @@ -129,7 +129,7 @@ namespace Godot internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer); + internal static extern void godot_icall_RefCounted_Disposed(Object obj, IntPtr ptr, bool isFinalizer); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 2f8b5f297c..ad6ca51e8b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -355,7 +355,7 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _normal.ToString(), D.ToString() @@ -364,7 +364,7 @@ namespace Godot public string ToString(string format) { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _normal.ToString(format), D.ToString(format) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index bd3bcb0c58..817103994a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -15,7 +15,7 @@ namespace Godot /// It is similar to Basis, which implements matrix representation of /// rotations, and can be parametrized using both an axis-angle pair /// or Euler angles. Basis stores rotation, scale, and shearing, - /// while Quat only stores rotation. + /// while Quaternion only stores rotation. /// /// Due to its compactness and the way it is stored in memory, certain /// operations (obtaining axis-angle and performing SLERP, in particular) @@ -23,7 +23,7 @@ namespace Godot /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] - public struct Quat : IEquatable<Quat> + public struct Quaternion : IEquatable<Quaternion> { /// <summary> /// X component of the quaternion (imaginary `i` axis part). @@ -114,6 +114,23 @@ namespace Godot } /// <summary> + /// Returns the angle between this quaternion and `to`. + /// This is the magnitude of the angle you would need to rotate + /// by to get from one to the other. + /// + /// Note: This method has an abnormally high amount + /// of floating-point error, so methods such as + /// <see cref="Mathf.IsZeroApprox"/> will not work reliably. + /// </summary> + /// <param name="to">The other quaternion.</param> + /// <returns>The angle between the quaternions.</returns> + public real_t AngleTo(Quaternion to) + { + real_t dot = Dot(to); + return Mathf.Acos(Mathf.Clamp(dot * dot * 2 - 1, -1, 1)); + } + + /// <summary> /// Performs a cubic spherical interpolation between quaternions `preA`, /// this vector, `b`, and `postB`, by the given amount `t`. /// </summary> @@ -122,11 +139,11 @@ namespace Godot /// <param name="postB">A quaternion after `b`.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated quaternion.</returns> - public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight) + public Quaternion CubicSlerp(Quaternion b, Quaternion preA, Quaternion postB, real_t weight) { real_t t2 = (1.0f - weight) * weight * 2f; - Quat sp = Slerp(b, weight); - Quat sq = preA.Slerpni(postB, weight); + Quaternion sp = Slerp(b, weight); + Quaternion sq = preA.Slerpni(postB, weight); return sp.Slerpni(sq, t2); } @@ -135,7 +152,7 @@ namespace Godot /// </summary> /// <param name="b">The other quaternion.</param> /// <returns>The dot product.</returns> - public real_t Dot(Quat b) + public real_t Dot(Quaternion b) { return x * b.x + y * b.y + z * b.z + w * b.w; } @@ -152,7 +169,7 @@ namespace Godot #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif var basis = new Basis(this); @@ -163,15 +180,15 @@ namespace Godot /// Returns the inverse of the quaternion. /// </summary> /// <returns>The inverse quaternion.</returns> - public Quat Inverse() + public Quaternion Inverse() { #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif - return new Quat(-x, -y, -z, w); + return new Quaternion(-x, -y, -z, w); } /// <summary> @@ -187,7 +204,7 @@ namespace Godot /// Returns a copy of the quaternion, normalized to unit length. /// </summary> /// <returns>The normalized quaternion.</returns> - public Quat Normalized() + public Quaternion Normalized() { return this / Length; } @@ -201,12 +218,12 @@ namespace Godot /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quat Slerp(Quat to, real_t weight) + public Quaternion Slerp(Quaternion to, real_t weight) { #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } if (!to.IsNormalized()) { @@ -217,7 +234,7 @@ namespace Godot // Calculate cosine. real_t cosom = x * to.x + y * to.y + z * to.z + w * to.w; - var to1 = new Quat(); + var to1 = new Quaternion(); // Adjust signs if necessary. if (cosom < 0.0) @@ -255,7 +272,7 @@ namespace Godot } // Calculate final values. - return new Quat + return new Quaternion ( scale0 * x + scale1 * to1.x, scale0 * y + scale1 * to1.y, @@ -272,7 +289,7 @@ namespace Godot /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quat Slerpni(Quat to, real_t weight) + public Quaternion Slerpni(Quaternion to, real_t weight) { real_t dot = Dot(to); @@ -286,7 +303,7 @@ namespace Godot real_t newFactor = Mathf.Sin(weight * theta) * sinT; real_t invFactor = Mathf.Sin((1.0f - weight) * theta) * sinT; - return new Quat + return new Quaternion ( invFactor * x + newFactor * to.x, invFactor * y + newFactor * to.y, @@ -305,7 +322,7 @@ namespace Godot #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif var u = new Vector3(x, y, z); @@ -314,15 +331,15 @@ namespace Godot } // Constants - private static readonly Quat _identity = new Quat(0, 0, 0, 1); + private static readonly Quaternion _identity = new Quaternion(0, 0, 0, 1); /// <summary> /// The identity quaternion, representing no rotation. /// Equivalent to an identity <see cref="Basis"/> matrix. If a vector is transformed by /// an identity quaternion, it will not change. /// </summary> - /// <value>Equivalent to `new Quat(0, 0, 0, 1)`.</value> - public static Quat Identity { get { return _identity; } } + /// <value>Equivalent to `new Quaternion(0, 0, 0, 1)`.</value> + public static Quaternion Identity { get { return _identity; } } /// <summary> /// Constructs a quaternion defined by the given values. @@ -331,7 +348,7 @@ namespace Godot /// <param name="y">Y component of the quaternion (imaginary `j` axis part).</param> /// <param name="z">Z component of the quaternion (imaginary `k` axis part).</param> /// <param name="w">W component of the quaternion (real part).</param> - public Quat(real_t x, real_t y, real_t z, real_t w) + public Quaternion(real_t x, real_t y, real_t z, real_t w) { this.x = x; this.y = y; @@ -343,7 +360,7 @@ namespace Godot /// Constructs a quaternion from the given quaternion. /// </summary> /// <param name="q">The existing quaternion.</param> - public Quat(Quat q) + public Quaternion(Quaternion q) { this = q; } @@ -352,9 +369,9 @@ namespace Godot /// Constructs a quaternion from the given <see cref="Basis"/>. /// </summary> /// <param name="basis">The basis to construct from.</param> - public Quat(Basis basis) + public Quaternion(Basis basis) { - this = basis.Quat(); + this = basis.Quaternion(); } /// <summary> @@ -364,7 +381,7 @@ namespace Godot /// given in the vector format as (X angle, Y angle, Z angle). /// </summary> /// <param name="eulerYXZ"></param> - public Quat(Vector3 eulerYXZ) + public Quaternion(Vector3 eulerYXZ) { real_t half_a1 = eulerYXZ.y * 0.5f; real_t half_a2 = eulerYXZ.x * 0.5f; @@ -393,7 +410,7 @@ namespace Godot /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> - public Quat(Vector3 axis, real_t angle) + public Quaternion(Vector3 axis, real_t angle) { #if DEBUG if (!axis.IsNormalized()) @@ -424,9 +441,9 @@ namespace Godot } } - public static Quat operator *(Quat left, Quat right) + public static Quaternion operator *(Quaternion left, Quaternion right) { - return new Quat + return new Quaternion ( left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z, @@ -435,24 +452,24 @@ namespace Godot ); } - public static Quat operator +(Quat left, Quat right) + public static Quaternion operator +(Quaternion left, Quaternion right) { - return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); + return new Quaternion(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); } - public static Quat operator -(Quat left, Quat right) + public static Quaternion operator -(Quaternion left, Quaternion right) { - return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); + return new Quaternion(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); } - public static Quat operator -(Quat left) + public static Quaternion operator -(Quaternion left) { - return new Quat(-left.x, -left.y, -left.z, -left.w); + return new Quaternion(-left.x, -left.y, -left.z, -left.w); } - public static Quat operator *(Quat left, Vector3 right) + public static Quaternion operator *(Quaternion left, Vector3 right) { - return new Quat + return new Quaternion ( left.w * right.x + left.y * right.z - left.z * right.y, left.w * right.y + left.z * right.x - left.x * right.z, @@ -461,9 +478,9 @@ namespace Godot ); } - public static Quat operator *(Vector3 left, Quat right) + public static Quaternion operator *(Vector3 left, Quaternion right) { - return new Quat + return new Quaternion ( right.w * left.x + right.y * left.z - right.z * left.y, right.w * left.y + right.z * left.x - right.x * left.z, @@ -472,42 +489,42 @@ namespace Godot ); } - public static Quat operator *(Quat left, real_t right) + public static Quaternion operator *(Quaternion left, real_t right) { - return new Quat(left.x * right, left.y * right, left.z * right, left.w * right); + return new Quaternion(left.x * right, left.y * right, left.z * right, left.w * right); } - public static Quat operator *(real_t left, Quat right) + public static Quaternion operator *(real_t left, Quaternion right) { - return new Quat(right.x * left, right.y * left, right.z * left, right.w * left); + return new Quaternion(right.x * left, right.y * left, right.z * left, right.w * left); } - public static Quat operator /(Quat left, real_t right) + public static Quaternion operator /(Quaternion left, real_t right) { return left * (1.0f / right); } - public static bool operator ==(Quat left, Quat right) + public static bool operator ==(Quaternion left, Quaternion right) { return left.Equals(right); } - public static bool operator !=(Quat left, Quat right) + public static bool operator !=(Quaternion left, Quaternion right) { return !left.Equals(right); } public override bool Equals(object obj) { - if (obj is Quat) + if (obj is Quaternion) { - return Equals((Quat)obj); + return Equals((Quaternion)obj); } return false; } - public bool Equals(Quat other) + public bool Equals(Quaternion other) { return x == other.x && y == other.y && z == other.z && w == other.w; } @@ -518,7 +535,7 @@ namespace Godot /// </summary> /// <param name="other">The other quaternion to compare.</param> /// <returns>Whether or not the quaternions are approximately equal.</returns> - public bool IsEqualApprox(Quat other) + public bool IsEqualApprox(Quaternion other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index 868c3536fe..612fb64a3d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -405,7 +405,7 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(), _size.ToString() @@ -414,7 +414,7 @@ namespace Godot public string ToString(string format) { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(format), _size.ToString(format) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index bc0f81b2a7..fe93592667 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -492,22 +492,16 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(), - y.ToString(), - origin.ToString() - }); + return "[X: " + x.ToString() + + ", Y: " + y.ToString() + + ", O: " + origin.ToString() + "]"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(format), - y.ToString(format), - origin.ToString(format) - }); + return "[X: " + x.ToString(format) + + ", Y: " + y.ToString(format) + + ", O: " + origin.ToString(format) + "]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index ac47f6029f..26b1a9e8b2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -19,7 +19,7 @@ namespace Godot /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] - public struct Transform : IEquatable<Transform> + public struct Transform3D : IEquatable<Transform3D> { /// <summary> /// The <see cref="Basis"/> of this transform. Contains the X, Y, and Z basis @@ -107,10 +107,10 @@ namespace Godot /// the transformation is composed of rotation, scaling, and translation. /// </summary> /// <returns>The inverse transformation matrix.</returns> - public Transform AffineInverse() + public Transform3D AffineInverse() { Basis basisInv = basis.Inverse(); - return new Transform(basisInv, basisInv.Xform(-origin)); + return new Transform3D(basisInv, basisInv.Xform(-origin)); } /// <summary> @@ -119,20 +119,20 @@ namespace Godot /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> - public Transform InterpolateWith(Transform transform, real_t weight) + public Transform3D InterpolateWith(Transform3D transform, real_t weight) { /* not sure if very "efficient" but good enough? */ Vector3 sourceScale = basis.Scale; - Quat sourceRotation = basis.RotationQuat(); + Quaternion sourceRotation = basis.RotationQuaternion(); Vector3 sourceLocation = origin; Vector3 destinationScale = transform.basis.Scale; - Quat destinationRotation = transform.basis.RotationQuat(); + Quaternion destinationRotation = transform.basis.RotationQuaternion(); Vector3 destinationLocation = transform.origin; - var interpolated = new Transform(); - interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight)); + var interpolated = new Transform3D(); + interpolated.basis.SetQuaternionScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight)); interpolated.origin = sourceLocation.Lerp(destinationLocation, weight); return interpolated; @@ -144,10 +144,10 @@ namespace Godot /// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling). /// </summary> /// <returns>The inverse matrix.</returns> - public Transform Inverse() + public Transform3D Inverse() { Basis basisTr = basis.Transposed(); - return new Transform(basisTr, basisTr.Xform(-origin)); + return new Transform3D(basisTr, basisTr.Xform(-origin)); } /// <summary> @@ -163,7 +163,7 @@ namespace Godot /// <param name="target">The object to look at.</param> /// <param name="up">The relative up direction</param> /// <returns>The resulting transform.</returns> - public Transform LookingAt(Vector3 target, Vector3 up) + public Transform3D LookingAt(Vector3 target, Vector3 up) { var t = this; t.SetLookAt(origin, target, up); @@ -175,9 +175,9 @@ namespace Godot /// and normalized axis vectors (scale of 1 or -1). /// </summary> /// <returns>The orthonormalized transform.</returns> - public Transform Orthonormalized() + public Transform3D Orthonormalized() { - return new Transform(basis.Orthonormalized(), origin); + return new Transform3D(basis.Orthonormalized(), origin); } /// <summary> @@ -187,9 +187,9 @@ namespace Godot /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="phi">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform Rotated(Vector3 axis, real_t phi) + public Transform3D Rotated(Vector3 axis, real_t phi) { - return new Transform(new Basis(axis, phi), new Vector3()) * this; + return new Transform3D(new Basis(axis, phi), new Vector3()) * this; } /// <summary> @@ -197,9 +197,9 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform Scaled(Vector3 scale) + public Transform3D Scaled(Vector3 scale) { - return new Transform(basis.Scaled(scale), origin * scale); + return new Transform3D(basis.Scaled(scale), origin * scale); } private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) @@ -234,9 +234,9 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform Translated(Vector3 offset) + public Transform3D Translated(Vector3 offset) { - return new Transform(basis, new Vector3 + return new Transform3D(basis, new Vector3 ( origin[0] += basis.Row0.Dot(offset), origin[1] += basis.Row1.Dot(offset), @@ -280,10 +280,10 @@ namespace Godot } // Constants - private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero); - private static readonly Transform _flipX = new Transform(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); - private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); - private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); + private static readonly Transform3D _identity = new Transform3D(Basis.Identity, Vector3.Zero); + private static readonly Transform3D _flipX = new Transform3D(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); + private static readonly Transform3D _flipY = new Transform3D(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); + private static readonly Transform3D _flipZ = new Transform3D(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); /// <summary> /// The identity transform, with no translation, rotation, or scaling applied. @@ -291,22 +291,22 @@ namespace Godot /// Do not use `new Transform()` with no arguments in C#, because it sets all values to zero. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value> - public static Transform Identity { get { return _identity; } } + public static Transform3D Identity { get { return _identity; } } /// <summary> /// The transform that will flip something along the X axis. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Left, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value> - public static Transform FlipX { get { return _flipX; } } + public static Transform3D FlipX { get { return _flipX; } } /// <summary> /// The transform that will flip something along the Y axis. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Down, Vector3.Back, Vector3.Zero)`.</value> - public static Transform FlipY { get { return _flipY; } } + public static Transform3D FlipY { get { return _flipY; } } /// <summary> /// The transform that will flip something along the Z axis. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Forward, Vector3.Zero)`.</value> - public static Transform FlipZ { get { return _flipZ; } } + public static Transform3D FlipZ { get { return _flipZ; } } /// <summary> /// Constructs a transformation matrix from 4 vectors (matrix columns). @@ -315,7 +315,7 @@ namespace Godot /// <param name="column1">The Y vector, or column index 1.</param> /// <param name="column2">The Z vector, or column index 2.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) + public Transform3D(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) { basis = new Basis(column0, column1, column2); this.origin = origin; @@ -324,11 +324,11 @@ namespace Godot /// <summary> /// Constructs a transformation matrix from the given quaternion and origin vector. /// </summary> - /// <param name="quat">The <see cref="Godot.Quat"/> to create the basis from.</param> + /// <param name="quaternion">The <see cref="Godot.Quaternion"/> to create the basis from.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Quat quat, Vector3 origin) + public Transform3D(Quaternion quaternion, Vector3 origin) { - basis = new Basis(quat); + basis = new Basis(quaternion); this.origin = origin; } @@ -337,40 +337,40 @@ namespace Godot /// </summary> /// <param name="basis">The <see cref="Godot.Basis"/> to create the basis from.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Basis basis, Vector3 origin) + public Transform3D(Basis basis, Vector3 origin) { this.basis = basis; this.origin = origin; } - public static Transform operator *(Transform left, Transform right) + public static Transform3D operator *(Transform3D left, Transform3D right) { left.origin = left.Xform(right.origin); left.basis *= right.basis; return left; } - public static bool operator ==(Transform left, Transform right) + public static bool operator ==(Transform3D left, Transform3D right) { return left.Equals(right); } - public static bool operator !=(Transform left, Transform right) + public static bool operator !=(Transform3D left, Transform3D right) { return !left.Equals(right); } public override bool Equals(object obj) { - if (obj is Transform) + if (obj is Transform3D) { - return Equals((Transform)obj); + return Equals((Transform3D)obj); } return false; } - public bool Equals(Transform other) + public bool Equals(Transform3D other) { return basis.Equals(other.basis) && origin.Equals(other.origin); } @@ -381,7 +381,7 @@ namespace Godot /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are approximately equal.</returns> - public bool IsEqualApprox(Transform other) + public bool IsEqualApprox(Transform3D other) { return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin); } @@ -393,20 +393,18 @@ namespace Godot public override string ToString() { - return String.Format("{0} - {1}", new object[] - { - basis.ToString(), - origin.ToString() - }); + return "[X: " + basis.x.ToString() + + ", Y: " + basis.y.ToString() + + ", Z: " + basis.z.ToString() + + ", O: " + origin.ToString() + "]"; } public string ToString(string format) { - return String.Format("{0} - {1}", new object[] - { - basis.ToString(format), - origin.ToString(format) - }); + return "[X: " + basis.x.ToString(format) + + ", Y: " + basis.y.ToString(format) + + ", Z: " + basis.z.ToString(format) + + ", O: " + origin.ToString(format) + "]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 6279ea1ace..af053bd263 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -160,22 +160,20 @@ namespace Godot } /// <summary> - /// Returns the vector with a maximum length by limiting its length to `length`. + /// Returns a new vector with all components clamped between the + /// components of `min` and `max` using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. /// </summary> - /// <param name="length">The length to limit to.</param> - /// <returns>The vector with its length limited.</returns> - public Vector2 Clamped(real_t length) + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector2 Clamp(Vector2 min, Vector2 max) { - var v = this; - real_t l = Length(); - - if (l > 0 && length < l) - { - v /= l; - v *= length; - } - - return v; + return new Vector2 + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y) + ); } /// <summary> @@ -335,6 +333,25 @@ namespace Godot } /// <summary> + /// Returns the vector with a maximum length by limiting its length to `length`. + /// </summary> + /// <param name="length">The length to limit to.</param> + /// <returns>The vector with its length limited.</returns> + public Vector2 LimitLength(real_t length = 1.0f) + { + Vector2 v = this; + real_t l = Length(); + + if (l > 0 && length < l) + { + v /= l; + v *= length; + } + + return v; + } + + /// <summary> /// Returns the axis of the vector's largest value. See <see cref="Axis"/>. /// If both components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -425,7 +442,7 @@ namespace Godot #if DEBUG if (!normal.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(normal)); + throw new ArgumentException("Argument is not normalized", nameof(normal)); } #endif return 2 * Dot(normal) * normal - this; @@ -519,7 +536,7 @@ namespace Godot /// compared to the original, with the same length. /// </summary> /// <returns>The perpendicular vector.</returns> - public Vector2 Perpendicular() + public Vector2 Orthogonal() { return new Vector2(y, -x); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index 8dd9ab2f0d..9068593fd8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -120,6 +120,23 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// components of `min` and `max` using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector2i Clamp(Vector2i min, Vector2i max) + { + return new Vector2i + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y) + ); + } + + /// <summary> /// Returns the cross product of this vector and `b`. /// </summary> /// <param name="b">The other vector.</param> @@ -248,13 +265,13 @@ namespace Godot } /// <summary> - /// Returns a vector rotated 90 degrees counter-clockwise + /// Returns a perpendicular vector rotated 90 degrees counter-clockwise /// compared to the original, with the same length. /// </summary> /// <returns>The perpendicular vector.</returns> - public Vector2 Perpendicular() + public Vector2i Orthogonal() { - return new Vector2(y, -x); + return new Vector2i(y, -x); } // Constants diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 3b895bbbf6..31a9af2d9e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -140,6 +140,24 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// components of `min` and `max` using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector3 Clamp(Vector3 min, Vector3 max) + { + return new Vector3 + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y), + Mathf.Clamp(z, min.z, max.z) + ); + } + + /// <summary> /// Returns the cross product of this vector and `b`. /// </summary> /// <param name="b">The other vector.</param> @@ -313,6 +331,25 @@ namespace Godot } /// <summary> + /// Returns the vector with a maximum length by limiting its length to `length`. + /// </summary> + /// <param name="length">The length to limit to.</param> + /// <returns>The vector with its length limited.</returns> + public Vector3 LimitLength(real_t length = 1.0f) + { + Vector3 v = this; + real_t l = Length(); + + if (l > 0 && length < l) + { + v /= l; + v *= length; + } + + return v; + } + + /// <summary> /// Returns the axis of the vector's largest value. See <see cref="Axis"/>. /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -419,7 +456,7 @@ namespace Godot #if DEBUG if (!normal.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(normal)); + throw new ArgumentException("Argument is not normalized", nameof(normal)); } #endif return 2.0f * Dot(normal) * normal - this; @@ -437,7 +474,7 @@ namespace Godot #if DEBUG if (!axis.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(axis)); + throw new ArgumentException("Argument is not normalized", nameof(axis)); } #endif return new Basis(axis, phi).Xform(this); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index bf25ba9cb3..e727afa3ff 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -89,6 +89,24 @@ namespace Godot } /// <summary> + /// Returns a new vector with all components clamped between the + /// components of `min` and `max` using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector3i Clamp(Vector3i min, Vector3i max) + { + return new Vector3i + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y), + Mathf.Clamp(z, min.z, max.z) + ); + } + + /// <summary> /// Returns the squared distance between this vector and `b`. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 54aaaf1f92..1fcfe74c86 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -50,7 +50,7 @@ <Compile Include="Core\NodePath.cs" /> <Compile Include="Core\Object.base.cs" /> <Compile Include="Core\Plane.cs" /> - <Compile Include="Core\Quat.cs" /> + <Compile Include="Core\Quaternion.cs" /> <Compile Include="Core\Rect2.cs" /> <Compile Include="Core\Rect2i.cs" /> <Compile Include="Core\RID.cs" /> @@ -58,8 +58,8 @@ <Compile Include="Core\SignalAwaiter.cs" /> <Compile Include="Core\StringExtensions.cs" /> <Compile Include="Core\StringName.cs" /> - <Compile Include="Core\Transform.cs" /> <Compile Include="Core\Transform2D.cs" /> + <Compile Include="Core\Transform3D.cs" /> <Compile Include="Core\UnhandledExceptionArgs.cs" /> <Compile Include="Core\Vector2.cs" /> <Compile Include="Core\Vector2i.cs" /> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 34a96eba17..2d04cedb9b 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -31,7 +31,7 @@ #ifdef MONO_GLUE_ENABLED #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/string_name.h" #include "../csharp_script.h" @@ -64,7 +64,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { return; } } - +#if 0 void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { @@ -76,19 +76,20 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } } +#endif } -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { +void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == nullptr); - // This is only called with Reference derived classes - CRASH_COND(!Object::cast_to<Reference>(p_ptr)); + // This is only called with RefCounted derived classes + CRASH_COND(!Object::cast_to<RefCounted>(p_ptr)); #endif +#if 0 + RefCounted *rc = static_cast<RefCounted *>(p_ptr); - Reference *ref = static_cast<Reference *>(p_ptr); - - if (ref->get_script_instance()) { - CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance()); + if (rc->get_script_instance()) { + CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance()); if (cs_instance) { if (!cs_instance->is_destructing_script_instance()) { bool delete_owner; @@ -97,9 +98,9 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance); if (delete_owner) { - memdelete(ref); + memdelete(rc); } else if (remove_script_instance) { - ref->set_script_instance(nullptr); + rc->set_script_instance(nullptr); } } return; @@ -108,11 +109,11 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea // Unsafe refcount decrement. The managed instance also counts as a reference. // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object) - CSharpLanguage::get_singleton()->pre_unsafe_unreference(ref); - if (ref->unreference()) { - memdelete(ref); + CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc); + if (rc->unreference()) { + memdelete(rc); } else { - void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + void *data = rc->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -124,6 +125,7 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea } } } +#endif } void godot_icall_Object_ConnectEventSignals(Object *p_ptr) { @@ -145,18 +147,18 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) { } Ref<WeakRef> wref; - Reference *ref = Object::cast_to<Reference>(p_ptr); + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); - if (ref) { - REF r = ref; + if (rc) { + REF r = rc; if (!r.is_valid()) { return nullptr; } - wref.instance(); + wref.instantiate(); wref->set_ref(r); } else { - wref.instance(); + wref.instantiate(); wref->set_obj(p_ptr); } @@ -242,7 +244,7 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) { void godot_register_object_icalls() { GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed); - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed); + GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString); diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 3db52d7c30..eed3bd2167 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -61,7 +61,7 @@ void godot_register_glue_header_icalls() { #include "core/config/engine.h" #include "core/object/class_db.h" #include "core/object/method_bind.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/node_path.h" #include "core/string/ustring.h" #include "core/typedefs.h" diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 020a40575c..375ad413c4 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -31,7 +31,7 @@ #include "godotsharp_dirs.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" #ifdef TOOLS_ENABLED @@ -63,8 +63,8 @@ String _get_expected_build_config() { String _get_mono_user_dir() { #ifdef TOOLS_ENABLED - if (EditorSettings::get_singleton()) { - return EditorSettings::get_singleton()->get_data_dir().plus_file("mono"); + if (EditorPaths::get_singleton()) { + return EditorPaths::get_singleton()->get_data_dir().plus_file("mono"); } else { String settings_path; diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h index f435aab3dd..d0e51d159f 100644 --- a/modules/mono/mono_gc_handle.h +++ b/modules/mono/mono_gc_handle.h @@ -33,7 +33,7 @@ #include <mono/jit/jit.h> -#include "core/object/reference.h" +#include "core/object/ref_counted.h" namespace gdmono { @@ -79,8 +79,8 @@ struct MonoGCHandleData { static MonoGCHandleData new_weak_handle(MonoObject *p_object); }; -class MonoGCHandleRef : public Reference { - GDCLASS(MonoGCHandleRef, Reference); +class MonoGCHandleRef : public RefCounted { + GDCLASS(MonoGCHandleRef, RefCounted); MonoGCHandleData data; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 560788fb3a..02d875f669 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -39,8 +39,8 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "core/os/thread.h" @@ -119,11 +119,11 @@ void gd_mono_profiler_init() { const String env_var_name = "MONO_ENV_OPTIONS"; if (OS::get_singleton()->has_environment(env_var_name)) { - const auto mono_env_ops = OS::get_singleton()->get_environment(env_var_name); + const String mono_env_ops = OS::get_singleton()->get_environment(env_var_name); // Usually MONO_ENV_OPTIONS looks like: --profile=jb:prof=timeline,ctl=remote,host=127.0.0.1:55467 const String prefix = "--profile="; if (mono_env_ops.begins_with(prefix)) { - const auto ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length()); + const String ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length()); mono_profiler_load(ops.utf8()); } } @@ -691,7 +691,7 @@ static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool } Ref<ConfigFile> cfg; - cfg.instance(); + cfg.instantiate(); Error cfg_err = cfg->load(cached_api_hash_path); ERR_FAIL_COND_V(cfg_err != OK, false); @@ -717,7 +717,7 @@ static void create_cached_api_hash_for(const String &p_api_assemblies_dir) { String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg"); Ref<ConfigFile> cfg; - cfg.instance(); + cfg.instantiate(); cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path)); cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path)); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index a1556bace5..67d6f3ef29 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -34,8 +34,8 @@ #include <mono/metadata/tokentype.h> #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/templates/list.h" diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index d66cc29b9a..341ca88728 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -109,8 +109,8 @@ void CachedData::clear_godot_api_cache() { class_Vector3 = nullptr; class_Vector3i = nullptr; class_Basis = nullptr; - class_Quat = nullptr; - class_Transform = nullptr; + class_Quaternion = nullptr; + class_Transform3D = nullptr; class_AABB = nullptr; class_Color = nullptr; class_Plane = nullptr; @@ -238,8 +238,8 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3)); CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i)); CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis)); - CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat)); - CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform)); + CACHE_CLASS_AND_CHECK(Quaternion, GODOT_API_CLASS(Quaternion)); + CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D)); CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB)); CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color)); CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane)); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 51370da452..3d867060f5 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -80,8 +80,8 @@ struct CachedData { GDMonoClass *class_Vector3; GDMonoClass *class_Vector3i; GDMonoClass *class_Basis; - GDMonoClass *class_Quat; - GDMonoClass *class_Transform; + GDMonoClass *class_Quaternion; + GDMonoClass *class_Transform3D; GDMonoClass *class_AABB; GDMonoClass *class_Color; GDMonoClass *class_Plane; diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 1d4d52dfce..111eaa0bbf 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -146,14 +146,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } - if (tclass == CACHED_CLASS(Quat)) { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + if (tclass == CACHED_CLASS(Quaternion)) { + GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion()); mono_field_set_value(p_object, mono_field, &from); break; } - if (tclass == CACHED_CLASS(Transform)) { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + if (tclass == CACHED_CLASS(Transform3D)) { + GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D()); mono_field_set_value(p_object, mono_field, &from); break; } @@ -336,8 +336,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); mono_field_set_value(p_object, mono_field, &from); } break; - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + case Variant::QUATERNION: { + GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion()); mono_field_set_value(p_object, mono_field, &from); } break; case Variant::AABB: { @@ -348,8 +348,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); mono_field_set_value(p_object, mono_field, &from); } break; - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + case Variant::TRANSFORM3D: { + GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D()); mono_field_set_value(p_object, mono_field, &from); } break; case Variant::COLOR: { diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index fa93c6533a..d6545d50ec 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -45,13 +45,13 @@ namespace GDMonoInternals { void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { // This method should not fail - +#if 0 CRASH_COND(!unmanaged); // All mono objects created from the managed world (e.g.: 'new Player()') // need to have a CSharpScript in order for their methods to be callable from the unmanaged side - Reference *ref = Object::cast_to<Reference>(unmanaged); + RefCounted *rc = Object::cast_to<RefCounted>(unmanaged); GDMonoClass *klass = GDMonoUtils::get_object_class(managed); @@ -73,18 +73,18 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { script_binding.inited = true; script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass); script_binding.wrapper_class = klass; - script_binding.gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); + script_binding.gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); script_binding.owner = unmanaged; - if (ref) { + if (rc) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) + // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) // May not me referenced yet, so we must use init_ref() instead of reference() - if (ref->init_ref()) { - CSharpLanguage::get_singleton()->post_unsafe_reference(ref); + if (rc->init_ref()) { + CSharpLanguage::get_singleton()->post_unsafe_reference(rc); } } @@ -99,7 +99,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { return; } - MonoGCHandleData gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); + MonoGCHandleData gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native); @@ -108,6 +108,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle); unmanaged->set_script_and_instance(script, csharp_instance); +#endif } void unhandled_exception(MonoException *p_exc) { diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index dafd36c36b..179bbfb40c 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -32,7 +32,7 @@ #include <stdlib.h> // abort -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" #include "../godotsharp_dirs.h" @@ -161,8 +161,8 @@ void GDMonoLog::initialize() { OS::Time time_now = OS::get_singleton()->get_time(); String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d", - date_now.year, date_now.month, date_now.day, - time_now.hour, time_now.min, time_now.sec); + (int)date_now.year, (int)date_now.month, (int)date_now.day, + (int)time_now.hour, (int)time_now.minute, (int)time_now.second); log_file_name += str_format("_%d", OS::get_singleton()->get_process_id()); diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index f7a53156ab..9ddbd251ac 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -41,7 +41,7 @@ #endif #ifdef GD_MONO_LOG_ENABLED -#include "core/os/file_access.h" +#include "core/io/file_access.h" #endif class GDMonoLog { diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 359f6bba4d..9f2977bfa2 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -104,12 +104,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_ return Variant::BASIS; } - if (vtclass == CACHED_CLASS(Quat)) { - return Variant::QUAT; + if (vtclass == CACHED_CLASS(Quaternion)) { + return Variant::QUATERNION; } - if (vtclass == CACHED_CLASS(Transform)) { - return Variant::TRANSFORM; + if (vtclass == CACHED_CLASS(Transform3D)) { + return Variant::TRANSFORM3D; } if (vtclass == CACHED_CLASS(AABB)) { @@ -508,9 +508,9 @@ MonoObject *variant_to_mono_object(const Variant &p_var) { GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); } - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); + case Variant::QUATERNION: { + GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_var.operator ::Quaternion()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quaternion), &from); } case Variant::AABB: { GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB()); @@ -520,9 +520,9 @@ MonoObject *variant_to_mono_object(const Variant &p_var) { GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); } - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); + case Variant::TRANSFORM3D: { + GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from); } case Variant::COLOR: { GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color()); @@ -619,8 +619,8 @@ size_t variant_get_managed_unboxed_size(const ManagedType &p_type) { RETURN_CHECK_FOR_STRUCT(Vector3); RETURN_CHECK_FOR_STRUCT(Vector3i); RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quat); - RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(Quaternion); + RETURN_CHECK_FOR_STRUCT(Transform3D); RETURN_CHECK_FOR_STRUCT(AABB); RETURN_CHECK_FOR_STRUCT(Color); RETURN_CHECK_FOR_STRUCT(Plane); @@ -724,8 +724,8 @@ void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type RETURN_CHECK_FOR_STRUCT(Vector3); RETURN_CHECK_FOR_STRUCT(Vector3i); RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quat); - RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(Quaternion); + RETURN_CHECK_FOR_STRUCT(Transform3D); RETURN_CHECK_FOR_STRUCT(AABB); RETURN_CHECK_FOR_STRUCT(Color); RETURN_CHECK_FOR_STRUCT(Plane); @@ -880,8 +880,8 @@ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_ty RETURN_CHECK_FOR_STRUCT(Vector3); RETURN_CHECK_FOR_STRUCT(Vector3i); RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quat); - RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(Quaternion); + RETURN_CHECK_FOR_STRUCT(Transform3D); RETURN_CHECK_FOR_STRUCT(AABB); RETURN_CHECK_FOR_STRUCT(Color); RETURN_CHECK_FOR_STRUCT(Plane); @@ -1036,12 +1036,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj)); } - if (vtclass == CACHED_CLASS(Quat)) { - return MARSHALLED_IN(Quat, unbox_addr<GDMonoMarshal::M_Quat>(p_obj)); + if (vtclass == CACHED_CLASS(Quaternion)) { + return MARSHALLED_IN(Quaternion, unbox_addr<GDMonoMarshal::M_Quaternion>(p_obj)); } - if (vtclass == CACHED_CLASS(Transform)) { - return MARSHALLED_IN(Transform, unbox_addr<GDMonoMarshal::M_Transform>(p_obj)); + if (vtclass == CACHED_CLASS(Transform3D)) { + return MARSHALLED_IN(Transform3D, unbox_addr<GDMonoMarshal::M_Transform3D>(p_obj)); } if (vtclass == CACHED_CLASS(AABB)) { @@ -1136,8 +1136,8 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj)); if (ptr != nullptr) { - Reference *ref = Object::cast_to<Reference>(ptr); - return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr); + RefCounted *rc = Object::cast_to<RefCounted>(ptr); + return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr); } return Variant(); } diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 668809ae5d..88afc7ebc5 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -263,15 +263,15 @@ enum { MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array - MATCHES_Quat = (MATCHES_real_t && (sizeof(Quat) == (sizeof(real_t) * 4)) && - offsetof(Quat, x) == (sizeof(real_t) * 0) && - offsetof(Quat, y) == (sizeof(real_t) * 1) && - offsetof(Quat, z) == (sizeof(real_t) * 2) && - offsetof(Quat, w) == (sizeof(real_t) * 3)), + MATCHES_Quaternion = (MATCHES_real_t && (sizeof(Quaternion) == (sizeof(real_t) * 4)) && + offsetof(Quaternion, x) == (sizeof(real_t) * 0) && + offsetof(Quaternion, y) == (sizeof(real_t) * 1) && + offsetof(Quaternion, z) == (sizeof(real_t) * 2) && + offsetof(Quaternion, w) == (sizeof(real_t) * 3)), - MATCHES_Transform = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform) == (sizeof(Basis) + sizeof(Vector3))) && - offsetof(Transform, basis) == 0 && - offsetof(Transform, origin) == sizeof(Basis)), + MATCHES_Transform3D = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform3D) == (sizeof(Basis) + sizeof(Vector3))) && + offsetof(Transform3D, basis) == 0 && + offsetof(Transform3D, origin) == sizeof(Basis)), MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) && offsetof(AABB, position) == (sizeof(Vector3) * 0) && @@ -292,7 +292,7 @@ enum { #ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY /* clang-format off */ static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && - MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color && + MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_AABB && MATCHES_Color && MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i); /* clang-format on */ #endif @@ -420,29 +420,29 @@ struct M_Basis { } }; -struct M_Quat { +struct M_Quaternion { real_t x, y, z, w; - static _FORCE_INLINE_ Quat convert_to(const M_Quat &p_from) { - return Quat(p_from.x, p_from.y, p_from.z, p_from.w); + static _FORCE_INLINE_ Quaternion convert_to(const M_Quaternion &p_from) { + return Quaternion(p_from.x, p_from.y, p_from.z, p_from.w); } - static _FORCE_INLINE_ M_Quat convert_from(const Quat &p_from) { - M_Quat ret = { p_from.x, p_from.y, p_from.z, p_from.w }; + static _FORCE_INLINE_ M_Quaternion convert_from(const Quaternion &p_from) { + M_Quaternion ret = { p_from.x, p_from.y, p_from.z, p_from.w }; return ret; } }; -struct M_Transform { +struct M_Transform3D { M_Basis basis; M_Vector3 origin; - static _FORCE_INLINE_ Transform convert_to(const M_Transform &p_from) { - return Transform(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin)); + static _FORCE_INLINE_ Transform3D convert_to(const M_Transform3D &p_from) { + return Transform3D(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin)); } - static _FORCE_INLINE_ M_Transform convert_from(const Transform &p_from) { - M_Transform ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) }; + static _FORCE_INLINE_ M_Transform3D convert_from(const Transform3D &p_from) { + M_Transform3D ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) }; return ret; } }; @@ -533,8 +533,8 @@ DECL_TYPE_MARSHAL_TEMPLATES(Transform2D) DECL_TYPE_MARSHAL_TEMPLATES(Vector3) DECL_TYPE_MARSHAL_TEMPLATES(Vector3i) DECL_TYPE_MARSHAL_TEMPLATES(Basis) -DECL_TYPE_MARSHAL_TEMPLATES(Quat) -DECL_TYPE_MARSHAL_TEMPLATES(Transform) +DECL_TYPE_MARSHAL_TEMPLATES(Quaternion) +DECL_TYPE_MARSHAL_TEMPLATES(Transform3D) DECL_TYPE_MARSHAL_TEMPLATES(AABB) DECL_TYPE_MARSHAL_TEMPLATES(Color) DECL_TYPE_MARSHAL_TEMPLATES(Plane) diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 6e0a263c7f..080398c997 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -35,8 +35,8 @@ #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/object/reference.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/os/os.h" @@ -54,6 +54,7 @@ namespace GDMonoUtils { MonoObject *unmanaged_get_managed(Object *unmanaged) { +#if 0 if (!unmanaged) { return nullptr; } @@ -108,18 +109,20 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { gchandle = MonoGCHandleData::new_strong_handle(mono_object); // Tie managed to unmanaged - Reference *ref = Object::cast_to<Reference>(unmanaged); + RefCounted *rc = Object::cast_to<RefCounted>(unmanaged); - if (ref) { + if (rc) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) - ref->reference(); - CSharpLanguage::get_singleton()->post_unsafe_reference(ref); + // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) + rc->reference(); + CSharpLanguage::get_singleton()->post_unsafe_reference(rc); } return mono_object; +#endif + return nullptr; } void set_main_thread(MonoThread *p_thread) { @@ -238,7 +241,7 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) { MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) { bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native); ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr, - "Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'."); + "Type inherits from native type '" + p_native + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'."); MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); ERR_FAIL_NULL_V(mono_object, nullptr); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 9e024418e1..773501e93d 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -41,7 +41,7 @@ #endif #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #define UNHANDLED_EXCEPTION(m_exc) \ if (unlikely(m_exc != nullptr)) { \ diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h index 159a2ed7b6..366662ff81 100644 --- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h +++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h @@ -176,7 +176,7 @@ T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) { } else if constexpr (cookie == 'F') { return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]); } else if constexpr (cookie == 'D') { - return (T)(size_t)p_margs->fargs[p_idx]; + return (T)p_margs->fargs[p_idx]; } } diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm index cdee04edcf..23424fbaf9 100644 --- a/modules/mono/mono_gd/support/ios_support.mm +++ b/modules/mono/mono_gd/support/ios_support.mm @@ -57,9 +57,9 @@ void ios_mono_log_callback(const char *log_domain, const char *log_level, const } void initialize() { - mono_dllmap_insert(NULL, "System.Native", NULL, "__Internal", NULL); - mono_dllmap_insert(NULL, "System.IO.Compression.Native", NULL, "__Internal", NULL); - mono_dllmap_insert(NULL, "System.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL); + mono_dllmap_insert(nullptr, "System.Native", nullptr, "__Internal", nullptr); + mono_dllmap_insert(nullptr, "System.IO.Compression.Native", nullptr, "__Internal", nullptr); + mono_dllmap_insert(nullptr, "System.Security.Cryptography.Native.Apple", nullptr, "__Internal", nullptr); #ifdef IOS_DEVICE // This function is defined in an auto-generated source file @@ -85,7 +85,7 @@ void cleanup() { GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() { NSLocale *locale = [NSLocale currentLocale]; NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; - if (countryCode == NULL) { + if (countryCode == nullptr) { return strdup("US"); } return strdup([countryCode UTF8String]); diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp index 80eb47bfd4..2ba89eac55 100644 --- a/modules/mono/register_types.cpp +++ b/modules/mono/register_types.cpp @@ -41,21 +41,21 @@ Ref<ResourceFormatSaverCSharpScript> resource_saver_cs; _GodotSharp *_godotsharp = nullptr; void register_mono_types() { - ClassDB::register_class<CSharpScript>(); + GDREGISTER_CLASS(CSharpScript); _godotsharp = memnew(_GodotSharp); - ClassDB::register_class<_GodotSharp>(); + GDREGISTER_CLASS(_GodotSharp); Engine::get_singleton()->add_singleton(Engine::Singleton("GodotSharp", _GodotSharp::get_singleton())); script_language_cs = memnew(CSharpLanguage); script_language_cs->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(script_language_cs); - resource_loader_cs.instance(); + resource_loader_cs.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_cs); - resource_saver_cs.instance(); + resource_saver_cs.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_cs); } diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h index 4c77f8cfed..e12ea45b3f 100644 --- a/modules/mono/signal_awaiter_utils.h +++ b/modules/mono/signal_awaiter_utils.h @@ -31,7 +31,7 @@ #ifndef SIGNAL_AWAITER_UTILS_H #define SIGNAL_AWAITER_UTILS_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "csharp_script.h" #include "mono_gc_handle.h" diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index bb1265e959..6b616dd52d 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "mono_reg_utils.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #ifdef WINDOWS_ENABLED diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index 93d44628ac..ec04d50704 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/modules/mono/utils/path_utils.cpp @@ -31,8 +31,8 @@ #include "path_utils.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #ifdef WINDOWS_ENABLED @@ -80,7 +80,7 @@ String cwd() { } String abspath(const String &p_path) { - if (p_path.is_abs_path()) { + if (p_path.is_absolute_path()) { return p_path.simplify_path(); } else { return path::join(path::cwd(), p_path).simplify_path(); diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index 43de77005e..053618ebe4 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -30,7 +30,7 @@ #include "string_utils.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include <stdio.h> #include <stdlib.h> @@ -170,10 +170,10 @@ Error read_all_file_utf8(const String &p_path, String &r_content) { FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); - int len = f->get_len(); + uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); - int r = f->get_buffer(w, len); + uint64_t r = f->get_buffer(w, len); f->close(); memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); diff --git a/modules/gdnavigation/SCsub b/modules/navigation/SCsub index 22b5509b32..22b5509b32 100644 --- a/modules/gdnavigation/SCsub +++ b/modules/navigation/SCsub diff --git a/modules/gdnavigation/config.py b/modules/navigation/config.py index d22f9454ed..d22f9454ed 100644 --- a/modules/gdnavigation/config.py +++ b/modules/navigation/config.py diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 39f208c7a4..df003cfe6f 100644 --- a/modules/gdnavigation/gd_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gd_navigation_server.cpp */ +/* godot_navigation_server.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gd_navigation_server.h" +#include "godot_navigation_server.h" #include "core/os/mutex.h" @@ -44,96 +44,96 @@ /// an instance of that struct with the submitted parameters. /// Then, that struct is stored in an array; the `sync` function consume that array. -#define COMMAND_1(F_NAME, T_0, D_0) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - MERGE(F_NAME, _command) \ - (T_0 p_d_0) : \ - d_0(p_d_0) {} \ - virtual void exec(GdNavigationServer *server) { \ - server->MERGE(_cmd_, F_NAME)(d_0); \ - } \ - }; \ - void GdNavigationServer::F_NAME(T_0 D_0) const { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0)); \ - add_command(cmd); \ - } \ - void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0) - -#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - T_1 d_1; \ - MERGE(F_NAME, _command) \ - ( \ - T_0 p_d_0, \ - T_1 p_d_1) : \ - d_0(p_d_0), \ - d_1(p_d_1) {} \ - virtual void exec(GdNavigationServer *server) { \ - server->MERGE(_cmd_, F_NAME)(d_0, d_1); \ - } \ - }; \ - void GdNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0, \ - D_1)); \ - add_command(cmd); \ - } \ - void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) - -#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - T_1 d_1; \ - T_2 d_2; \ - T_3 d_3; \ - MERGE(F_NAME, _command) \ - ( \ - T_0 p_d_0, \ - T_1 p_d_1, \ - T_2 p_d_2, \ - T_3 p_d_3) : \ - d_0(p_d_0), \ - d_1(p_d_1), \ - d_2(p_d_2), \ - d_3(p_d_3) {} \ - virtual void exec(GdNavigationServer *server) { \ - server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \ - } \ - }; \ - void GdNavigationServer::F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) const { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0, \ - D_1, \ - D_2, \ - D_3)); \ - add_command(cmd); \ - } \ - void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) - -GdNavigationServer::GdNavigationServer() : +#define COMMAND_1(F_NAME, T_0, D_0) \ + struct MERGE(F_NAME, _command) : public SetCommand { \ + T_0 d_0; \ + MERGE(F_NAME, _command) \ + (T_0 p_d_0) : \ + d_0(p_d_0) {} \ + virtual void exec(GodotNavigationServer *server) { \ + server->MERGE(_cmd_, F_NAME)(d_0); \ + } \ + }; \ + void GodotNavigationServer::F_NAME(T_0 D_0) const { \ + auto cmd = memnew(MERGE(F_NAME, _command)( \ + D_0)); \ + add_command(cmd); \ + } \ + void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0) + +#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ + struct MERGE(F_NAME, _command) : public SetCommand { \ + T_0 d_0; \ + T_1 d_1; \ + MERGE(F_NAME, _command) \ + ( \ + T_0 p_d_0, \ + T_1 p_d_1) : \ + d_0(p_d_0), \ + d_1(p_d_1) {} \ + virtual void exec(GodotNavigationServer *server) { \ + server->MERGE(_cmd_, F_NAME)(d_0, d_1); \ + } \ + }; \ + void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \ + auto cmd = memnew(MERGE(F_NAME, _command)( \ + D_0, \ + D_1)); \ + add_command(cmd); \ + } \ + void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) + +#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \ + struct MERGE(F_NAME, _command) : public SetCommand { \ + T_0 d_0; \ + T_1 d_1; \ + T_2 d_2; \ + T_3 d_3; \ + MERGE(F_NAME, _command) \ + ( \ + T_0 p_d_0, \ + T_1 p_d_1, \ + T_2 p_d_2, \ + T_3 p_d_3) : \ + d_0(p_d_0), \ + d_1(p_d_1), \ + d_2(p_d_2), \ + d_3(p_d_3) {} \ + virtual void exec(GodotNavigationServer *server) { \ + server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \ + } \ + }; \ + void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) const { \ + auto cmd = memnew(MERGE(F_NAME, _command)( \ + D_0, \ + D_1, \ + D_2, \ + D_3)); \ + add_command(cmd); \ + } \ + void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) + +GodotNavigationServer::GodotNavigationServer() : NavigationServer3D() { } -GdNavigationServer::~GdNavigationServer() { +GodotNavigationServer::~GodotNavigationServer() { flush_queries(); } -void GdNavigationServer::add_command(SetCommand *command) const { - auto mut_this = const_cast<GdNavigationServer *>(this); +void GodotNavigationServer::add_command(SetCommand *command) const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); { MutexLock lock(commands_mutex); mut_this->commands.push_back(command); } } -RID GdNavigationServer::map_create() const { - auto mut_this = const_cast<GdNavigationServer *>(this); +RID GodotNavigationServer::map_create() const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); - NavMap *space = memnew(NavMap); - RID rid = map_owner.make_rid(space); + RID rid = map_owner.make_rid(); + NavMap *space = map_owner.getornull(rid); space->set_self(rid); return rid; } @@ -155,7 +155,7 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) { } } -bool GdNavigationServer::map_is_active(RID p_map) const { +bool GodotNavigationServer::map_is_active(RID p_map) const { NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, false); @@ -169,7 +169,7 @@ COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) { map->set_up(p_up); } -Vector3 GdNavigationServer::map_get_up(RID p_map) const { +Vector3 GodotNavigationServer::map_get_up(RID p_map) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); @@ -183,7 +183,7 @@ COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) { map->set_cell_size(p_cell_size); } -real_t GdNavigationServer::map_get_cell_size(RID p_map) const { +real_t GodotNavigationServer::map_get_cell_size(RID p_map) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, 0); @@ -197,53 +197,53 @@ COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margi map->set_edge_connection_margin(p_connection_margin); } -real_t GdNavigationServer::map_get_edge_connection_margin(RID p_map) const { +real_t GodotNavigationServer::map_get_edge_connection_margin(RID p_map) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, 0); return map->get_edge_connection_margin(); } -Vector<Vector3> GdNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const { +Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>()); return map->get_path(p_origin, p_destination, p_optimize, p_layers); } -Vector3 GdNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { +Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); return map->get_closest_point_to_segment(p_from, p_to, p_use_collision); } -Vector3 GdNavigationServer::map_get_closest_point(RID p_map, const Vector3 &p_point) const { +Vector3 GodotNavigationServer::map_get_closest_point(RID p_map, const Vector3 &p_point) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); return map->get_closest_point(p_point); } -Vector3 GdNavigationServer::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const { +Vector3 GodotNavigationServer::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); return map->get_closest_point_normal(p_point); } -RID GdNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const { +RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, RID()); return map->get_closest_point_owner(p_point); } -RID GdNavigationServer::region_create() const { - auto mut_this = const_cast<GdNavigationServer *>(this); +RID GodotNavigationServer::region_create() const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); - NavRegion *reg = memnew(NavRegion); - RID rid = region_owner.make_rid(reg); + RID rid = region_owner.make_rid(); + NavRegion *reg = region_owner.getornull(rid); reg->set_self(rid); return rid; } @@ -270,7 +270,7 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) { } } -COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform) { +COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND(region == nullptr); @@ -284,7 +284,7 @@ COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) { region->set_layers(p_layers); } -uint32_t GdNavigationServer::region_get_layers(RID p_region) const { +uint32_t GodotNavigationServer::region_get_layers(RID p_region) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(region == nullptr, 0); @@ -298,7 +298,7 @@ COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) { region->set_mesh(p_nav_mesh); } -void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const { +void GodotNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const { ERR_FAIL_COND(r_mesh.is_null()); ERR_FAIL_COND(p_node == nullptr); @@ -308,32 +308,32 @@ void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p #endif } -int GdNavigationServer::region_get_connections_count(RID p_region) const { +int GodotNavigationServer::region_get_connections_count(RID p_region) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(!region, 0); return region->get_connections_count(); } -Vector3 GdNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const { +Vector3 GodotNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(!region, Vector3()); return region->get_connection_pathway_start(p_connection_id); } -Vector3 GdNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const { +Vector3 GodotNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(!region, Vector3()); return region->get_connection_pathway_end(p_connection_id); } -RID GdNavigationServer::agent_create() const { - auto mut_this = const_cast<GdNavigationServer *>(this); +RID GodotNavigationServer::agent_create() const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); - RvoAgent *agent = memnew(RvoAgent()); - RID rid = agent_owner.make_rid(agent); + RID rid = agent_owner.make_rid(); + RvoAgent *agent = agent_owner.getornull(rid); agent->set_self(rid); return rid; } @@ -428,7 +428,7 @@ COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore) { agent->get_agent()->ignore_y_ = p_ignore; } -bool GdNavigationServer::agent_is_map_changed(RID p_agent) const { +bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const { RvoAgent *agent = agent_owner.getornull(p_agent); ERR_FAIL_COND_V(agent == nullptr, false); @@ -472,7 +472,6 @@ COMMAND_1(free, RID, p_object) { active_maps.remove(map_index); active_maps_update_id.remove(map_index); map_owner.free(p_object); - memdelete(map); } else if (region_owner.owns(p_object)) { NavRegion *region = region_owner.getornull(p_object); @@ -484,7 +483,6 @@ COMMAND_1(free, RID, p_object) { } region_owner.free(p_object); - memdelete(region); } else if (agent_owner.owns(p_object)) { RvoAgent *agent = agent_owner.getornull(p_object); @@ -496,20 +494,19 @@ COMMAND_1(free, RID, p_object) { } agent_owner.free(p_object); - memdelete(agent); } else { ERR_FAIL_COND("Invalid ID."); } } -void GdNavigationServer::set_active(bool p_active) const { - auto mut_this = const_cast<GdNavigationServer *>(this); +void GodotNavigationServer::set_active(bool p_active) const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); mut_this->active = p_active; } -void GdNavigationServer::flush_queries() { +void GodotNavigationServer::flush_queries() { // In c++ we can't be sure that this is performed in the main thread // even with mutable functions. MutexLock lock(commands_mutex); @@ -521,7 +518,7 @@ void GdNavigationServer::flush_queries() { commands.clear(); } -void GdNavigationServer::process(real_t p_delta_time) { +void GodotNavigationServer::process(real_t p_delta_time) { flush_queries(); if (!active) { diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/navigation/godot_navigation_server.h index 2f51f6431e..65224493fd 100644 --- a/modules/gdnavigation/gd_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gd_navigation_server.h */ +/* godot_navigation_server.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GD_NAVIGATION_SERVER_H -#define GD_NAVIGATION_SERVER_H +#ifndef GODOT_NAVIGATION_SERVER_H +#define GODOT_NAVIGATION_SERVER_H #include "core/templates/local_vector.h" #include "core/templates/rid.h" @@ -61,31 +61,31 @@ virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) -class GdNavigationServer; +class GodotNavigationServer; struct SetCommand { virtual ~SetCommand() {} - virtual void exec(GdNavigationServer *server) = 0; + virtual void exec(GodotNavigationServer *server) = 0; }; -class GdNavigationServer : public NavigationServer3D { +class GodotNavigationServer : public NavigationServer3D { Mutex commands_mutex; /// Mutex used to make any operation threadsafe. Mutex operations_mutex; std::vector<SetCommand *> commands; - mutable RID_PtrOwner<NavMap> map_owner; - mutable RID_PtrOwner<NavRegion> region_owner; - mutable RID_PtrOwner<RvoAgent> agent_owner; + mutable RID_Owner<NavMap> map_owner; + mutable RID_Owner<NavRegion> region_owner; + mutable RID_Owner<RvoAgent> agent_owner; bool active = true; LocalVector<NavMap *> active_maps; LocalVector<uint32_t> active_maps_update_id; public: - GdNavigationServer(); - virtual ~GdNavigationServer(); + GodotNavigationServer(); + virtual ~GodotNavigationServer(); void add_command(SetCommand *command) const; @@ -113,7 +113,7 @@ public: COMMAND_2(region_set_map, RID, p_region, RID, p_map); COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers); virtual uint32_t region_get_layers(RID p_region) const; - COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform); + COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh); virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const; virtual int region_get_connections_count(RID p_region) const; @@ -146,4 +146,4 @@ public: #undef COMMAND_2 #undef COMMAND_4_DEF -#endif // GD_NAVIGATION_SERVER_H +#endif // GODOT_NAVIGATION_SERVER_H diff --git a/modules/gdnavigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 80f367f3a6..41306f0687 100644 --- a/modules/gdnavigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -112,7 +112,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p } } - // Check for trival cases + // Check for trivial cases if (!begin_poly || !end_poly) { return Vector<Vector3>(); } @@ -168,7 +168,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway); const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance; - auto it = std::find( + const std::vector<gd::NavigationPoly>::iterator it = std::find( navigation_polys.begin(), navigation_polys.end(), gd::NavigationPoly(connection.polygon)); @@ -351,7 +351,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p path.push_back(begin_point); } - path.invert(); + path.reverse(); } else { path.push_back(end_point); @@ -363,7 +363,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p np_id = navigation_polys[np_id].back_navigation_poly_id; } - path.invert(); + path.reverse(); } return path; @@ -504,7 +504,7 @@ void NavMap::add_region(NavRegion *p_region) { } void NavMap::remove_region(NavRegion *p_region) { - std::vector<NavRegion *>::iterator it = std::find(regions.begin(), regions.end(), p_region); + const std::vector<NavRegion *>::iterator it = std::find(regions.begin(), regions.end(), p_region); if (it != regions.end()) { regions.erase(it); regenerate_links = true; @@ -524,7 +524,7 @@ void NavMap::add_agent(RvoAgent *agent) { void NavMap::remove_agent(RvoAgent *agent) { remove_agent_as_controlled(agent); - auto it = std::find(agents.begin(), agents.end(), agent); + const std::vector<RvoAgent *>::iterator it = std::find(agents.begin(), agents.end(), agent); if (it != agents.end()) { agents.erase(it); agents_dirty = true; @@ -540,7 +540,7 @@ void NavMap::set_agent_as_controlled(RvoAgent *agent) { } void NavMap::remove_agent_as_controlled(RvoAgent *agent) { - auto it = std::find(controlled_agents.begin(), controlled_agents.end(), agent); + const std::vector<RvoAgent *>::iterator it = std::find(controlled_agents.begin(), controlled_agents.end(), agent); if (it != controlled_agents.end()) { controlled_agents.erase(it); } diff --git a/modules/gdnavigation/nav_map.h b/modules/navigation/nav_map.h index 8e013a72eb..8e013a72eb 100644 --- a/modules/gdnavigation/nav_map.h +++ b/modules/navigation/nav_map.h diff --git a/modules/gdnavigation/nav_region.cpp b/modules/navigation/nav_region.cpp index c1690b2a4b..81b15a49f5 100644 --- a/modules/gdnavigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -52,7 +52,7 @@ uint32_t NavRegion::get_layers() const { return layers; } -void NavRegion::set_transform(Transform p_transform) { +void NavRegion::set_transform(Transform3D p_transform) { transform = p_transform; polygons_dirty = true; } diff --git a/modules/gdnavigation/nav_region.h b/modules/navigation/nav_region.h index 527b2500ac..f8b067e638 100644 --- a/modules/gdnavigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -46,7 +46,7 @@ class NavRegion; class NavRegion : public NavRid { NavMap *map = nullptr; - Transform transform; + Transform3D transform; Ref<NavigationMesh> mesh; uint32_t layers = 1; Vector<gd::Edge::Connection> connections; @@ -71,8 +71,8 @@ public: void set_layers(uint32_t p_layers); uint32_t get_layers() const; - void set_transform(Transform transform); - const Transform &get_transform() const { + void set_transform(Transform3D transform); + const Transform3D &get_transform() const { return transform; } diff --git a/modules/gdnavigation/nav_rid.h b/modules/navigation/nav_rid.h index a0a60a3643..a0a60a3643 100644 --- a/modules/gdnavigation/nav_rid.h +++ b/modules/navigation/nav_rid.h diff --git a/modules/gdnavigation/nav_utils.h b/modules/navigation/nav_utils.h index 35da391eea..35da391eea 100644 --- a/modules/gdnavigation/nav_utils.h +++ b/modules/navigation/nav_utils.h diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp b/modules/navigation/navigation_mesh_editor_plugin.cpp index aa9248d2a1..aa9248d2a1 100644 --- a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/navigation_mesh_editor_plugin.cpp diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.h b/modules/navigation/navigation_mesh_editor_plugin.h index c39269865b..c39269865b 100644 --- a/modules/gdnavigation/navigation_mesh_editor_plugin.h +++ b/modules/navigation/navigation_mesh_editor_plugin.h diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index a7d4e79148..7aeb9e1858 100644 --- a/modules/gdnavigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -32,7 +32,7 @@ #include "navigation_mesh_generator.h" -#include "core/math/quick_hull.h" +#include "core/math/convex_hull.h" #include "core/os/thread.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/mesh_instance_3d.h" @@ -47,12 +47,12 @@ #include "scene/resources/sphere_shape_3d.h" #include "scene/resources/world_margin_shape_3d.h" -#include "modules/modules_enabled.gen.h" #ifdef TOOLS_ENABLED #include "editor/editor_node.h" #include "editor/editor_settings.h" #endif +#include "modules/modules_enabled.gen.h" #ifdef MODULE_CSG_ENABLED #include "modules/csg/csg_shape.h" #endif @@ -68,7 +68,7 @@ void NavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> & p_verticies.push_back(p_vec3.z); } -void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { +void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { int current_vertex_count; for (int i = 0; i < p_mesh->get_surface_count(); i++) { @@ -123,7 +123,7 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform } } -void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { +void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { int face_count = p_faces.size() / 3; int current_vertex_count = p_verticies.size() / 3; @@ -138,7 +138,7 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons } } -void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { +void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { if (Object::cast_to<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node); Ref<Mesh> mesh = mesh_instance->get_mesh(); @@ -169,7 +169,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, if (Object::cast_to<CollisionShape3D>(child)) { CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child); - Transform transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform(); + Transform3D transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform(); Ref<Mesh> mesh; Ref<Shape3D> s = col_shape->get_shape(); @@ -177,7 +177,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { Ref<BoxMesh> box_mesh; - box_mesh.instance(); + box_mesh.instantiate(); box_mesh->set_size(box->get_size()); mesh = box_mesh; } @@ -185,7 +185,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); if (capsule) { Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instance(); + capsule_mesh.instantiate(); capsule_mesh->set_radius(capsule->get_radius()); capsule_mesh->set_mid_height(capsule->get_height() / 2.0); mesh = capsule_mesh; @@ -194,7 +194,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s); if (cylinder) { Ref<CylinderMesh> cylinder_mesh; - cylinder_mesh.instance(); + cylinder_mesh.instantiate(); cylinder_mesh->set_height(cylinder->get_height()); cylinder_mesh->set_bottom_radius(cylinder->get_radius()); cylinder_mesh->set_top_radius(cylinder->get_radius()); @@ -204,7 +204,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s); if (sphere) { Ref<SphereMesh> sphere_mesh; - sphere_mesh.instance(); + sphere_mesh.instantiate(); sphere_mesh->set_radius(sphere->get_radius()); sphere_mesh->set_height(sphere->get_radius() * 2.0); mesh = sphere_mesh; @@ -220,7 +220,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Vector<Vector3> varr = Variant(convex_polygon->get_points()); Geometry3D::MeshData md; - Error err = QuickHull::build(varr, md); + Error err = ConvexHullComputer::convex_hull(varr, md); if (err == OK) { PackedVector3Array faces; @@ -251,11 +251,11 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, if (Object::cast_to<GridMap>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { GridMap *gridmap_instance = Object::cast_to<GridMap>(p_node); Array meshes = gridmap_instance->get_meshes(); - Transform xform = gridmap_instance->get_transform(); + Transform3D xform = gridmap_instance->get_transform(); for (int i = 0; i < meshes.size(); i += 2) { Ref<Mesh> mesh = meshes[i + 1]; if (mesh.is_valid()) { - _add_mesh(mesh, p_accumulated_transform * xform * meshes[i], p_verticies, p_indices); + _add_mesh(mesh, p_accumulated_transform * xform * (Transform3D)meshes[i], p_verticies, p_indices); } } } @@ -513,7 +513,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes); } - Transform navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse(); + Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse(); for (const List<Node *>::Element *E = parse_nodes.front(); E; E = E->next()) { int geometry_type = p_nav_mesh->get_parsed_geometry_type(); uint32_t collision_mask = p_nav_mesh->get_collision_mask(); diff --git a/modules/gdnavigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h index 88ccdb1c41..847c7d097b 100644 --- a/modules/gdnavigation/navigation_mesh_generator.h +++ b/modules/navigation/navigation_mesh_generator.h @@ -50,9 +50,9 @@ protected: static void _bind_methods(); static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies); - static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); - static void _add_faces(const PackedVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); - static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); + static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); + static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); + static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh); static void _build_recast_navigation_mesh( diff --git a/modules/gdnavigation/register_types.cpp b/modules/navigation/register_types.cpp index 8443d3d242..97c01d42ab 100644 --- a/modules/gdnavigation/register_types.cpp +++ b/modules/navigation/register_types.cpp @@ -31,9 +31,10 @@ #include "register_types.h" #include "core/config/engine.h" -#include "gd_navigation_server.h" #include "servers/navigation_server_3d.h" +#include "godot_navigation_server.h" + #ifndef _3D_DISABLED #include "navigation_mesh_generator.h" #endif @@ -42,38 +43,29 @@ #include "navigation_mesh_editor_plugin.h" #endif -/** - @author AndreaCatania -*/ - #ifndef _3D_DISABLED NavigationMeshGenerator *_nav_mesh_generator = nullptr; #endif NavigationServer3D *new_server() { - return memnew(GdNavigationServer); + return memnew(GodotNavigationServer); } -void register_gdnavigation_types() { +void register_navigation_types() { NavigationServer3DManager::set_default_server(new_server); #ifndef _3D_DISABLED _nav_mesh_generator = memnew(NavigationMeshGenerator); - ClassDB::register_class<NavigationMeshGenerator>(); + GDREGISTER_CLASS(NavigationMeshGenerator); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton())); #endif #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<NavigationMeshEditorPlugin>(); - - ClassDB::APIType prev_api = ClassDB::get_current_api(); - ClassDB::set_current_api(ClassDB::API_EDITOR); - - ClassDB::set_current_api(prev_api); #endif } -void unregister_gdnavigation_types() { +void unregister_navigation_types() { #ifndef _3D_DISABLED if (_nav_mesh_generator) { memdelete(_nav_mesh_generator); diff --git a/modules/squish/image_compress_squish.h b/modules/navigation/register_types.h index 301d30fcf1..4737c818eb 100644 --- a/modules/squish/image_compress_squish.h +++ b/modules/navigation/register_types.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_compress_squish.h */ +/* register_types.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,12 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IMAGE_COMPRESS_SQUISH_H -#define IMAGE_COMPRESS_SQUISH_H +#ifndef NAVIGATION_REGISTER_TYPES_H +#define NAVIGATION_REGISTER_TYPES_H -#include "core/io/image.h" +void register_navigation_types(); +void unregister_navigation_types(); -void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels); -void image_decompress_squish(Image *p_image); - -#endif // IMAGE_COMPRESS_SQUISH_H +#endif // NAVIGATION_REGISTER_TYPES_H diff --git a/modules/gdnavigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp index 21e43d08c1..21e43d08c1 100644 --- a/modules/gdnavigation/rvo_agent.cpp +++ b/modules/navigation/rvo_agent.cpp diff --git a/modules/gdnavigation/rvo_agent.h b/modules/navigation/rvo_agent.h index 369cb1f9a3..369cb1f9a3 100644 --- a/modules/gdnavigation/rvo_agent.h +++ b/modules/navigation/rvo_agent.h diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index 86e7f9cc08..2ae7f8cad9 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -6,11 +6,12 @@ <description> Uses an [OpenSimplexNoise] to fill the texture data. You can specify the texture size but keep in mind that larger textures will take longer to generate and seamless noise only works with square sized textures. NoiseTexture can also generate normal map textures. - The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_data] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the data: + The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data: [codeblock] var texture = preload("res://noise.tres") yield(texture, "changed") - var image = texture.get_data() + var image = texture.get_image() + var data = image.get_data() [/codeblock] </description> <tutorials> @@ -30,6 +31,9 @@ <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise"> The [OpenSimplexNoise] instance used to generate the noise. </member> + <member name="noise_offset" type="Vector2" setter="set_noise_offset" getter="get_noise_offset" default="Vector2(0, 0)"> + An offset used to specify the noise space coordinate of the top left corner of the generated noise. This value is ignored if [member seamless] is enabled. + </member> <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false"> Whether the texture can be tiled without visible seams or not. Seamless textures take longer to generate. [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise. diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index ad82f87213..4d45e41cc3 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -31,8 +31,10 @@ </argument> <argument index="1" name="height" type="int"> </argument> + <argument index="2" name="noise_offset" type="Vector2" default="Vector2(0, 0)"> + </argument> <description> - Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. + Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. If [code]noise_offset[/code] is specified, then the offset value is used as the coordinates of the top-left corner of the generated noise. </description> </method> <method name="get_noise_1d" qualifiers="const"> diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index f5d401b058..66c52ffbf9 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -52,6 +52,9 @@ void NoiseTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise); ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise); + ClassDB::bind_method(D_METHOD("set_noise_offset", "noise_offset"), &NoiseTexture::set_noise_offset); + ClassDB::bind_method(D_METHOD("get_noise_offset"), &NoiseTexture::get_noise_offset); + ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless); ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless); @@ -71,6 +74,7 @@ void NoiseTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normal_map"), "set_as_normal_map", "is_normal_map"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "noise_offset"), "set_noise_offset", "get_noise_offset"); } void NoiseTexture::_validate_property(PropertyInfo &property) const { @@ -81,9 +85,9 @@ void NoiseTexture::_validate_property(PropertyInfo &property) const { } } -void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) { - data = p_image; - if (data.is_valid()) { +void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) { + image = p_image; + if (image.is_valid()) { if (texture.is_valid()) { RID new_texture = RS::get_singleton()->texture_2d_create(p_image); RS::get_singleton()->texture_replace(texture, new_texture); @@ -95,7 +99,7 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) { } void NoiseTexture::_thread_done(const Ref<Image> &p_image) { - _set_texture_data(p_image); + _set_texture_image(p_image); noise_thread.wait_to_finish(); if (regen_queued) { noise_thread.start(_thread_function, this); @@ -130,7 +134,7 @@ Ref<Image> NoiseTexture::_generate_texture() { if (seamless) { image = ref_noise->get_seamless_image(size.x); } else { - image = ref_noise->get_image(size.x, size.y); + image = ref_noise->get_image(size.x, size.y, noise_offset); } if (as_normal_map) { @@ -159,7 +163,7 @@ void NoiseTexture::_update_texture() { } else { Ref<Image> image = _generate_texture(); - _set_texture_data(image); + _set_texture_image(image); } update_queued = false; } @@ -183,6 +187,7 @@ Ref<OpenSimplexNoise> NoiseTexture::get_noise() { } void NoiseTexture::set_width(int p_width) { + ERR_FAIL_COND(p_width <= 0); if (p_width == size.x) { return; } @@ -191,6 +196,7 @@ void NoiseTexture::set_width(int p_width) { } void NoiseTexture::set_height(int p_height) { + ERR_FAIL_COND(p_height <= 0); if (p_height == size.y) { return; } @@ -198,6 +204,14 @@ void NoiseTexture::set_height(int p_height) { _queue_update(); } +void NoiseTexture::set_noise_offset(Vector2 p_noise_offset) { + if (noise_offset == p_noise_offset) { + return; + } + noise_offset = p_noise_offset; + _queue_update(); +} + void NoiseTexture::set_seamless(bool p_seamless) { if (p_seamless == seamless) { return; @@ -245,6 +259,10 @@ int NoiseTexture::get_height() const { return size.y; } +Vector2 NoiseTexture::get_noise_offset() const { + return noise_offset; +} + RID NoiseTexture::get_rid() const { if (!texture.is_valid()) { texture = RS::get_singleton()->texture_2d_placeholder_create(); @@ -253,6 +271,6 @@ RID NoiseTexture::get_rid() const { return texture; } -Ref<Image> NoiseTexture::get_data() const { - return data; +Ref<Image> NoiseTexture::get_image() const { + return image; } diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h index e89479d962..6237b6460d 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/opensimplex/noise_texture.h @@ -34,7 +34,7 @@ #include "open_simplex_noise.h" #include "core/io/image.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/property_editor.h" @@ -43,7 +43,7 @@ class NoiseTexture : public Texture2D { GDCLASS(NoiseTexture, Texture2D); private: - Ref<Image> data; + Ref<Image> image; Thread noise_thread; @@ -56,6 +56,7 @@ private: Ref<OpenSimplexNoise> noise; Vector2i size = Vector2i(512, 512); + Vector2 noise_offset; bool seamless = false; bool as_normal_map = false; float bump_strength = 8.0; @@ -66,7 +67,7 @@ private: void _queue_update(); Ref<Image> _generate_texture(); void _update_texture(); - void _set_texture_data(const Ref<Image> &p_image); + void _set_texture_image(const Ref<Image> &p_image); protected: static void _bind_methods(); @@ -79,6 +80,9 @@ public: void set_width(int p_width); void set_height(int p_height); + void set_noise_offset(Vector2 p_noise_offset); + Vector2 get_noise_offset() const; + void set_seamless(bool p_seamless); bool get_seamless(); @@ -94,7 +98,7 @@ public: virtual RID get_rid() const override; virtual bool has_alpha() const override { return false; } - virtual Ref<Image> get_data() const override; + virtual Ref<Image> get_image() const override; NoiseTexture(); virtual ~NoiseTexture(); diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp index 3773946112..f0a8867284 100644 --- a/modules/opensimplex/open_simplex_noise.cpp +++ b/modules/opensimplex/open_simplex_noise.cpp @@ -96,7 +96,7 @@ void OpenSimplexNoise::set_lacunarity(float p_lacunarity) { emit_changed(); } -Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) const { +Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height, const Vector2 &p_noise_offset) const { Vector<uint8_t> data; data.resize(p_width * p_height); @@ -104,7 +104,7 @@ Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) const { for (int i = 0; i < p_height; i++) { for (int j = 0; j < p_width; j++) { - float v = get_noise_2d(j, i); + float v = get_noise_2d(float(j) + p_noise_offset.x, float(i) + p_noise_offset.y); v = v * 0.5 + 0.5; // Normalize [0..1] wd8[(i * p_width + j)] = uint8_t(CLAMP(v * 255.0, 0, 255)); } @@ -161,7 +161,7 @@ void OpenSimplexNoise::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lacunarity", "lacunarity"), &OpenSimplexNoise::set_lacunarity); ClassDB::bind_method(D_METHOD("get_lacunarity"), &OpenSimplexNoise::get_lacunarity); - ClassDB::bind_method(D_METHOD("get_image", "width", "height"), &OpenSimplexNoise::get_image); + ClassDB::bind_method(D_METHOD("get_image", "width", "height", "noise_offset"), &OpenSimplexNoise::get_image, DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("get_seamless_image", "size"), &OpenSimplexNoise::get_seamless_image); ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &OpenSimplexNoise::get_noise_1d); diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h index 847c157409..dcf922a8bf 100644 --- a/modules/opensimplex/open_simplex_noise.h +++ b/modules/opensimplex/open_simplex_noise.h @@ -32,7 +32,7 @@ #define OPEN_SIMPLEX_NOISE_H #include "core/io/image.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "scene/resources/texture.h" #include "thirdparty/misc/open-simplex-noise.h" @@ -75,7 +75,7 @@ public: void set_lacunarity(float p_lacunarity); float get_lacunarity() const { return lacunarity; } - Ref<Image> get_image(int p_width, int p_height) const; + Ref<Image> get_image(int p_width, int p_height, const Vector2 &p_noise_offset = Vector2()) const; Ref<Image> get_seamless_image(int p_size) const; float get_noise_1d(float x) const; diff --git a/modules/opensimplex/register_types.cpp b/modules/opensimplex/register_types.cpp index e9735a2cc8..d6f9f3436d 100644 --- a/modules/opensimplex/register_types.cpp +++ b/modules/opensimplex/register_types.cpp @@ -33,8 +33,8 @@ #include "open_simplex_noise.h" void register_opensimplex_types() { - ClassDB::register_class<OpenSimplexNoise>(); - ClassDB::register_class<NoiseTexture>(); + GDREGISTER_CLASS(OpenSimplexNoise); + GDREGISTER_CLASS(NoiseTexture); } void unregister_opensimplex_types() { diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp index d2d8976694..980cac17d3 100644 --- a/modules/pvr/image_compress_pvrtc.cpp +++ b/modules/pvr/image_compress_pvrtc.cpp @@ -31,7 +31,7 @@ #include "image_compress_pvrtc.h" #include "core/io/image.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include <PvrTcEncoder.h> #include <RgbaBitmap.h> @@ -43,6 +43,10 @@ static void _compress_pvrtc1_4bpp(Image *p_img) { if (!img->is_size_po2() || img->get_width() != img->get_height()) { make_mipmaps = img->has_mipmaps(); img->resize_to_po2(true); + // Resizing can fail for some formats + if (!img->is_size_po2() || img->get_width() != img->get_height()) { + ERR_FAIL_MSG("Failed to resize the image for compression."); + } } img->convert(Image::FORMAT_RGBA8); if (!img->has_mipmaps() && make_mipmaps) { @@ -52,7 +56,7 @@ static void _compress_pvrtc1_4bpp(Image *p_img) { bool use_alpha = img->detect_alpha(); Ref<Image> new_img; - new_img.instance(); + new_img.instantiate(); new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4); Vector<uint8_t> data = new_img->get_data(); @@ -65,7 +69,7 @@ static void _compress_pvrtc1_4bpp(Image *p_img) { img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); Javelin::RgbaBitmap bm(w, h); void *dst = (void *)bm.GetData(); - copymem(dst, &r[ofs], size); + memcpy(dst, &r[ofs], size); Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); for (int j = 0; j < size / 4; j++) { // Red and blue colors are swapped. diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp index aeac564c93..ef72087d25 100644 --- a/modules/pvr/register_types.cpp +++ b/modules/pvr/register_types.cpp @@ -36,7 +36,7 @@ static Ref<ResourceFormatPVR> resource_loader_pvr; void register_pvr_types() { - resource_loader_pvr.instance(); + resource_loader_pvr.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_pvr); _register_pvrtc_compress_func(); diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp index 83f032ca2b..cb12976090 100644 --- a/modules/pvr/texture_loader_pvr.cpp +++ b/modules/pvr/texture_loader_pvr.cpp @@ -30,7 +30,7 @@ #include "texture_loader_pvr.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" static void _pvrtc_decompress(Image *p_img); diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub new file mode 100644 index 0000000000..6e7b3e7b8d --- /dev/null +++ b/modules/raycast/SCsub @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_raycast = env_modules.Clone() + +# Thirdparty source files + +thirdparty_obj = [] + +if env["builtin_embree"]: + thirdparty_dir = "#thirdparty/embree/" + + embree_src = [ + "common/sys/sysinfo.cpp", + "common/sys/alloc.cpp", + "common/sys/filename.cpp", + "common/sys/library.cpp", + "common/sys/thread.cpp", + "common/sys/string.cpp", + "common/sys/regression.cpp", + "common/sys/mutex.cpp", + "common/sys/condition.cpp", + "common/sys/barrier.cpp", + "common/math/constants.cpp", + "common/simd/sse.cpp", + "common/lexers/stringstream.cpp", + "common/lexers/tokenstream.cpp", + "common/tasking/taskschedulerinternal.cpp", + "kernels/common/device.cpp", + "kernels/common/stat.cpp", + "kernels/common/acceln.cpp", + "kernels/common/accelset.cpp", + "kernels/common/state.cpp", + "kernels/common/rtcore.cpp", + "kernels/common/rtcore_builder.cpp", + "kernels/common/scene.cpp", + "kernels/common/alloc.cpp", + "kernels/common/geometry.cpp", + "kernels/common/scene_triangle_mesh.cpp", + "kernels/geometry/primitive4.cpp", + "kernels/builders/primrefgen.cpp", + "kernels/bvh/bvh.cpp", + "kernels/bvh/bvh_statistics.cpp", + "kernels/bvh/bvh4_factory.cpp", + "kernels/bvh/bvh8_factory.cpp", + "kernels/bvh/bvh_collider.cpp", + "kernels/bvh/bvh_rotate.cpp", + "kernels/bvh/bvh_refit.cpp", + "kernels/bvh/bvh_builder.cpp", + "kernels/bvh/bvh_builder_morton.cpp", + "kernels/bvh/bvh_builder_sah.cpp", + "kernels/bvh/bvh_builder_sah_spatial.cpp", + "kernels/bvh/bvh_builder_sah_mb.cpp", + "kernels/bvh/bvh_builder_twolevel.cpp", + "kernels/bvh/bvh_intersector1_bvh4.cpp", + ] + + thirdparty_sources = [thirdparty_dir + file for file in embree_src] + + env_raycast.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "include"]) + env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"]) + + if not env.msvc: + if env["arch"] in ["x86", "x86_64"]: + env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"]) + + if env["platform"] == "windows": + env_raycast.Append(CPPFLAGS=["-mstackrealign"]) + + if env["platform"] == "windows": + if env.msvc: + env.Append(LINKFLAGS=["psapi.lib"]) + else: + env.Append(LIBS=["psapi"]) + + env_thirdparty = env_raycast.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) + + if not env["arch"] in ["x86", "x86_64"] or env.msvc: + # Embree needs those, it will automatically use SSE2NEON in ARM + env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"]) + + env.modules_sources += thirdparty_obj + + +# Godot source files + +module_obj = [] + +env_raycast.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/raycast/config.py b/modules/raycast/config.py new file mode 100644 index 0000000000..5de36c5322 --- /dev/null +++ b/modules/raycast/config.py @@ -0,0 +1,17 @@ +def can_build(env, platform): + # Depends on Embree library, which only supports x86_64 and aarch64. + + if platform == "android": + return env["android_arch"] in ["arm64v8", "x86_64"] + + if platform == "javascript": + return False # No SIMD support yet + + if env["bits"] == "32": + return False + + return True + + +def configure(env): + pass diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py new file mode 100644 index 0000000000..31a25a318f --- /dev/null +++ b/modules/raycast/godot_update_embree.py @@ -0,0 +1,251 @@ +import glob, os, shutil, subprocess, re + +include_dirs = [ + "common/tasking", + "kernels/bvh", + "kernels/builders", + "common/sys", + "kernels", + "kernels/common", + "common/math", + "common/algorithms", + "common/lexers", + "common/simd", + "common/simd/arm", + "include/embree3", + "kernels/subdiv", + "kernels/geometry", +] + +cpp_files = [ + "common/sys/sysinfo.cpp", + "common/sys/alloc.cpp", + "common/sys/filename.cpp", + "common/sys/library.cpp", + "common/sys/thread.cpp", + "common/sys/string.cpp", + "common/sys/regression.cpp", + "common/sys/mutex.cpp", + "common/sys/condition.cpp", + "common/sys/barrier.cpp", + "common/math/constants.cpp", + "common/simd/sse.cpp", + "common/lexers/stringstream.cpp", + "common/lexers/tokenstream.cpp", + "common/tasking/taskschedulerinternal.cpp", + "kernels/common/device.cpp", + "kernels/common/stat.cpp", + "kernels/common/acceln.cpp", + "kernels/common/accelset.cpp", + "kernels/common/state.cpp", + "kernels/common/rtcore.cpp", + "kernels/common/rtcore_builder.cpp", + "kernels/common/scene.cpp", + "kernels/common/alloc.cpp", + "kernels/common/geometry.cpp", + "kernels/common/scene_triangle_mesh.cpp", + "kernels/geometry/primitive4.cpp", + "kernels/builders/primrefgen.cpp", + "kernels/bvh/bvh.cpp", + "kernels/bvh/bvh_statistics.cpp", + "kernels/bvh/bvh4_factory.cpp", + "kernels/bvh/bvh8_factory.cpp", + "kernels/bvh/bvh_collider.cpp", + "kernels/bvh/bvh_rotate.cpp", + "kernels/bvh/bvh_refit.cpp", + "kernels/bvh/bvh_builder.cpp", + "kernels/bvh/bvh_builder_morton.cpp", + "kernels/bvh/bvh_builder_sah.cpp", + "kernels/bvh/bvh_builder_sah_spatial.cpp", + "kernels/bvh/bvh_builder_sah_mb.cpp", + "kernels/bvh/bvh_builder_twolevel.cpp", + "kernels/bvh/bvh_intersector1.cpp", + "kernels/bvh/bvh_intersector1_bvh4.cpp", +] + +os.chdir("../../thirdparty") + +dir_name = "embree" +if os.path.exists(dir_name): + shutil.rmtree(dir_name) + +subprocess.run(["git", "clone", "https://github.com/embree/embree.git", "embree-tmp"]) +os.chdir("embree-tmp") + +commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip() + +all_files = set(cpp_files) + +dest_dir = os.path.join("..", dir_name) +for include_dir in include_dirs: + headers = glob.iglob(os.path.join(include_dir, "*.h")) + all_files.update(headers) + +for f in all_files: + d = os.path.join(dest_dir, os.path.dirname(f)) + if not os.path.exists(d): + os.makedirs(d) + shutil.copy2(f, d) + +with open(os.path.join(dest_dir, "kernels/hash.h"), "w") as hash_file: + hash_file.write( + f""" +// Copyright 2009-2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#define RTC_HASH "{commit_hash}" +""" + ) + +with open(os.path.join(dest_dir, "kernels/config.h"), "w") as config_file: + config_file.write( + """ +// Copyright 2009-2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +/* #undef EMBREE_RAY_MASK */ +/* #undef EMBREE_STAT_COUNTERS */ +/* #undef EMBREE_BACKFACE_CULLING */ +/* #undef EMBREE_BACKFACE_CULLING_CURVES */ +#define EMBREE_FILTER_FUNCTION +/* #undef EMBREE_IGNORE_INVALID_RAYS */ +#define EMBREE_GEOMETRY_TRIANGLE +/* #undef EMBREE_GEOMETRY_QUAD */ +/* #undef EMBREE_GEOMETRY_CURVE */ +/* #undef EMBREE_GEOMETRY_SUBDIVISION */ +/* #undef EMBREE_GEOMETRY_USER */ +/* #undef EMBREE_GEOMETRY_INSTANCE */ +/* #undef EMBREE_GEOMETRY_GRID */ +/* #undef EMBREE_GEOMETRY_POINT */ +/* #undef EMBREE_RAY_PACKETS */ +/* #undef EMBREE_COMPACT_POLYS */ + +#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0 + +#if defined(EMBREE_GEOMETRY_TRIANGLE) + #define IF_ENABLED_TRIS(x) x +#else + #define IF_ENABLED_TRIS(x) +#endif + +#if defined(EMBREE_GEOMETRY_QUAD) + #define IF_ENABLED_QUADS(x) x +#else + #define IF_ENABLED_QUADS(x) +#endif + +#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT) + #define IF_ENABLED_CURVES_OR_POINTS(x) x +#else + #define IF_ENABLED_CURVES_OR_POINTS(x) +#endif + +#if defined(EMBREE_GEOMETRY_CURVE) + #define IF_ENABLED_CURVES(x) x +#else + #define IF_ENABLED_CURVES(x) +#endif + +#if defined(EMBREE_GEOMETRY_POINT) + #define IF_ENABLED_POINTS(x) x +#else + #define IF_ENABLED_POINTS(x) +#endif + +#if defined(EMBREE_GEOMETRY_SUBDIVISION) + #define IF_ENABLED_SUBDIV(x) x +#else + #define IF_ENABLED_SUBDIV(x) +#endif + +#if defined(EMBREE_GEOMETRY_USER) + #define IF_ENABLED_USER(x) x +#else + #define IF_ENABLED_USER(x) +#endif + +#if defined(EMBREE_GEOMETRY_INSTANCE) + #define IF_ENABLED_INSTANCE(x) x +#else + #define IF_ENABLED_INSTANCE(x) +#endif + +#if defined(EMBREE_GEOMETRY_GRID) + #define IF_ENABLED_GRIDS(x) x +#else + #define IF_ENABLED_GRIDS(x) +#endif +""" + ) + + +with open("CMakeLists.txt", "r") as cmake_file: + cmake_content = cmake_file.read() + major_version = int(re.compile(r"EMBREE_VERSION_MAJOR\s(\d+)").findall(cmake_content)[0]) + minor_version = int(re.compile(r"EMBREE_VERSION_MINOR\s(\d+)").findall(cmake_content)[0]) + patch_version = int(re.compile(r"EMBREE_VERSION_PATCH\s(\d+)").findall(cmake_content)[0]) + +with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as config_file: + config_file.write( + f""" +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#define RTC_VERSION_MAJOR {major_version} +#define RTC_VERSION_MINOR {minor_version} +#define RTC_VERSION_PATCH {patch_version} +#define RTC_VERSION {major_version}{minor_version:02d}{patch_version:02d} +#define RTC_VERSION_STRING "{major_version}.{minor_version}.{patch_version}" + +#define RTC_MAX_INSTANCE_LEVEL_COUNT 1 + +#define EMBREE_MIN_WIDTH 0 +#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH + +#define EMBREE_STATIC_LIB +/* #undef EMBREE_API_NAMESPACE */ + +#if defined(EMBREE_API_NAMESPACE) +# define RTC_NAMESPACE +# define RTC_NAMESPACE_BEGIN namespace {{ +# define RTC_NAMESPACE_END }} +# define RTC_NAMESPACE_USE using namespace ; +# define RTC_API_EXTERN_C +# undef EMBREE_API_NAMESPACE +#else +# define RTC_NAMESPACE_BEGIN +# define RTC_NAMESPACE_END +# define RTC_NAMESPACE_USE +# if defined(__cplusplus) +# define RTC_API_EXTERN_C extern "C" +# else +# define RTC_API_EXTERN_C +# endif +#endif + +#if defined(ISPC) +# define RTC_API_IMPORT extern "C" unmasked +# define RTC_API_EXPORT extern "C" unmasked +#elif defined(EMBREE_STATIC_LIB) +# define RTC_API_IMPORT RTC_API_EXTERN_C +# define RTC_API_EXPORT RTC_API_EXTERN_C +#elif defined(_WIN32) +# define RTC_API_IMPORT RTC_API_EXTERN_C __declspec(dllimport) +# define RTC_API_EXPORT RTC_API_EXTERN_C __declspec(dllexport) +#else +# define RTC_API_IMPORT RTC_API_EXTERN_C +# define RTC_API_EXPORT RTC_API_EXTERN_C __attribute__ ((visibility ("default"))) +#endif + +#if defined(RTC_EXPORT_API) +# define RTC_API RTC_API_EXPORT +#else +# define RTC_API RTC_API_IMPORT +#endif +""" + ) + +os.chdir("..") +shutil.rmtree("embree-tmp") diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp new file mode 100644 index 0000000000..0583acc119 --- /dev/null +++ b/modules/raycast/lightmap_raycaster.cpp @@ -0,0 +1,201 @@ +/*************************************************************************/ +/* lightmap_raycaster.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. */ +/*************************************************************************/ + +#ifdef TOOLS_ENABLED + +#include "lightmap_raycaster.h" + +#ifdef __SSE2__ +#include <pmmintrin.h> +#endif + +LightmapRaycaster *LightmapRaycasterEmbree::create_embree_raycaster() { + return memnew(LightmapRaycasterEmbree); +} + +void LightmapRaycasterEmbree::make_default_raycaster() { + create_function = create_embree_raycaster; +} + +void LightmapRaycasterEmbree::filter_function(const struct RTCFilterFunctionNArguments *p_args) { + RTCHit *hit = (RTCHit *)p_args->hit; + + unsigned int geomID = hit->geomID; + float u = hit->u; + float v = hit->v; + + LightmapRaycasterEmbree *scene = (LightmapRaycasterEmbree *)p_args->geometryUserPtr; + RTCGeometry geom = rtcGetGeometry(scene->embree_scene, geomID); + + rtcInterpolate0(geom, hit->primID, hit->u, hit->v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, &hit->u, 2); + + if (scene->alpha_textures.has(geomID)) { + const AlphaTextureData &alpha_texture = scene->alpha_textures[geomID]; + + if (alpha_texture.sample(hit->u, hit->v) < 128) { + p_args->valid[0] = 0; + return; + } + } + + rtcInterpolate0(geom, hit->primID, u, v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, &hit->Ng_x, 3); +} + +bool LightmapRaycasterEmbree::intersect(Ray &r_ray) { + RTCIntersectContext context; + + rtcInitIntersectContext(&context); + + rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray); + return r_ray.geomID != RTC_INVALID_GEOMETRY_ID; +} + +void LightmapRaycasterEmbree::intersect(Vector<Ray> &r_rays) { + Ray *rays = r_rays.ptrw(); + for (int i = 0; i < r_rays.size(); ++i) { + intersect(rays[i]); + } +} + +void LightmapRaycasterEmbree::set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) { + if (p_alpha_texture.is_valid() && p_alpha_texture->get_size() != Vector2i()) { + AlphaTextureData tex; + tex.size = p_alpha_texture->get_size(); + tex.data = p_alpha_texture->get_data(); + alpha_textures.insert(p_id, tex); + } +} + +float blerp(float c00, float c10, float c01, float c11, float tx, float ty) { + return Math::lerp(Math::lerp(c00, c10, tx), Math::lerp(c01, c11, tx), ty); +} + +uint8_t LightmapRaycasterEmbree::AlphaTextureData::sample(float u, float v) const { + float x = u * size.x; + float y = v * size.y; + int xi = (int)x; + int yi = (int)y; + + uint8_t texels[4]; + + for (int i = 0; i < 4; ++i) { + int sample_x = CLAMP(xi + i % 2, 0, size.x - 1); + int sample_y = CLAMP(yi + i / 2, 0, size.y - 1); + texels[i] = data[sample_y * size.x + sample_x]; + } + + return Math::round(blerp(texels[0], texels[1], texels[2], texels[3], x - xi, y - yi)); +} + +void LightmapRaycasterEmbree::add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) { + RTCGeometry embree_mesh = rtcNewGeometry(embree_device, RTC_GEOMETRY_TYPE_TRIANGLE); + + rtcSetGeometryVertexAttributeCount(embree_mesh, 2); + + int vertex_count = p_vertices.size(); + + ERR_FAIL_COND(vertex_count % 3 != 0); + ERR_FAIL_COND(vertex_count != p_uv2s.size()); + ERR_FAIL_COND(!p_normals.is_empty() && vertex_count != p_normals.size()); + + Vector3 *embree_vertices = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count); + memcpy(embree_vertices, p_vertices.ptr(), sizeof(Vector3) * vertex_count); + + Vector2 *embree_light_uvs = (Vector2 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vector2), vertex_count); + memcpy(embree_light_uvs, p_uv2s.ptr(), sizeof(Vector2) * vertex_count); + + uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3); + for (int i = 0; i < vertex_count; i++) { + embree_triangles[i] = i; + } + + if (!p_normals.is_empty()) { + Vector3 *embree_normals = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count); + memcpy(embree_normals, p_normals.ptr(), sizeof(Vector3) * vertex_count); + } + + rtcCommitGeometry(embree_mesh); + rtcSetGeometryIntersectFilterFunction(embree_mesh, filter_function); + rtcSetGeometryUserData(embree_mesh, this); + rtcAttachGeometryByID(embree_scene, embree_mesh, p_id); + rtcReleaseGeometry(embree_mesh); +} + +void LightmapRaycasterEmbree::commit() { + rtcCommitScene(embree_scene); +} + +void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) { + for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) { + rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get())); + } + rtcCommitScene(embree_scene); + filter_meshes = p_mesh_ids; +} + +void LightmapRaycasterEmbree::clear_mesh_filter() { + for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) { + rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get())); + } + rtcCommitScene(embree_scene); + filter_meshes.clear(); +} + +void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) { + print_error("Embree error: " + String(p_str)); +} + +LightmapRaycasterEmbree::LightmapRaycasterEmbree() { +#ifdef __SSE2__ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); +#endif + + embree_device = rtcNewDevice(nullptr); + rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr); + embree_scene = rtcNewScene(embree_device); +} + +LightmapRaycasterEmbree::~LightmapRaycasterEmbree() { +#ifdef __SSE2__ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); +#endif + + if (embree_scene != nullptr) { + rtcReleaseScene(embree_scene); + } + + if (embree_device != nullptr) { + rtcReleaseDevice(embree_device); + } +} + +#endif diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h new file mode 100644 index 0000000000..4c3de27837 --- /dev/null +++ b/modules/raycast/lightmap_raycaster.h @@ -0,0 +1,77 @@ +/*************************************************************************/ +/* lightmap_raycaster.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. */ +/*************************************************************************/ + +#ifdef TOOLS_ENABLED + +#include "core/object/object.h" +#include "scene/3d/lightmapper.h" +#include "scene/resources/mesh.h" + +#include <embree3/rtcore.h> + +class LightmapRaycasterEmbree : public LightmapRaycaster { + GDCLASS(LightmapRaycasterEmbree, LightmapRaycaster); + +private: + struct AlphaTextureData { + Vector<uint8_t> data; + Vector2i size; + + uint8_t sample(float u, float v) const; + }; + + RTCDevice embree_device; + RTCScene embree_scene; + + static void filter_function(const struct RTCFilterFunctionNArguments *p_args); + + Map<unsigned int, AlphaTextureData> alpha_textures; + Set<int> filter_meshes; + +public: + virtual bool intersect(Ray &p_ray) override; + + virtual void intersect(Vector<Ray> &r_rays) override; + + virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) override; + virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) override; + virtual void commit() override; + + virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override; + virtual void clear_mesh_filter() override; + + static LightmapRaycaster *create_embree_raycaster(); + static void make_default_raycaster(); + + LightmapRaycasterEmbree(); + ~LightmapRaycasterEmbree(); +}; + +#endif diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp new file mode 100644 index 0000000000..88c0145ebc --- /dev/null +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -0,0 +1,583 @@ +/*************************************************************************/ +/* raycast_occlusion_cull.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 "raycast_occlusion_cull.h" +#include "core/config/project_settings.h" +#include "core/templates/local_vector.h" + +#ifdef __SSE2__ +#include <pmmintrin.h> +#endif + +RaycastOcclusionCull *RaycastOcclusionCull::raycast_singleton = nullptr; + +void RaycastOcclusionCull::RaycastHZBuffer::clear() { + HZBuffer::clear(); + + camera_rays.clear(); + camera_ray_masks.clear(); + packs_size = Size2i(); +} + +void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) { + if (p_size == Size2i()) { + clear(); + return; + } + + if (!sizes.is_empty() && p_size == sizes[0]) { + return; // Size didn't change + } + + HZBuffer::resize(p_size); + + packs_size = Size2i(Math::ceil(p_size.x / (float)TILE_SIZE), Math::ceil(p_size.y / (float)TILE_SIZE)); + int ray_packets_count = packs_size.x * packs_size.y; + camera_rays.resize(ray_packets_count); + camera_ray_masks.resize(ray_packets_count * TILE_SIZE * TILE_SIZE); +} + +void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool) { + CameraRayThreadData td; + td.camera_matrix = p_cam_projection; + td.camera_transform = p_cam_transform; + td.camera_orthogonal = p_cam_orthogonal; + td.thread_count = p_thread_work_pool.get_thread_count(); + + p_thread_work_pool.do_work(td.thread_count, this, &RaycastHZBuffer::_camera_rays_threaded, &td); +} + +void RaycastOcclusionCull::RaycastHZBuffer::_camera_rays_threaded(uint32_t p_thread, RaycastOcclusionCull::RaycastHZBuffer::CameraRayThreadData *p_data) { + uint32_t packs_total = camera_rays.size(); + uint32_t total_threads = p_data->thread_count; + uint32_t from = p_thread * packs_total / total_threads; + uint32_t to = (p_thread + 1 == total_threads) ? packs_total : ((p_thread + 1) * packs_total / total_threads); + _generate_camera_rays(p_data->camera_transform, p_data->camera_matrix, p_data->camera_orthogonal, from, to); +} + +void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to) { + Size2i buffer_size = sizes[0]; + + CameraMatrix inv_camera_matrix = p_cam_projection.inverse(); + float z_far = p_cam_projection.get_z_far() * 1.05f; + debug_tex_range = z_far; + + RayPacket *ray_packets = camera_rays.ptr(); + uint32_t *ray_masks = camera_ray_masks.ptr(); + + for (int i = p_from; i < p_to; i++) { + RayPacket &packet = ray_packets[i]; + int tile_x = (i % packs_size.x) * TILE_SIZE; + int tile_y = (i / packs_size.x) * TILE_SIZE; + + for (int j = 0; j < TILE_RAYS; j++) { + float x = tile_x + j % TILE_SIZE; + float y = tile_y + j / TILE_SIZE; + + ray_masks[i * TILE_RAYS + j] = ~0U; + + if (x >= buffer_size.x || y >= buffer_size.y) { + ray_masks[i * TILE_RAYS + j] = 0U; + } else { + float u = x / (buffer_size.x - 1); + float v = y / (buffer_size.y - 1); + u = u * 2.0f - 1.0f; + v = v * 2.0f - 1.0f; + + Plane pixel_proj = Plane(u, v, -1.0, 1.0); + Plane pixel_view = inv_camera_matrix.xform4(pixel_proj); + Vector3 pixel_world = p_cam_transform.xform(pixel_view.normal); + + Vector3 dir; + if (p_cam_orthogonal) { + dir = -p_cam_transform.basis.get_axis(2); + } else { + dir = (pixel_world - p_cam_transform.origin).normalized(); + } + + packet.ray.org_x[j] = pixel_world.x; + packet.ray.org_y[j] = pixel_world.y; + packet.ray.org_z[j] = pixel_world.z; + + packet.ray.dir_x[j] = dir.x; + packet.ray.dir_y[j] = dir.y; + packet.ray.dir_z[j] = dir.z; + + packet.ray.tnear[j] = 0.0f; + + packet.ray.time[j] = 0.0f; + + packet.ray.flags[j] = 0; + packet.ray.mask[j] = -1; + packet.hit.geomID[j] = RTC_INVALID_GEOMETRY_ID; + } + + packet.ray.tfar[j] = z_far; + } + } +} + +void RaycastOcclusionCull::RaycastHZBuffer::sort_rays() { + if (is_empty()) { + return; + } + + Size2i buffer_size = sizes[0]; + for (int i = 0; i < packs_size.y; i++) { + for (int j = 0; j < packs_size.x; j++) { + for (int tile_i = 0; tile_i < TILE_SIZE; tile_i++) { + for (int tile_j = 0; tile_j < TILE_SIZE; tile_j++) { + int x = j * TILE_SIZE + tile_j; + int y = i * TILE_SIZE + tile_i; + if (x >= buffer_size.x || y >= buffer_size.y) { + continue; + } + int k = tile_i * TILE_SIZE + tile_j; + int packet_index = i * packs_size.x + j; + mips[0][y * buffer_size.x + x] = camera_rays[packet_index].ray.tfar[k]; + } + } + } + } +} + +//////////////////////////////////////////////////////// + +bool RaycastOcclusionCull::is_occluder(RID p_rid) { + return occluder_owner.owns(p_rid); +} + +RID RaycastOcclusionCull::occluder_allocate() { + return occluder_owner.allocate_rid(); +} + +void RaycastOcclusionCull::occluder_initialize(RID p_occluder) { + Occluder *occluder = memnew(Occluder); + occluder_owner.initialize_rid(p_occluder, occluder); +} + +void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { + Occluder *occluder = occluder_owner.getornull(p_occluder); + ERR_FAIL_COND(!occluder); + + occluder->vertices = p_vertices; + occluder->indices = p_indices; + + for (Set<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) { + RID scenario_rid = E->get().scenario; + RID instance_rid = E->get().instance; + ERR_CONTINUE(!scenarios.has(scenario_rid)); + Scenario &scenario = scenarios[scenario_rid]; + ERR_CONTINUE(!scenario.instances.has(instance_rid)); + + if (!scenario.dirty_instances.has(instance_rid)) { + scenario.dirty_instances.insert(instance_rid); + scenario.dirty_instances_array.push_back(instance_rid); + } + } +} + +void RaycastOcclusionCull::free_occluder(RID p_occluder) { + Occluder *occluder = occluder_owner.getornull(p_occluder); + ERR_FAIL_COND(!occluder); + memdelete(occluder); + occluder_owner.free(p_occluder); +} + +//////////////////////////////////////////////////////// + +void RaycastOcclusionCull::add_scenario(RID p_scenario) { + if (scenarios.has(p_scenario)) { + scenarios[p_scenario].removed = false; + } else { + scenarios[p_scenario] = Scenario(); + } +} + +void RaycastOcclusionCull::remove_scenario(RID p_scenario) { + ERR_FAIL_COND(!scenarios.has(p_scenario)); + Scenario &scenario = scenarios[p_scenario]; + scenario.removed = true; +} + +void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) { + ERR_FAIL_COND(!scenarios.has(p_scenario)); + Scenario &scenario = scenarios[p_scenario]; + + if (!scenario.instances.has(p_instance)) { + scenario.instances[p_instance] = OccluderInstance(); + } + + OccluderInstance &instance = scenario.instances[p_instance]; + + if (instance.removed) { + instance.removed = false; + scenario.removed_instances.erase(p_instance); + } + + bool changed = false; + + if (instance.occluder != p_occluder) { + Occluder *old_occluder = occluder_owner.getornull(instance.occluder); + if (old_occluder) { + old_occluder->users.erase(InstanceID(p_scenario, p_instance)); + } + + instance.occluder = p_occluder; + + if (p_occluder.is_valid()) { + Occluder *occluder = occluder_owner.getornull(p_occluder); + ERR_FAIL_COND(!occluder); + occluder->users.insert(InstanceID(p_scenario, p_instance)); + } + changed = true; + } + + if (instance.xform != p_xform) { + scenario.instances[p_instance].xform = p_xform; + changed = true; + } + + if (instance.enabled != p_enabled) { + instance.enabled = p_enabled; + scenario.dirty = true; // The scenario needs a scene re-build, but the instance doesn't need update + } + + if (changed && !scenario.dirty_instances.has(p_instance)) { + scenario.dirty_instances.insert(p_instance); + scenario.dirty_instances_array.push_back(p_instance); + scenario.dirty = true; + } +} + +void RaycastOcclusionCull::scenario_remove_instance(RID p_scenario, RID p_instance) { + ERR_FAIL_COND(!scenarios.has(p_scenario)); + Scenario &scenario = scenarios[p_scenario]; + + if (scenario.instances.has(p_instance)) { + OccluderInstance &instance = scenario.instances[p_instance]; + + if (!instance.removed) { + Occluder *occluder = occluder_owner.getornull(instance.occluder); + if (occluder) { + occluder->users.erase(InstanceID(p_scenario, p_instance)); + } + + scenario.removed_instances.push_back(p_instance); + instance.removed = true; + } + } +} + +void RaycastOcclusionCull::Scenario::_update_dirty_instance_thread(int p_idx, RID *p_instances) { + _update_dirty_instance(p_idx, p_instances, nullptr); +} + +void RaycastOcclusionCull::Scenario::_update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool) { + OccluderInstance *occ_inst = instances.getptr(p_instances[p_idx]); + + if (!occ_inst) { + return; + } + + Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder); + + if (!occ) { + return; + } + + int vertices_size = occ->vertices.size(); + + // Embree requires the last element to be readable by a 16-byte SSE load instruction, so we add padding to be safe. + occ_inst->xformed_vertices.resize(vertices_size + 1); + + const Vector3 *read_ptr = occ->vertices.ptr(); + Vector3 *write_ptr = occ_inst->xformed_vertices.ptr(); + + if (p_thread_pool && vertices_size > 1024) { + TransformThreadData td; + td.xform = occ_inst->xform; + td.read = read_ptr; + td.write = write_ptr; + td.vertex_count = vertices_size; + td.thread_count = p_thread_pool->get_thread_count(); + p_thread_pool->do_work(td.thread_count, this, &Scenario::_transform_vertices_thread, &td); + } else { + _transform_vertices_range(read_ptr, write_ptr, occ_inst->xform, 0, vertices_size); + } + + occ_inst->indices.resize(occ->indices.size()); + memcpy(occ_inst->indices.ptr(), occ->indices.ptr(), occ->indices.size() * sizeof(int32_t)); +} + +void RaycastOcclusionCull::Scenario::_transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data) { + uint32_t vertex_total = p_data->vertex_count; + uint32_t total_threads = p_data->thread_count; + uint32_t from = p_thread * vertex_total / total_threads; + uint32_t to = (p_thread + 1 == total_threads) ? vertex_total : ((p_thread + 1) * vertex_total / total_threads); + _transform_vertices_range(p_data->read, p_data->write, p_data->xform, from, to); +} + +void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to) { + for (int i = p_from; i < p_to; i++) { + p_write[i] = p_xform.xform(p_read[i]); + } +} + +void RaycastOcclusionCull::Scenario::_commit_scene(void *p_ud) { + Scenario *scenario = (Scenario *)p_ud; + int commit_idx = 1 - (scenario->current_scene_idx); + rtcCommitScene(scenario->ebr_scene[commit_idx]); + scenario->commit_done = true; +} + +bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) { + ERR_FAIL_COND_V(singleton == nullptr, false); + + if (commit_thread == nullptr) { + commit_thread = memnew(Thread); + } + + if (commit_thread->is_started()) { + if (commit_done) { + commit_thread->wait_to_finish(); + current_scene_idx = 1 - current_scene_idx; + } else { + return false; + } + } + + if (removed) { + if (ebr_scene[0]) { + rtcReleaseScene(ebr_scene[0]); + } + if (ebr_scene[1]) { + rtcReleaseScene(ebr_scene[1]); + } + return true; + } + + if (!dirty && removed_instances.is_empty() && dirty_instances_array.is_empty()) { + return false; + } + + for (unsigned int i = 0; i < removed_instances.size(); i++) { + instances.erase(removed_instances[i]); + } + + if (dirty_instances_array.size() / p_thread_pool.get_thread_count() > 128) { + // Lots of instances, use per-instance threading + p_thread_pool.do_work(dirty_instances_array.size(), this, &Scenario::_update_dirty_instance_thread, dirty_instances_array.ptr()); + } else { + // Few instances, use threading on the vertex transforms + for (unsigned int i = 0; i < dirty_instances_array.size(); i++) { + _update_dirty_instance(i, dirty_instances_array.ptr(), &p_thread_pool); + } + } + + dirty_instances.clear(); + dirty_instances_array.clear(); + removed_instances.clear(); + + if (raycast_singleton->ebr_device == nullptr) { + raycast_singleton->_init_embree(); + } + + int next_scene_idx = 1 - current_scene_idx; + RTCScene &next_scene = ebr_scene[next_scene_idx]; + + if (next_scene) { + rtcReleaseScene(next_scene); + } + + next_scene = rtcNewScene(raycast_singleton->ebr_device); + rtcSetSceneBuildQuality(next_scene, RTCBuildQuality(raycast_singleton->build_quality)); + + const RID *inst_rid = nullptr; + while ((inst_rid = instances.next(inst_rid))) { + OccluderInstance *occ_inst = instances.getptr(*inst_rid); + Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder); + + if (!occ || !occ_inst->enabled) { + continue; + } + + RTCGeometry geom = rtcNewGeometry(raycast_singleton->ebr_device, RTC_GEOMETRY_TYPE_TRIANGLE); + rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, occ_inst->xformed_vertices.ptr(), 0, sizeof(Vector3), occ_inst->xformed_vertices.size()); + rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, occ_inst->indices.ptr(), 0, sizeof(uint32_t) * 3, occ_inst->indices.size() / 3); + rtcCommitGeometry(geom); + rtcAttachGeometry(next_scene, geom); + rtcReleaseGeometry(geom); + } + + dirty = false; + commit_done = false; + commit_thread->start(&Scenario::_commit_scene, this); + return false; +} + +void RaycastOcclusionCull::Scenario::_raycast(uint32_t p_idx, const RaycastThreadData *p_raycast_data) const { + RTCIntersectContext ctx; + rtcInitIntersectContext(&ctx); + ctx.flags = RTC_INTERSECT_CONTEXT_FLAG_COHERENT; + + rtcIntersect16((const int *)&p_raycast_data->masks[p_idx * TILE_RAYS], ebr_scene[current_scene_idx], &ctx, &p_raycast_data->rays[p_idx]); +} + +void RaycastOcclusionCull::Scenario::raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const { + ERR_FAIL_COND(singleton == nullptr); + if (raycast_singleton->ebr_device == nullptr) { + return; // Embree is initialized on demand when there is some scenario with occluders in it. + } + + if (ebr_scene[current_scene_idx] == nullptr) { + return; + } + + RaycastThreadData td; + td.rays = r_rays.ptr(); + td.masks = p_valid_masks.ptr(); + + p_thread_pool.do_work(r_rays.size(), this, &Scenario::_raycast, &td); +} + +//////////////////////////////////////////////////////// + +void RaycastOcclusionCull::add_buffer(RID p_buffer) { + ERR_FAIL_COND(buffers.has(p_buffer)); + buffers[p_buffer] = RaycastHZBuffer(); +} + +void RaycastOcclusionCull::remove_buffer(RID p_buffer) { + ERR_FAIL_COND(!buffers.has(p_buffer)); + buffers.erase(p_buffer); +} + +void RaycastOcclusionCull::buffer_set_scenario(RID p_buffer, RID p_scenario) { + ERR_FAIL_COND(!buffers.has(p_buffer)); + ERR_FAIL_COND(p_scenario.is_valid() && !scenarios.has(p_scenario)); + buffers[p_buffer].scenario_rid = p_scenario; +} + +void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size) { + ERR_FAIL_COND(!buffers.has(p_buffer)); + buffers[p_buffer].resize(p_size); +} + +void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) { + if (!buffers.has(p_buffer)) { + return; + } + + RaycastHZBuffer &buffer = buffers[p_buffer]; + + if (buffer.is_empty() || !scenarios.has(buffer.scenario_rid)) { + return; + } + + Scenario &scenario = scenarios[buffer.scenario_rid]; + + bool removed = scenario.update(p_thread_pool); + + if (removed) { + scenarios.erase(buffer.scenario_rid); + return; + } + + buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_thread_pool); + + scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks, p_thread_pool); + buffer.sort_rays(); + buffer.update_mips(); +} + +RaycastOcclusionCull::HZBuffer *RaycastOcclusionCull::buffer_get_ptr(RID p_buffer) { + if (!buffers.has(p_buffer)) { + return nullptr; + } + return &buffers[p_buffer]; +} + +RID RaycastOcclusionCull::buffer_get_debug_texture(RID p_buffer) { + ERR_FAIL_COND_V(!buffers.has(p_buffer), RID()); + return buffers[p_buffer].get_debug_texture(); +} + +//////////////////////////////////////////////////////// + +void RaycastOcclusionCull::set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) { + if (build_quality == p_quality) { + return; + } + + build_quality = p_quality; + + const RID *scenario_rid = nullptr; + while ((scenario_rid = scenarios.next(scenario_rid))) { + scenarios[*scenario_rid].dirty = true; + } +} + +void RaycastOcclusionCull::_init_embree() { +#ifdef __SSE2__ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); +#endif + + String settings = vformat("threads=%d", MAX(1, OS::get_singleton()->get_processor_count() - 2)); + ebr_device = rtcNewDevice(settings.utf8().ptr()); +} + +RaycastOcclusionCull::RaycastOcclusionCull() { + raycast_singleton = this; + int default_quality = GLOBAL_GET("rendering/occlusion_culling/bvh_build_quality"); + build_quality = RS::ViewportOcclusionCullingBuildQuality(default_quality); +} + +RaycastOcclusionCull::~RaycastOcclusionCull() { + const RID *scenario_rid = nullptr; + while ((scenario_rid = scenarios.next(scenario_rid))) { + Scenario &scenario = scenarios[*scenario_rid]; + if (scenario.commit_thread) { + scenario.commit_thread->wait_to_finish(); + memdelete(scenario.commit_thread); + } + } + + if (ebr_device != nullptr) { +#ifdef __SSE2__ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); +#endif + rtcReleaseDevice(ebr_device); + } + + raycast_singleton = nullptr; +} diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h new file mode 100644 index 0000000000..85710a790c --- /dev/null +++ b/modules/raycast/raycast_occlusion_cull.h @@ -0,0 +1,184 @@ +/*************************************************************************/ +/* raycast_occlusion_cull.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 OCCLUSION_CULL_RAYCASTER_H +#define OCCLUSION_CULL_RAYCASTER_H + +#include "core/io/image.h" +#include "core/math/camera_matrix.h" +#include "core/object/object.h" +#include "core/object/ref_counted.h" +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "scene/resources/mesh.h" +#include "servers/rendering/renderer_scene_occlusion_cull.h" + +#include <embree3/rtcore.h> + +class RaycastOcclusionCull : public RendererSceneOcclusionCull { + typedef RTCRayHit16 RayPacket; + +public: + class RaycastHZBuffer : public HZBuffer { + private: + Size2i packs_size; + + struct CameraRayThreadData { + CameraMatrix camera_matrix; + Transform3D camera_transform; + bool camera_orthogonal; + int thread_count; + Size2i buffer_size; + }; + + void _camera_rays_threaded(uint32_t p_thread, CameraRayThreadData *p_data); + void _generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to); + + public: + LocalVector<RayPacket> camera_rays; + LocalVector<uint32_t> camera_ray_masks; + RID scenario_rid; + + virtual void clear() override; + virtual void resize(const Size2i &p_size) override; + void sort_rays(); + void update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool); + }; + +private: + struct InstanceID { + RID scenario; + RID instance; + + bool operator<(const InstanceID &rhs) const { + if (instance == rhs.instance) { + return rhs.scenario < scenario; + } + return instance < rhs.instance; + } + + InstanceID() {} + InstanceID(RID s, RID i) : + scenario(s), instance(i) {} + }; + + struct Occluder { + PackedVector3Array vertices; + PackedInt32Array indices; + Set<InstanceID> users; + }; + + struct OccluderInstance { + RID occluder; + LocalVector<uint32_t> indices; + LocalVector<Vector3> xformed_vertices; + Transform3D xform; + bool enabled = true; + bool removed = false; + }; + + struct Scenario { + struct RaycastThreadData { + RayPacket *rays; + const uint32_t *masks; + }; + + struct TransformThreadData { + uint32_t thread_count; + uint32_t vertex_count; + Transform3D xform; + const Vector3 *read; + Vector3 *write; + }; + + Thread *commit_thread = nullptr; + bool commit_done = true; + bool dirty = false; + bool removed = false; + + RTCScene ebr_scene[2] = { nullptr, nullptr }; + int current_scene_idx = 0; + + HashMap<RID, OccluderInstance> instances; + Set<RID> dirty_instances; // To avoid duplicates + LocalVector<RID> dirty_instances_array; // To iterate and split into threads + LocalVector<RID> removed_instances; + + void _update_dirty_instance_thread(int p_idx, RID *p_instances); + void _update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool); + void _transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data); + void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to); + static void _commit_scene(void *p_ud); + bool update(ThreadWorkPool &p_thread_pool); + + void _raycast(uint32_t p_thread, const RaycastThreadData *p_raycast_data) const; + void raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const; + }; + + static RaycastOcclusionCull *raycast_singleton; + + static const int TILE_SIZE = 4; + static const int TILE_RAYS = TILE_SIZE * TILE_SIZE; + + RTCDevice ebr_device = nullptr; + RID_PtrOwner<Occluder> occluder_owner; + HashMap<RID, Scenario> scenarios; + HashMap<RID, RaycastHZBuffer> buffers; + RS::ViewportOcclusionCullingBuildQuality build_quality; + + void _init_embree(); + +public: + virtual bool is_occluder(RID p_rid) override; + virtual RID occluder_allocate() override; + virtual void occluder_initialize(RID p_occluder) override; + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) override; + virtual void free_occluder(RID p_occluder) override; + + virtual void add_scenario(RID p_scenario) override; + virtual void remove_scenario(RID p_scenario) override; + virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) override; + virtual void scenario_remove_instance(RID p_scenario, RID p_instance) override; + + virtual void add_buffer(RID p_buffer) override; + virtual void remove_buffer(RID p_buffer) override; + virtual HZBuffer *buffer_get_ptr(RID p_buffer) override; + virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) override; + virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) override; + virtual void buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) override; + virtual RID buffer_get_debug_texture(RID p_buffer) override; + + virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) override; + + RaycastOcclusionCull(); + ~RaycastOcclusionCull(); +}; + +#endif // OCCLUSION_CULL_RAYCASTER_H diff --git a/modules/etc/register_types.cpp b/modules/raycast/register_types.cpp index b165bccb3e..78ca91309f 100644 --- a/modules/etc/register_types.cpp +++ b/modules/raycast/register_types.cpp @@ -30,19 +30,20 @@ #include "register_types.h" -#include "image_compress_etc.h" -#include "texture_loader_pkm.h" +#include "lightmap_raycaster.h" +#include "raycast_occlusion_cull.h" -static Ref<ResourceFormatPKM> resource_loader_pkm; +RaycastOcclusionCull *raycast_occlusion_cull = nullptr; -void register_etc_types() { - resource_loader_pkm.instance(); - ResourceLoader::add_resource_format_loader(resource_loader_pkm); - - _register_etc_compress_func(); +void register_raycast_types() { +#ifdef TOOLS_ENABLED + LightmapRaycasterEmbree::make_default_raycaster(); +#endif + raycast_occlusion_cull = memnew(RaycastOcclusionCull); } -void unregister_etc_types() { - ResourceLoader::remove_resource_format_loader(resource_loader_pkm); - resource_loader_pkm.unref(); +void unregister_raycast_types() { + if (raycast_occlusion_cull) { + memdelete(raycast_occlusion_cull); + } } diff --git a/modules/etc/register_types.h b/modules/raycast/register_types.h index e8cbb635ae..789604a491 100644 --- a/modules/etc/register_types.h +++ b/modules/raycast/register_types.h @@ -28,10 +28,5 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef ETC_REGISTER_TYPES_H -#define ETC_REGISTER_TYPES_H - -void register_etc_types(); -void unregister_etc_types(); - -#endif // ETC_REGISTER_TYPES_H +void register_raycast_types(); +void unregister_raycast_types(); diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index b21f5d1e7a..7f5a0dfecb 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RegEx" inherits="Reference" version="4.0"> +<class name="RegEx" inherits="RefCounted" version="4.0"> <brief_description> Class for searching text for patterns using regular expressions. </brief_description> diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml index a45de60aef..492519d3d9 100644 --- a/modules/regex/doc_classes/RegExMatch.xml +++ b/modules/regex/doc_classes/RegExMatch.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RegExMatch" inherits="Reference" version="4.0"> +<class name="RegExMatch" inherits="RefCounted" version="4.0"> <brief_description> Contains the results of a [RegEx] search. </brief_description> @@ -51,7 +51,7 @@ <member name="names" type="Dictionary" setter="" getter="get_names" default="{}"> A dictionary of named groups and its corresponding group number. Only groups that were matched are included. If multiple groups have the same name, that name would refer to the first matching one. </member> - <member name="strings" type="Array" setter="" getter="get_strings" default="[ ]"> + <member name="strings" type="Array" setter="" getter="get_strings" default="[]"> An [Array] of the match and its capturing groups. </member> <member name="subject" type="String" setter="" getter="get_subject" default=""""> diff --git a/modules/regex/regex.h b/modules/regex/regex.h index f5773042fb..68fe2bc6e0 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -31,15 +31,15 @@ #ifndef REGEX_H #define REGEX_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/templates/map.h" #include "core/templates/vector.h" #include "core/variant/array.h" #include "core/variant/dictionary.h" -class RegExMatch : public Reference { - GDCLASS(RegExMatch, Reference); +class RegExMatch : public RefCounted { + GDCLASS(RegExMatch, RefCounted); struct Range { int start = 0; @@ -68,8 +68,8 @@ public: int get_end(const Variant &p_name) const; }; -class RegEx : public Reference { - GDCLASS(RegEx, Reference); +class RegEx : public RefCounted { + GDCLASS(RegEx, RefCounted); void *general_ctx; void *code = nullptr; diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp index 82f3eaf707..03957f88cf 100644 --- a/modules/regex/register_types.cpp +++ b/modules/regex/register_types.cpp @@ -33,8 +33,8 @@ #include "regex.h" void register_regex_types() { - ClassDB::register_class<RegExMatch>(); - ClassDB::register_class<RegEx>(); + GDREGISTER_CLASS(RegExMatch); + GDREGISTER_CLASS(RegEx); } void unregister_regex_types() { diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_decompress_squish.cpp index cce08034df..1450b0fe88 100644 --- a/modules/squish/image_compress_squish.cpp +++ b/modules/squish/image_decompress_squish.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_compress_squish.cpp */ +/* image_decompress_squish.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "image_compress_squish.h" +#include "image_decompress_squish.h" #include <squish.h> @@ -76,83 +76,3 @@ void image_decompress_squish(Image *p_image) { p_image->convert_ra_rgba8_to_rg(); } } - -void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels) { - if (p_image->get_format() >= Image::FORMAT_DXT1) { - return; //do not compress, already compressed - } - - int w = p_image->get_width(); - int h = p_image->get_height(); - - if (p_image->get_format() <= Image::FORMAT_RGBA8) { - int squish_comp = squish::kColourRangeFit; - - if (p_lossy_quality > 0.85) { - squish_comp = squish::kColourIterativeClusterFit; - } else if (p_lossy_quality > 0.75) { - squish_comp = squish::kColourClusterFit; - } - - Image::Format target_format = Image::FORMAT_RGBA8; - - p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert - - switch (p_channels) { - case Image::USED_CHANNELS_L: { - target_format = Image::FORMAT_DXT1; - squish_comp |= squish::kDxt1; - } break; - case Image::USED_CHANNELS_LA: { - target_format = Image::FORMAT_DXT5; - squish_comp |= squish::kDxt5; - } break; - case Image::USED_CHANNELS_R: { - target_format = Image::FORMAT_RGTC_R; - squish_comp |= squish::kBc4; - } break; - case Image::USED_CHANNELS_RG: { - target_format = Image::FORMAT_RGTC_RG; - squish_comp |= squish::kBc5; - } break; - case Image::USED_CHANNELS_RGB: { - target_format = Image::FORMAT_DXT1; - squish_comp |= squish::kDxt1; - } break; - case Image::USED_CHANNELS_RGBA: { - //TODO, should convert both, then measure which one does a better job - target_format = Image::FORMAT_DXT5; - squish_comp |= squish::kDxt5; - - } break; - default: { - ERR_PRINT("Unknown image format, defaulting to RGBA8"); - break; - } - } - - Vector<uint8_t> data; - int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); - int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0; - data.resize(target_size); - int shift = Image::get_format_pixel_rshift(target_format); - - const uint8_t *rb = p_image->get_data().ptr(); - uint8_t *wb = data.ptrw(); - - int dst_ofs = 0; - - for (int i = 0; i <= mm_count; i++) { - int bw = w % 4 != 0 ? w + (4 - w % 4) : w; - int bh = h % 4 != 0 ? h + (4 - h % 4) : h; - - int src_ofs = p_image->get_mipmap_offset(i); - squish::CompressImage(&rb[src_ofs], w, h, &wb[dst_ofs], squish_comp); - dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift; - w = MAX(w / 2, 1); - h = MAX(h / 2, 1); - } - - p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); - } -} diff --git a/modules/etc/image_compress_etc.h b/modules/squish/image_decompress_squish.h index 44a06194e9..fff5839ac4 100644 --- a/modules/etc/image_compress_etc.h +++ b/modules/squish/image_decompress_squish.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_compress_etc.h */ +/* image_decompress_squish.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IMAGE_COMPRESS_ETC_H -#define IMAGE_COMPRESS_ETC_H +#ifndef IMAGE_DECOMPRESS_SQUISH_H +#define IMAGE_DECOMPRESS_SQUISH_H -void _register_etc_compress_func(); +#include "core/io/image.h" -#endif // IMAGE_COMPRESS_ETC_H +void image_decompress_squish(Image *p_image); + +#endif // IMAGE_DECOMPRESS_SQUISH_H diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp index 451e9d8e93..51aab040e7 100644 --- a/modules/squish/register_types.cpp +++ b/modules/squish/register_types.cpp @@ -29,10 +29,10 @@ /*************************************************************************/ #include "register_types.h" -#include "image_compress_squish.h" + +#include "image_decompress_squish.h" void register_squish_types() { - Image::set_compress_bc_func(image_compress_squish); Image::_image_decompress_bc = image_decompress_squish; } diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index 6732078efc..768b419348 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -30,7 +30,7 @@ #include "audio_stream_ogg_vorbis.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) { ERR_FAIL_COND(!active); @@ -129,7 +129,7 @@ Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { "to it. AudioStreamOGGVorbis should not be created from the " "inspector or with `.new()`. Instead, load an audio file."); - ovs.instance(); + ovs.instantiate(); ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this); ovs->ogg_alloc.alloc_buffer = (char *)memalloc(decode_mem_size); ovs->ogg_alloc.alloc_buffer_length_in_bytes = decode_mem_size; @@ -204,7 +204,7 @@ void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) { clear_data(); data = memalloc(src_data_len); - copymem(data, src_datar, src_data_len); + memcpy(data, src_datar, src_data_len); data_len = src_data_len; break; @@ -221,7 +221,7 @@ Vector<uint8_t> AudioStreamOGGVorbis::get_data() const { vdata.resize(data_len); { uint8_t *w = vdata.ptrw(); - copymem(w, data, data_len); + memcpy(w, data, data_len); } } diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml index 8a1bb62e24..94fdff5d43 100644 --- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()"> Contains the audio data in bytes. </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> diff --git a/modules/stb_vorbis/register_types.cpp b/modules/stb_vorbis/register_types.cpp index 6f7eb53bc8..bdb1cf69cf 100644 --- a/modules/stb_vorbis/register_types.cpp +++ b/modules/stb_vorbis/register_types.cpp @@ -41,11 +41,11 @@ void register_stb_vorbis_types() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { Ref<ResourceImporterOGGVorbis> ogg_import; - ogg_import.instance(); + ogg_import.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(ogg_import); } #endif - ClassDB::register_class<AudioStreamOGGVorbis>(); + GDREGISTER_CLASS(AudioStreamOGGVorbis); } void unregister_stb_vorbis_types() { diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp index ec1c30783a..85de698efd 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp @@ -30,8 +30,8 @@ #include "resource_importer_ogg_vorbis.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "scene/resources/texture.h" String ResourceImporterOGGVorbis::get_importer_name() const { @@ -79,7 +79,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); - size_t len = f->get_len(); + uint64_t len = f->get_length(); Vector<uint8_t> data; data.resize(len); @@ -90,7 +90,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin memdelete(f); Ref<AudioStreamOGGVorbis> ogg_stream; - ogg_stream.instance(); + ogg_stream.instantiate(); ogg_stream->set_data(data); ERR_FAIL_COND_V(!ogg_stream->get_data().size(), ERR_FILE_CORRUPT); diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 6ce3e4b4b3..4911346b96 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -140,7 +140,7 @@ Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, const char *p } Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - uint32_t size = f->get_len(); + uint64_t size = f->get_length(); Vector<uint8_t> src_image; src_image.resize(size + 1); uint8_t *src_w = src_image.ptrw(); diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index e7863f88a3..d06c5c2f14 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -131,7 +131,7 @@ if env["builtin_harfbuzz"]: ] ) - if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server": + if env["platform"] == "android" or env["platform"] == "linuxbsd": env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"]) if env["platform"] == "javascript": @@ -448,7 +448,7 @@ if env["builtin_icu"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - icu_data_name = "icudt68l.dat" + icu_data_name = "icudt69l.dat" if env_icu["tools"]: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp index 2521e68dda..62eedebb59 100644 --- a/modules/text_server_adv/dynamic_font_adv.cpp +++ b/modules/text_server_adv/dynamic_font_adv.cpp @@ -66,7 +66,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); } - size_t len = f->get_len(); + uint64_t len = f->get_length(); font_mem_cache.resize(len); f->get_buffer(font_mem_cache.ptrw(), len); font_mem = font_mem_cache.ptr(); @@ -231,7 +231,7 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const { Dictionary out; // Read feature flags. - unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL); + unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr); if (count != 0) { hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t)); hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, feature_tags); @@ -240,7 +240,7 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const { } memfree(feature_tags); } - count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL); + count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr); if (count != 0) { hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t)); hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, feature_tags); @@ -420,7 +420,7 @@ DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::bitmap_to_character( Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata)); if (tex.texture.is_null()) { - tex.texture.instance(); + tex.texture.instantiate(); tex.texture->create_from_image(img); } else { tex.texture->update(img); //update @@ -639,7 +639,7 @@ bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const { DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size); ERR_FAIL_COND_V(fds == nullptr, false); - unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL); + unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr); if (count != 0) { hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t)); hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, script_tags); @@ -651,7 +651,7 @@ bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const { } memfree(script_tags); } - count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL); + count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr); if (count != 0) { hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t)); hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, script_tags); @@ -997,6 +997,29 @@ Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, in return advance; } +bool DynamicFontDataAdvanced::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { + _THREAD_SAFE_METHOD_ + DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size); + ERR_FAIL_COND_V(fds == nullptr, false); + + int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + ERR_FAIL_COND_V(error, false); + + r_points.clear(); + r_contours.clear(); + + float h = fds->ascent; + float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font; + for (short i = 0; i < fds->face->glyph->outline.n_points; i++) { + r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i]))); + } + for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) { + r_contours.push_back(fds->face->glyph->outline.contours[i]); + } + r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); + return true; +} + DynamicFontDataAdvanced::~DynamicFontDataAdvanced() { clear_cache(); if (library != nullptr) { diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h index d69a30b321..b3f97bb029 100644 --- a/modules/text_server_adv/dynamic_font_adv.h +++ b/modules/text_server_adv/dynamic_font_adv.h @@ -34,7 +34,6 @@ #include "font_adv.h" #include "modules/modules_enabled.gen.h" - #ifdef MODULE_FREETYPE_ENABLED #include <ft2build.h> @@ -186,6 +185,8 @@ public: virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override; virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override; + virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override; + virtual ~DynamicFontDataAdvanced() override; }; diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h index 2b6d977451..4fadefc569 100644 --- a/modules/text_server_adv/font_adv.h +++ b/modules/text_server_adv/font_adv.h @@ -92,8 +92,8 @@ struct FontDataAdvanced { virtual bool has_outline() const = 0; virtual float get_base_size() const = 0; - virtual bool is_lang_supported(const String &p_lang) const { return false; }; - virtual bool is_script_supported(uint32_t p_script) const { return false; }; + virtual bool is_lang_supported(const String &p_lang) const { return true; }; + virtual bool is_script_supported(uint32_t p_script) const { return true; }; virtual bool has_char(char32_t p_char) const = 0; virtual String get_supported_chars() const = 0; @@ -107,6 +107,8 @@ struct FontDataAdvanced { virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0; virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0; + virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; }; + virtual ~FontDataAdvanced(){}; }; diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index 8f23bb9e02..f9bbd25a5f 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -75,10 +75,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) { paren_sp -= 1; } - if (paren_sp < start_sp) + if (paren_sp < start_sp) { start_sp = paren_sp; - if (paren_sp >= 0) + } + if (paren_sp >= 0) { sc = paren_stack[paren_sp].script_code; + } } } diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 43b8f18101..2513039e8e 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -129,6 +129,10 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) { return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029); } +_FORCE_INLINE_ bool is_underscore(char32_t p_char) { + return (p_char == 0x005F); +} + /*************************************************************************/ String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite"; @@ -181,7 +185,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { UErrorCode err = U_ZERO_ERROR; // ICU data found. - size_t len = f->get_len(); + uint64_t len = f->get_length(); icu_data = (uint8_t *)memalloc(len); f->get_buffer(icu_data, len); f->close(); @@ -906,6 +910,13 @@ Vector2 TextServerAdvanced::font_draw_glyph_outline(RID p_font, RID p_canvas, in return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color); } +bool TextServerAdvanced::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { + _THREAD_SAFE_METHOD_ + const FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND_V(!fd, false); + return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation); +} + float TextServerAdvanced::font_get_oversampling() const { return oversampling; } @@ -1651,6 +1662,161 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float return 0.f; } +void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) { + _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped_line); + ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); + if (!sd->valid) { + shaped_text_shape(p_shaped_line); + } + + bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; + bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY; + bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS; + + Glyph *sd_glyphs = sd->glyphs.ptrw(); + + if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { + return; + } + + int sd_size = sd->glyphs.size(); + RID last_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; + uint32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, '.'); + Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, dot_gl_idx, last_gl_font_size); + uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' '); + Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size); + + int ellipsis_advance = 0; + if (add_ellipsis) { + ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0); + } + + int ell_min_characters = 6; + float width = sd->width; + + bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL); + + int trim_pos = (is_rtl) ? sd_size : 0; + int ellipsis_pos = (enforce_ellipsis) ? 0 : -1; + + int last_valid_cut = 0; + bool found = false; + + int glyphs_from = (is_rtl) ? 0 : sd_size - 1; + int glyphs_to = (is_rtl) ? sd_size - 1 : -1; + int glyphs_delta = (is_rtl) ? +1 : -1; + + for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) { + if (!is_rtl) { + width -= sd_glyphs[i].advance; + } + if (sd_glyphs[i].count > 0) { + bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; + + if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) { + if (cut_per_word && above_min_char_treshold) { + if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + last_valid_cut = i; + found = true; + } + } else { + last_valid_cut = i; + found = true; + } + if (found) { + trim_pos = last_valid_cut; + + if (above_min_char_treshold && width - ellipsis_advance <= p_width) { + ellipsis_pos = trim_pos; + } + break; + } + } + } + if (is_rtl) { + width -= sd_glyphs[i].advance; + } + } + + if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) { + int added_glyphs = 0; + if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) { + // Insert an additional space when cutting word bound for aesthetics. + if (cut_per_word && (ellipsis_pos > 0)) { + TextServer::Glyph gl; + gl.start = sd_glyphs[ellipsis_pos].start; + gl.end = sd_glyphs[ellipsis_pos].end; + gl.count = 1; + gl.advance = whitespace_adv.x; + gl.index = whitespace_gl_idx; + gl.font_rid = last_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + + // Optimized glyph insertion by replacing a glyph whenever possible. + int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs); + if (is_rtl) { + if (glyph_idx < 0) { + sd->glyphs.insert(0, gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } else { + if (glyph_idx > (sd_size - 1)) { + sd->glyphs.append(gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } + added_glyphs++; + } + // Add ellipsis dots. + for (int d = 0; d < 3; d++) { + TextServer::Glyph gl; + gl.start = sd_glyphs[ellipsis_pos].start; + gl.end = sd_glyphs[ellipsis_pos].end; + gl.count = 1; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = last_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + + // Optimized glyph insertion by replacing a glyph whenever possible. + int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs); + if (is_rtl) { + if (glyph_idx < 0) { + sd->glyphs.insert(0, gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } else { + if (glyph_idx > (sd_size - 1)) { + sd->glyphs.append(gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } + added_glyphs++; + } + } + + // Cut the remaining glyphs off. + if (!is_rtl) { + sd->glyphs.resize(trim_pos + added_glyphs); + } else { + if (trim_pos - added_glyphs >= 0) { + sd->glyphs = sd->glyphs.subarray(trim_pos - added_glyphs, sd->glyphs.size() - 1); + } + } + + // Update to correct width. + sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0); + } +} + bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); @@ -1721,7 +1887,10 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_whitespace(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } - if (u_ispunct(c)) { + if (is_underscore(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; + } + if (u_ispunct(c) && c != 0x005F) { sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; } if (breaks.has(sd->glyphs[i].start)) { @@ -1825,8 +1994,9 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d } } } - if (!is_transparent(c)) + if (!is_transparent(c)) { pc = c; + } i++; } @@ -2344,24 +2514,22 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { sd->glyphs.push_back(gl); } else { Vector<RID> fonts; - // Push fonts with the language and script support first. - for (int l = 0; l < span.fonts.size(); l++) { - if ((font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) { - fonts.push_back(sd->spans[k].fonts[l]); - } - } - // Push fonts with the script support. - for (int l = 0; l < sd->spans[k].fonts.size(); l++) { - if (!(font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) { - fonts.push_back(sd->spans[k].fonts[l]); - } - } - // Push the rest valid fonts. - for (int l = 0; l < sd->spans[k].fonts.size(); l++) { - if (!(font_is_language_supported(span.fonts[l], span.language)) && !(font_is_script_supported(span.fonts[l], script))) { - fonts.push_back(sd->spans[k].fonts[l]); + Vector<RID> fonts_scr_only; + Vector<RID> fonts_no_match; + int font_count = span.fonts.size(); + for (int l = 0; l < font_count; l++) { + if (font_is_script_supported(span.fonts[l], script)) { + if (font_is_language_supported(span.fonts[l], span.language)) { + fonts.push_back(sd->spans[k].fonts[l]); + } else { + fonts_scr_only.push_back(sd->spans[k].fonts[l]); + } + } else { + fonts_no_match.push_back(sd->spans[k].fonts[l]); } } + fonts.append_array(fonts_scr_only); + fonts.append_array(fonts_no_match); _shape_run(sd, MAX(sd->spans[k].start, script_run_start), MIN(sd->spans[k].end, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0); } } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index b53b5716e5..3c4f840bfd 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -188,6 +188,8 @@ public: virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override; + virtual float font_get_oversampling() const override; virtual void font_set_oversampling(float p_oversampling) override; @@ -227,6 +229,8 @@ public: virtual bool shaped_text_update_breaks(RID p_shaped) override; virtual bool shaped_text_update_justification_ops(RID p_shaped) override; + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override; + virtual bool shaped_text_is_ready(RID p_shaped) const override; virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override; diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index 66d36bc885..7e77987074 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -65,7 +65,7 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); } - size_t len = f->get_len(); + uint64_t len = f->get_length(); font_mem_cache.resize(len); f->get_buffer(font_mem_cache.ptrw(), len); font_mem = font_mem_cache.ptr(); @@ -306,7 +306,7 @@ DynamicFontDataFallback::Character DynamicFontDataFallback::bitmap_to_character( Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata)); if (tex.texture.is_null()) { - tex.texture.instance(); + tex.texture.instantiate(); tex.texture->create_from_image(img); } else { tex.texture->update(img); //update @@ -680,6 +680,29 @@ Vector2 DynamicFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, in return advance; } +bool DynamicFontDataFallback::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { + _THREAD_SAFE_METHOD_ + DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size); + ERR_FAIL_COND_V(fds == nullptr, false); + + int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + ERR_FAIL_COND_V(error, false); + + r_points.clear(); + r_contours.clear(); + + float h = fds->ascent; + float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font; + for (short i = 0; i < fds->face->glyph->outline.n_points; i++) { + r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i]))); + } + for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) { + r_contours.push_back(fds->face->glyph->outline.contours[i]); + } + r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); + return true; +} + DynamicFontDataFallback::~DynamicFontDataFallback() { clear_cache(); if (library != nullptr) { diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h index eb70f46666..82e59fa607 100644 --- a/modules/text_server_fb/dynamic_font_fb.h +++ b/modules/text_server_fb/dynamic_font_fb.h @@ -34,7 +34,6 @@ #include "font_fb.h" #include "modules/modules_enabled.gen.h" - #ifdef MODULE_FREETYPE_ENABLED #include <ft2build.h> @@ -164,6 +163,8 @@ public: virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override; virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override; + virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override; + virtual ~DynamicFontDataFallback() override; }; diff --git a/modules/text_server_fb/font_fb.h b/modules/text_server_fb/font_fb.h index 218f3df03a..fe9888b7f4 100644 --- a/modules/text_server_fb/font_fb.h +++ b/modules/text_server_fb/font_fb.h @@ -93,6 +93,8 @@ struct FontDataFallback { virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0; virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0; + virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; }; + virtual ~FontDataFallback(){}; }; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index f46f96d30d..9ad7dabbcc 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -46,7 +46,11 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) { } _FORCE_INLINE_ bool is_punct(char32_t p_char) { - return (p_char >= 0x0020 && p_char <= 0x002F) || (p_char >= 0x003A && p_char <= 0x0040) || (p_char >= 0x005B && p_char <= 0x0060) || (p_char >= 0x007B && p_char <= 0x007E) || (p_char >= 0x2000 && p_char <= 0x206F) || (p_char >= 0x3000 && p_char <= 0x303F); + return (p_char >= 0x0020 && p_char <= 0x002F) || (p_char >= 0x003A && p_char <= 0x0040) || (p_char >= 0x005B && p_char <= 0x005E) || (p_char == 0x0060) || (p_char >= 0x007B && p_char <= 0x007E) || (p_char >= 0x2000 && p_char <= 0x206F) || (p_char >= 0x3000 && p_char <= 0x303F); +} + +_FORCE_INLINE_ bool is_underscore(char32_t p_char) { + return (p_char == 0x005F); } /*************************************************************************/ @@ -452,6 +456,13 @@ Vector2 TextServerFallback::font_draw_glyph_outline(RID p_font, RID p_canvas, in return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color); } +bool TextServerFallback::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { + _THREAD_SAFE_METHOD_ + const FontDataFallback *fd = font_owner.getornull(p_font); + ERR_FAIL_COND_V(!fd, false); + return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation); +} + float TextServerFallback::font_get_oversampling() const { return oversampling; } @@ -627,17 +638,17 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te span.start = sd->text.length(); span.end = span.start + p_text.length(); // Pre-sort fonts, push fonts with the language support first. - for (int i = 0; i < p_fonts.size(); i++) { + Vector<RID> fonts_no_match; + int font_count = p_fonts.size(); + for (int i = 0; i < font_count; i++) { if (font_is_language_supported(p_fonts[i], p_language)) { span.fonts.push_back(p_fonts[i]); + } else { + fonts_no_match.push_back(p_fonts[i]); } } - // Push the rest valid fonts. - for (int i = 0; i < p_fonts.size(); i++) { - if (!font_is_language_supported(p_fonts[i], p_language)) { - span.fonts.push_back(p_fonts[i]); - } - } + span.fonts.append_array(fonts_no_match); + ERR_FAIL_COND_V(span.fonts.is_empty(), false); span.font_size = p_size; span.language = p_language; @@ -1101,6 +1112,9 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { if (is_punct(c)) { sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION; } + if (is_underscore(c)) { + sd->glyphs.write[i].flags |= GRAPHEME_IS_UNDERSCORE; + } if (is_whitespace(c) && !is_linebreak(c)) { sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE; sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT; @@ -1134,6 +1148,161 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) { return true; } +void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) { + _THREAD_SAFE_METHOD_ + ShapedTextData *sd = shaped_owner.getornull(p_shaped_line); + ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); + if (!sd->valid) { + shaped_text_shape(p_shaped_line); + } + + bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; + bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY; + bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS; + + Glyph *sd_glyphs = sd->glyphs.ptrw(); + + if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { + return; + } + + int sd_size = sd->glyphs.size(); + RID last_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; + uint32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, '.'); + Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, dot_gl_idx, last_gl_font_size); + uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' '); + Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size); + + int ellipsis_advance = 0; + if (add_ellipsis) { + ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0); + } + + int ell_min_characters = 6; + float width = sd->width; + + bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL); + + int trim_pos = (is_rtl) ? sd_size : 0; + int ellipsis_pos = (enforce_ellipsis) ? 0 : -1; + + int last_valid_cut = 0; + bool found = false; + + int glyphs_from = (is_rtl) ? 0 : sd_size - 1; + int glyphs_to = (is_rtl) ? sd_size - 1 : -1; + int glyphs_delta = (is_rtl) ? +1 : -1; + + for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) { + if (!is_rtl) { + width -= sd_glyphs[i].advance; + } + if (sd_glyphs[i].count > 0) { + bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; + + if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) { + if (cut_per_word && above_min_char_treshold) { + if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + last_valid_cut = i; + found = true; + } + } else { + last_valid_cut = i; + found = true; + } + if (found) { + trim_pos = last_valid_cut; + + if (above_min_char_treshold && width - ellipsis_advance <= p_width) { + ellipsis_pos = trim_pos; + } + break; + } + } + } + if (is_rtl) { + width -= sd_glyphs[i].advance; + } + } + + if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) { + int added_glyphs = 0; + if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) { + // Insert an additional space when cutting word bound for aesthetics. + if (cut_per_word && (ellipsis_pos > 0)) { + TextServer::Glyph gl; + gl.start = sd_glyphs[ellipsis_pos].start; + gl.end = sd_glyphs[ellipsis_pos].end; + gl.count = 1; + gl.advance = whitespace_adv.x; + gl.index = whitespace_gl_idx; + gl.font_rid = last_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + + // Optimized glyph insertion by replacing a glyph whenever possible. + int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs); + if (is_rtl) { + if (glyph_idx < 0) { + sd->glyphs.insert(0, gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } else { + if (glyph_idx > (sd_size - 1)) { + sd->glyphs.append(gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } + added_glyphs++; + } + // Add ellipsis dots. + for (int d = 0; d < 3; d++) { + TextServer::Glyph gl; + gl.start = sd_glyphs[ellipsis_pos].start; + gl.end = sd_glyphs[ellipsis_pos].end; + gl.count = 1; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = last_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + + // Optimized glyph insertion by replacing a glyph whenever possible. + int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs); + if (is_rtl) { + if (glyph_idx < 0) { + sd->glyphs.insert(0, gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } else { + if (glyph_idx > (sd_size - 1)) { + sd->glyphs.append(gl); + } else { + sd->glyphs.set(glyph_idx, gl); + } + } + added_glyphs++; + } + } + + // Cut the remaining glyphs off. + if (!is_rtl) { + sd->glyphs.resize(trim_pos + added_glyphs); + } else { + for (int ridx = 0; ridx <= trim_pos - added_glyphs; ridx++) { + sd->glyphs.remove(0); + } + } + + // Update to correct width. + sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0); + } +} + bool TextServerFallback::shaped_text_shape(RID p_shaped) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.getornull(p_shaped); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index b10369d172..b70c8f4ec0 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -137,6 +137,8 @@ public: virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override; + virtual float font_get_oversampling() const override; virtual void font_set_oversampling(float p_oversampling) override; @@ -176,6 +178,8 @@ public: virtual bool shaped_text_update_breaks(RID p_shaped) override; virtual bool shaped_text_update_justification_ops(RID p_shaped) override; + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override; + virtual bool shaped_text_is_ready(RID p_shaped) const override; virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override; diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index ef53661557..f0d7c335bd 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -35,7 +35,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size) { +Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size, size_t p_input_size) { Error error; Vector<uint8_t> pixels; @@ -56,11 +56,14 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t compressed_pos += 1; count = (c & 0x7f) + 1; - if (output_pos + count * p_pixel_size > output_pos) { + if (output_pos + count * p_pixel_size > p_output_size) { return ERR_PARSE_ERROR; } if (c & 0x80) { + if (compressed_pos + p_pixel_size > p_input_size) { + return ERR_PARSE_ERROR; + } for (size_t i = 0; i < p_pixel_size; i++) { pixels_w[i] = p_compressed_buffer[compressed_pos]; compressed_pos += 1; @@ -72,6 +75,9 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t output_pos += p_pixel_size; } } else { + if (compressed_pos + count * p_pixel_size > p_input_size) { + return ERR_PARSE_ERROR; + } count *= p_pixel_size; for (size_t i = 0; i < count; i++) { p_uncompressed_buffer[output_pos] = p_compressed_buffer[compressed_pos]; @@ -83,7 +89,7 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t return OK; } -Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_output_size) { +Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size) { #define TGA_PUT_PIXEL(r, g, b, a) \ int image_data_ofs = ((y * width) + x); \ image_data_w[image_data_ofs * 4 + 0] = r; \ @@ -134,7 +140,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff if (p_is_monochrome) { while (y != y_end) { while (x != x_end) { - if (i > p_output_size) { + if (i >= p_input_size) { return ERR_PARSE_ERROR; } uint8_t shade = p_buffer[i]; @@ -150,7 +156,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } else { while (y != y_end) { while (x != x_end) { - if (i > p_output_size) { + if (i >= p_input_size) { return ERR_PARSE_ERROR; } uint8_t index = p_buffer[i]; @@ -181,7 +187,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } else if (p_header.pixel_depth == 24) { while (y != y_end) { while (x != x_end) { - if (i + 2 > p_output_size) { + if (i + 2 >= p_input_size) { return ERR_PARSE_ERROR; } @@ -200,7 +206,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } else if (p_header.pixel_depth == 32) { while (y != y_end) { while (x != x_end) { - if (i + 3 > p_output_size) { + if (i + 3 >= p_input_size) { return ERR_PARSE_ERROR; } @@ -226,9 +232,9 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; - int src_image_len = f->get_len(); + uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); - ERR_FAIL_COND_V(src_image_len < (int)sizeof(tga_header_s), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(src_image_len < (int64_t)sizeof(tga_header_s), ERR_FILE_CORRUPT); src_image.resize(src_image_len); Error err = OK; @@ -307,7 +313,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force const uint8_t *buffer = nullptr; if (is_encoded) { - err = decode_tga_rle(src_image_r, pixel_size, uncompressed_buffer_w, buffer_size); + err = decode_tga_rle(src_image_r, pixel_size, uncompressed_buffer_w, buffer_size, src_image_len); if (err == OK) { uncompressed_buffer_r = uncompressed_buffer.ptr(); @@ -337,7 +343,7 @@ static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) { Error open_memfile_error = memfile.open_custom(p_tga, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer."); Ref<Image> img; - img.instance(); + img.instantiate(); Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load TGA image."); return img; diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index cb2ce07edd..e4463a322f 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -72,8 +72,8 @@ class ImageLoaderTGA : public ImageFormatLoader { uint8_t pixel_depth = 0; uint8_t image_descriptor = 0; }; - static Error decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size); - static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_output_size); + static Error decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size, size_t p_input_size); + static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size); public: virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp index 0218b8c7a4..55148a6b87 100644 --- a/modules/theora/register_types.cpp +++ b/modules/theora/register_types.cpp @@ -35,10 +35,10 @@ static Ref<ResourceFormatLoaderTheora> resource_loader_theora; void register_theora_types() { - resource_loader_theora.instance(); + resource_loader_theora.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_theora, true); - ClassDB::register_class<VideoStreamTheora>(); + GDREGISTER_CLASS(VideoStreamTheora); } void unregister_theora_types() { diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index c5f6dc0d99..2f6faec8ec 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -58,7 +58,7 @@ int VideoStreamPlaybackTheora::buffer_data() { #else - int bytes = file->get_buffer((uint8_t *)buffer, 4096); + uint64_t bytes = file->get_buffer((uint8_t *)buffer, 4096); ogg_sync_wrote(&oy, bytes); return (bytes); @@ -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, true); //zero copy send to visual server + texture->update(img); //zero copy send to visual server frames_pending = 1; } @@ -176,7 +176,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { thread_eof = false; //pre-fill buffer int to_read = ring_buffer.space_left(); - int read = file->get_buffer(read_buffer.ptr(), to_read); + uint64_t read = file->get_buffer(read_buffer.ptr(), to_read); ring_buffer.write(read_buffer.ptr(), read); thread.start(_streaming_thread, this); @@ -225,7 +225,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { /* identify the codec: try theora */ if (!theora_p && th_decode_headerin(&ti, &tc, &ts, &op) >= 0) { /* it is theora */ - copymem(&to, &test, sizeof(test)); + memcpy(&to, &test, sizeof(test)); theora_p = 1; } else if (!vorbis_p && vorbis_synthesis_headerin(&vi, &vc, &op) >= 0) { /* it is vorbis */ @@ -238,7 +238,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { audio_track_skip--; } else { - copymem(&vo, &test, sizeof(test)); + memcpy(&vo, &test, sizeof(test)); vorbis_p = 1; } } else { @@ -302,7 +302,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { } } - /* and now we have it all. initialize decoders */ + /* And now we have it all. Initialize decoders. */ if (theora_p) { td = th_decode_alloc(&ti, ts); px_fmt = ti.pixel_fmt; @@ -335,7 +335,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { size.y = h; Ref<Image> img; - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8); } else { @@ -484,10 +484,10 @@ void VideoStreamPlaybackTheora::update(float p_delta) { //printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); - /* is it already too old to be useful? This is only actually - useful cosmetically after a SIGSTOP. Note that we have to + /* is it already too old to be useful? This is only actually + useful cosmetically after a SIGSTOP. Note that we have to decode the frame even if we don't show it (for now) due to - keyframing. Soon enough libtheora will be able to deal + keyframing. Soon enough libtheora will be able to deal with non-keyframe seeks. */ if (videobuf_time >= get_time()) { @@ -603,6 +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)."); } void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) { @@ -631,8 +632,8 @@ void VideoStreamPlaybackTheora::_streaming_thread(void *ud) { //just fill back the buffer if (!vs->thread_eof) { int to_read = vs->ring_buffer.space_left(); - if (to_read) { - int read = vs->file->get_buffer(vs->read_buffer.ptr(), to_read); + if (to_read > 0) { + uint64_t read = vs->file->get_buffer(vs->read_buffer.ptr(), to_read); vs->ring_buffer.write(vs->read_buffer.ptr(), read); vs->thread_eof = vs->file->eof_reached(); } diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 2685a8a013..760173d0df 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -31,8 +31,8 @@ #ifndef VIDEO_STREAM_THEORA_H #define VIDEO_STREAM_THEORA_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/os/semaphore.h" #include "core/os/thread.h" #include "core/templates/ring_buffer.h" diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 47214e6974..eb7a8597e6 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -37,7 +37,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; - int src_image_len = f->get_len(); + uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); src_image.resize(src_image_len); diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp index f747763248..6a2fb0f666 100644 --- a/modules/tinyexr/image_saver_tinyexr.cpp +++ b/modules/tinyexr/image_saver_tinyexr.cpp @@ -169,7 +169,7 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) { 0 }, // R { 1, 0 }, // GR { 2, 1, 0 }, // BGR - { 2, 1, 0, 3 } // BGRA + { 3, 2, 1, 0 } // ABGR }; int channel_count = get_channel_count(format); diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml index 785c8dad50..09a2c8a88c 100644 --- a/modules/upnp/doc_classes/UPNP.xml +++ b/modules/upnp/doc_classes/UPNP.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UPNP" inherits="Reference" version="4.0"> +<class name="UPNP" inherits="RefCounted" version="4.0"> <brief_description> UPNP network functions. </brief_description> diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index f3b96bb89d..f7b5386d86 100644 --- a/modules/upnp/doc_classes/UPNPDevice.xml +++ b/modules/upnp/doc_classes/UPNPDevice.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UPNPDevice" inherits="Reference" version="4.0"> +<class name="UPNPDevice" inherits="RefCounted" version="4.0"> <brief_description> UPNP device. </brief_description> diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp index a5ee39517f..1e5edd3602 100644 --- a/modules/upnp/register_types.cpp +++ b/modules/upnp/register_types.cpp @@ -36,8 +36,8 @@ #include "upnp_device.h" void register_upnp_types() { - ClassDB::register_class<UPNP>(); - ClassDB::register_class<UPNPDevice>(); + GDREGISTER_CLASS(UPNP); + GDREGISTER_CLASS(UPNPDevice); } void unregister_upnp_types() { diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 8e4e833d45..efe618012a 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -92,7 +92,7 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) { void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { Ref<UPNPDevice> new_device; - new_device.instance(); + new_device.instantiate(); new_device->set_description_url(dev->descURL); new_device->set_service_type(dev->st); diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h index a0cca96bc8..b961a9667f 100644 --- a/modules/upnp/upnp.h +++ b/modules/upnp/upnp.h @@ -31,14 +31,14 @@ #ifndef GODOT_UPNP_H #define GODOT_UPNP_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "upnp_device.h" #include <miniupnpc/miniupnpc.h> -class UPNP : public Reference { - GDCLASS(UPNP, Reference); +class UPNP : public RefCounted { + GDCLASS(UPNP, RefCounted); private: String discover_multicast_if = ""; diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h index 126e761a56..0a66c36ab9 100644 --- a/modules/upnp/upnp_device.h +++ b/modules/upnp/upnp_device.h @@ -31,10 +31,10 @@ #ifndef GODOT_UPNP_DEVICE_H #define GODOT_UPNP_DEVICE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class UPNPDevice : public Reference { - GDCLASS(UPNPDevice, Reference); +class UPNPDevice : public RefCounted { + GDCLASS(UPNPDevice, RefCounted); public: enum IGDStatus { diff --git a/modules/vhacd/config.py b/modules/vhacd/config.py index d22f9454ed..a42f27fbe1 100644 --- a/modules/vhacd/config.py +++ b/modules/vhacd/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp index daad39bdfb..3d7aaee921 100644 --- a/modules/vhacd/register_types.cpp +++ b/modules/vhacd/register_types.cpp @@ -32,7 +32,7 @@ #include "scene/resources/mesh.h" #include "thirdparty/vhacd/public/VHACD.h" -static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces) { +static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int p_max_convex_hulls = -1) { Vector<float> vertices; vertices.resize(p_faces.size() * 9); Vector<uint32_t> indices; @@ -47,8 +47,12 @@ static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces) { } } - VHACD::IVHACD *decomposer = VHACD::CreateVHACD(); VHACD::IVHACD::Parameters params; + if (p_max_convex_hulls > 0) { + params.m_maxConvexHulls = p_max_convex_hulls; + } + + VHACD::IVHACD *decomposer = VHACD::CreateVHACD(); decomposer->Compute(vertices.ptr(), vertices.size() / 3, indices.ptr(), indices.size() / 3, params); int hull_count = decomposer->GetNConvexHulls(); diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml index 5112ea43a7..9d51bd86a2 100644 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ b/modules/visual_script/doc_classes/VisualScript.xml @@ -4,7 +4,7 @@ A script implemented in the Visual Script programming environment. </brief_description> <description> - A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it. + A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes. You are most likely to use this class via the Visual Script editor or when writing plugins for it. </description> @@ -39,7 +39,7 @@ </argument> <argument index="1" name="node" type="VisualScriptNode"> </argument> - <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Add a node to the VisualScript. diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml index de5d731cc0..d6b96957f5 100644 --- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml @@ -15,10 +15,10 @@ <methods> </methods> <members> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> The constant's parent class. </member> - <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="@"""> + <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="&"""> The constant to return. See the given class for its available constants. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml index 243338ea52..02cec97b27 100644 --- a/modules/visual_script/doc_classes/VisualScriptComment.xml +++ b/modules/visual_script/doc_classes/VisualScriptComment.xml @@ -15,7 +15,7 @@ <member name="description" type="String" setter="set_description" getter="get_description" default=""""> The text inside the comment node. </member> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 150, 150 )"> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(150, 150)"> The comment node's size (in pixels). </member> <member name="title" type="String" setter="set_title" getter="get_title" default=""Comment""> diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml index 5c9c8d3eca..df3121d093 100644 --- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml @@ -15,7 +15,7 @@ <methods> </methods> <members> - <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="@"""> + <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&"""> The signal to emit. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml index 5253f7bc7d..223adbbb96 100644 --- a/modules/visual_script/doc_classes/VisualScriptExpression.xml +++ b/modules/visual_script/doc_classes/VisualScriptExpression.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptExpression" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node that can execute a custom expression. </brief_description> <description> + A Visual Script node that can execute a custom expression. Values can be provided for the input and the expression result can be retrieved from the output. </description> <tutorials> </tutorials> diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml index 873d26a5be..652418bd64 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunction.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunction.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptFunction" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node representing a function. </brief_description> <description> + [VisualScriptFunction] represents a function header. It is the starting point for the function body and can be used to tweak the function's properties (e.g. RPC mode). </description> <tutorials> </tutorials> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml index 2d0fac1fa0..f0b666e57a 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptFunctionCall" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node for calling a function. </brief_description> <description> + [VisualScriptFunctionCall] is created when you add or drag and drop a function onto the Visual Script graph. It allows to tweak parameters of the call, e.g. what object the function is called on. </description> <tutorials> </tutorials> @@ -10,46 +12,66 @@ </methods> <members> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> + The script to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE]. </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> + The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE]. </member> <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> + The type to be used when [member call_mode] is set to [constant CALL_MODE_BASIC_TYPE]. </member> <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode" default="0"> + [code]call_mode[/code] determines the target object on which the method will be called. See [enum CallMode] for options. </member> - <member name="function" type="StringName" setter="set_function" getter="get_function" default="@"""> + <member name="function" type="StringName" setter="set_function" getter="get_function" default="&"""> + The name of the function to be called. </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> + The node path to use when [member call_mode] is set to [constant CALL_MODE_NODE_PATH]. </member> <member name="rpc_call_mode" type="int" setter="set_rpc_call_mode" getter="get_rpc_call_mode" enum="VisualScriptFunctionCall.RPCCallMode" default="0"> + The mode for RPC calls. See [method Node.rpc] for more details and [enum RPCCallMode] for available options. </member> <member name="singleton" type="StringName" setter="set_singleton" getter="get_singleton"> + The singleton to call the method on. Used when [member call_mode] is set to [constant CALL_MODE_SINGLETON]. </member> <member name="use_default_args" type="int" setter="set_use_default_args" getter="get_use_default_args"> + Number of default arguments that will be used when calling the function. Can't be higher than the number of available default arguments in the method's declaration. </member> <member name="validate" type="bool" setter="set_validate" getter="get_validate" default="true"> + If [code]false[/code], call errors (e.g. wrong number of arguments) will be ignored. </member> </members> <constants> <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> + The method will be called on this [Object]. </constant> <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> + The method will be called on the given [Node] in the scene tree. </constant> <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> + The method will be called on an instanced node with the given type and script. </constant> <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode"> + The method will be called on a GDScript basic type (e.g. [Vector2]). </constant> <constant name="CALL_MODE_SINGLETON" value="4" enum="CallMode"> + The method will be called on a singleton. </constant> <constant name="RPC_DISABLED" value="0" enum="RPCCallMode"> + The method will be called locally. </constant> <constant name="RPC_RELIABLE" value="1" enum="RPCCallMode"> + The method will be called remotely. </constant> <constant name="RPC_UNRELIABLE" value="2" enum="RPCCallMode"> + The method will be called remotely using an unreliable protocol. </constant> <constant name="RPC_RELIABLE_TO_ID" value="3" enum="RPCCallMode"> + The method will be called remotely for the given peer. </constant> <constant name="RPC_UNRELIABLE_TO_ID" value="4" enum="RPCCallMode"> + The method will be called remotely for the given peer, using an unreliable protocol. </constant> </constants> </class> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml index 68083614a6..54a02bf270 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionState" inherits="Reference" version="4.0"> +<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0"> <brief_description> + A Visual Script node representing a function state. </brief_description> <description> + [VisualScriptFunctionState] is returned from [VisualScriptYield] and can be used to resume a paused function call. </description> <tutorials> </tutorials> @@ -17,20 +19,23 @@ <argument index="2" name="args" type="Array"> </argument> <description> + Connects this [VisualScriptFunctionState] to a signal in the given object to automatically resume when it's emitted. </description> </method> <method name="is_valid" qualifiers="const"> <return type="bool"> </return> <description> + Returns whether the function state is valid. </description> </method> <method name="resume"> <return type="Variant"> </return> - <argument index="0" name="args" type="Array" default="null"> + <argument index="0" name="args" type="Array" default="[]"> </argument> <description> + Resumes the function to run from the point it was yielded. </description> </method> </methods> diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml index ef17bd8a28..87fdfd4e53 100644 --- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node returning a constant from [@GlobalScope]. </brief_description> <description> + A Visual Script node returning a constant from [@GlobalScope]. </description> <tutorials> </tutorials> @@ -10,6 +12,7 @@ </methods> <members> <member name="constant" type="int" setter="set_global_constant" getter="get_global_constant" default="0"> + The constant to be used. </member> </members> <constants> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml index bb1618a655..b348048298 100644 --- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptIndexGet" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node for getting a value from an array or a dictionary. </brief_description> <description> + [VisualScriptIndexGet] will return the value stored in an array or a dictionary under the given index. </description> <tutorials> </tutorials> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml index 4ff96f7211..d7fe7340ad 100644 --- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptIndexSet" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node for setting a value in an array or a dictionary. </brief_description> <description> + [VisualScriptIndexSet] will set the value stored in an array or a dictionary under the given index to the provided new value. </description> <tutorials> </tutorials> diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml index 6c296fdb4b..d6fa111500 100644 --- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml +++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml @@ -1,27 +1,35 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptInputAction" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node returning a state of an action. </brief_description> <description> + [VisualScriptInputAction] can be used to check if an action is pressed or released. </description> <tutorials> </tutorials> <methods> </methods> <members> - <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="@"""> + <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="&"""> + Name of the action. </member> <member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode" default="0"> + State of the action to check. See [enum Mode] for options. </member> </members> <constants> <constant name="MODE_PRESSED" value="0" enum="Mode"> + [code]True[/code] if action is pressed. </constant> <constant name="MODE_RELEASED" value="1" enum="Mode"> + [code]True[/code] if action is released (i.e. not pressed). </constant> <constant name="MODE_JUST_PRESSED" value="2" enum="Mode"> + [code]True[/code] on the frame the action was pressed. </constant> <constant name="MODE_JUST_RELEASED" value="3" enum="Mode"> + [code]True[/code] on the frame the action was released. </constant> </constants> </class> diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml index 8a7254b46a..671c427228 100644 --- a/modules/visual_script/doc_classes/VisualScriptLists.xml +++ b/modules/visual_script/doc_classes/VisualScriptLists.xml @@ -19,6 +19,7 @@ <argument index="2" name="index" type="int"> </argument> <description> + Adds an input port to the Visual Script node. </description> </method> <method name="add_output_data_port"> @@ -31,6 +32,7 @@ <argument index="2" name="index" type="int"> </argument> <description> + Adds an output port to the Visual Script node. </description> </method> <method name="remove_input_data_port"> @@ -39,6 +41,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Removes an input port from the Visual Script node. </description> </method> <method name="remove_output_data_port"> @@ -47,6 +50,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Removes an output port from the Visual Script node. </description> </method> <method name="set_input_data_port_name"> @@ -57,6 +61,7 @@ <argument index="1" name="name" type="String"> </argument> <description> + Sets the name of an input port. </description> </method> <method name="set_input_data_port_type"> @@ -67,6 +72,7 @@ <argument index="1" name="type" type="int" enum="Variant.Type"> </argument> <description> + Sets the type of an input port. </description> </method> <method name="set_output_data_port_name"> @@ -77,6 +83,7 @@ <argument index="1" name="name" type="String"> </argument> <description> + Sets the name of an output port. </description> </method> <method name="set_output_data_port_type"> @@ -87,6 +94,7 @@ <argument index="1" name="type" type="int" enum="Variant.Type"> </argument> <description> + Sets the type of an output port. </description> </method> </methods> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml index c3741eea89..185f0f1ffb 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml @@ -18,7 +18,7 @@ <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0"> The local variable's type. </member> - <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="@"new_local""> + <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&"new_local""> The local variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml index 619bbb90ca..865f0153c9 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml @@ -20,7 +20,7 @@ <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0"> The local variable's type. </member> - <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="@"new_local""> + <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&"new_local""> The local variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml index c8ce0f2732..cbbefa7f71 100644 --- a/modules/visual_script/doc_classes/VisualScriptOperator.xml +++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptOperator" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node that performs an operation on two values. </brief_description> <description> [b]Input Ports:[/b] @@ -15,8 +16,10 @@ </methods> <members> <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="Variant.Operator" default="6"> + The operation to be performed. See [enum Variant.Operator] for available options. </member> <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0"> + The type of the values for this operation. See [enum Variant.Type] for available options. </member> </members> <constants> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml index 1c22070ab1..c1bf443ea3 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptPropertyGet" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node returning a value of a property from an [Object]. </brief_description> <description> + [VisualScriptPropertyGet] can return a value of any property from the current object or other objects. </description> <tutorials> </tutorials> @@ -10,28 +12,39 @@ </methods> <members> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> + The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> + The base type to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. </member> <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> + The type to be used when [member set_mode] is set to [constant CALL_MODE_BASIC_TYPE]. </member> <member name="index" type="StringName" setter="set_index" getter="get_index"> + The indexed name of the property to retrieve. See [method Object.get_indexed] for details. </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> + The node path to use when [member set_mode] is set to [constant CALL_MODE_NODE_PATH]. </member> - <member name="property" type="StringName" setter="set_property" getter="get_property" default="@"""> + <member name="property" type="StringName" setter="set_property" getter="get_property" default="&"""> + The name of the property to retrieve. Changing this will clear [member index]. </member> <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode" default="0"> + [code]set_mode[/code] determines the target object from which the property will be retrieved. See [enum CallMode] for options. </member> </members> <constants> <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> + The property will be retrieved from this [Object]. </constant> <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> + The property will be retrieved from the given [Node] in the scene tree. </constant> <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> + The property will be retrieved from an instanced node with the given type and script. </constant> <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode"> + The property will be retrieved from a GDScript basic type (e.g. [Vector2]). </constant> </constants> </class> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml index 629576e261..75d6a63469 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptPropertySet" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node that sets a property of an [Object]. </brief_description> <description> + [VisualScriptPropertySet] can set the value of any property from the current object or other objects. </description> <tutorials> </tutorials> @@ -10,52 +12,75 @@ </methods> <members> <member name="assign_op" type="int" setter="set_assign_op" getter="get_assign_op" enum="VisualScriptPropertySet.AssignOp" default="0"> + The additional operation to perform when assigning. See [enum AssignOp] for options. </member> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> + The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> + The base type to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. </member> <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> + The type to be used when [member set_mode] is set to [constant CALL_MODE_BASIC_TYPE]. </member> <member name="index" type="StringName" setter="set_index" getter="get_index"> + The indexed name of the property to set. See [method Object.set_indexed] for details. </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> + The node path to use when [member set_mode] is set to [constant CALL_MODE_NODE_PATH]. </member> - <member name="property" type="StringName" setter="set_property" getter="get_property" default="@"""> + <member name="property" type="StringName" setter="set_property" getter="get_property" default="&"""> + The name of the property to set. Changing this will clear [member index]. </member> <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode" default="0"> + [code]set_mode[/code] determines the target object on which the property will be set. See [enum CallMode] for options. </member> </members> <constants> <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> + The property will be set on this [Object]. </constant> <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> + The property will be set on the given [Node] in the scene tree. </constant> <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> + The property will be set on an instanced node with the given type and script. </constant> <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode"> + The property will be set on a GDScript basic type (e.g. [Vector2]). </constant> <constant name="ASSIGN_OP_NONE" value="0" enum="AssignOp"> + The property will be assigned regularly. </constant> <constant name="ASSIGN_OP_ADD" value="1" enum="AssignOp"> + The value will be added to the property. Equivalent of doing [code]+=[/code]. </constant> <constant name="ASSIGN_OP_SUB" value="2" enum="AssignOp"> + The value will be subtracted from the property. Equivalent of doing [code]-=[/code]. </constant> <constant name="ASSIGN_OP_MUL" value="3" enum="AssignOp"> + The property will be multiplied by the value. Equivalent of doing [code]*=[/code]. </constant> <constant name="ASSIGN_OP_DIV" value="4" enum="AssignOp"> + The property will be divided by the value. Equivalent of doing [code]/=[/code]. </constant> <constant name="ASSIGN_OP_MOD" value="5" enum="AssignOp"> + A modulo operation will be performed on the property and the value. Equivalent of doing [code]%=[/code]. </constant> <constant name="ASSIGN_OP_SHIFT_LEFT" value="6" enum="AssignOp"> + The property will be binarly shifted to the left by the given value. Equivalent of doing [code]<<[/code]. </constant> <constant name="ASSIGN_OP_SHIFT_RIGHT" value="7" enum="AssignOp"> + The property will be binarly shifted to the right by the given value. Equivalent of doing [code]>>[/code]. </constant> <constant name="ASSIGN_OP_BIT_AND" value="8" enum="AssignOp"> + A binary [code]AND[/code] operation will be performed on the property. Equivalent of doing [code]&=[/code]. </constant> <constant name="ASSIGN_OP_BIT_OR" value="9" enum="AssignOp"> + A binary [code]OR[/code] operation will be performed on the property. Equivalent of doing [code]|=[/code]. </constant> <constant name="ASSIGN_OP_BIT_XOR" value="10" enum="AssignOp"> + A binary [code]XOR[/code] operation will be performed on the property. Equivalent of doing [code]^=[/code]. </constant> </constants> </class> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml index 191d4b6977..8cddd02c77 100644 --- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml +++ b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptSceneTree" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node for accessing [SceneTree] methods. </brief_description> <description> + A Visual Script node for accessing [SceneTree] methods. </description> <tutorials> </tutorials> diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml index cb3b04b583..89a10edde4 100644 --- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptSubCall" inherits="VisualScriptNode" version="4.0"> <brief_description> + Calls a method called [code]_subcall[/code] in this object. </brief_description> <description> + [VisualScriptSubCall] will call method named [code]_subcall[/code] in the current script. It will fail if the method doesn't exist or the provided arguments are wrong. </description> <tutorials> </tutorials> @@ -13,6 +15,7 @@ <argument index="0" name="arguments" type="Variant"> </argument> <description> + Called by this node. </description> </method> </methods> diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml index 80a8d31041..5dd1ad3421 100644 --- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml +++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptTypeCast" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node that casts the given value to another type. </brief_description> <description> + [VisualScriptTypeCast] will perform a type conversion to an [Object]-derived type. </description> <tutorials> </tutorials> @@ -10,8 +12,10 @@ </methods> <members> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default=""""> + The target script class to be converted to. If none, only the [member base_type] will be used. </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> + The target type to be converted to. </member> </members> <constants> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml index d182e14e4d..df20ac53f2 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml @@ -15,7 +15,7 @@ <methods> </methods> <members> - <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="@"""> + <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&"""> The variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml index 3bd392dd85..eb8ebbe338 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml @@ -16,7 +16,7 @@ <methods> </methods> <members> - <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="@"""> + <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&"""> The variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml index 0a8d529a48..b04ab7b014 100644 --- a/modules/visual_script/doc_classes/VisualScriptYield.xml +++ b/modules/visual_script/doc_classes/VisualScriptYield.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptYield" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node used to pause a function execution. </brief_description> <description> + [VisualScriptYield] will pause the function call and return [VisualScriptFunctionState], which can be used to resume the function. </description> <tutorials> </tutorials> @@ -10,16 +12,21 @@ </methods> <members> <member name="mode" type="int" setter="set_yield_mode" getter="get_yield_mode" enum="VisualScriptYield.YieldMode" default="1"> + The mode to use for yielding. See [enum YieldMode] for available options. </member> <member name="wait_time" type="float" setter="set_wait_time" getter="get_wait_time"> + The time to wait when [member mode] is set to [constant YIELD_WAIT]. </member> </members> <constants> <constant name="YIELD_FRAME" value="1" enum="YieldMode"> + Yields during an idle frame. </constant> <constant name="YIELD_PHYSICS_FRAME" value="2" enum="YieldMode"> + Yields during a physics frame. </constant> <constant name="YIELD_WAIT" value="3" enum="YieldMode"> + Yields a function and waits the given time. </constant> </constants> </class> diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml index 483cdfeaf8..c6c3188d08 100644 --- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml @@ -1,29 +1,38 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualScriptYieldSignal" inherits="VisualScriptNode" version="4.0"> <brief_description> + A Visual Script node yielding for a signal. </brief_description> <description> + [VisualScriptYieldSignal] will pause the function execution until the provided signal is emitted. </description> <tutorials> </tutorials> <methods> </methods> <members> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> + The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE]. </member> <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode" default="0"> + [code]call_mode[/code] determines the target object to wait for the signal emission. See [enum CallMode] for options. </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> + The node path to use when [member call_mode] is set to [constant CALL_MODE_NODE_PATH]. </member> - <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="@"""> + <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&"""> + The signal name to be waited for. </member> </members> <constants> <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> + A signal from this [Object] will be used. </constant> <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> + A signal from the given [Node] in the scene tree will be used. </constant> <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> + A signal from an instanced node with the given type will be used. </constant> </constants> </class> diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index 4c7b66e368..f20ef046a3 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -51,59 +51,59 @@ void register_visual_script_types() { //script_language_gd->init(); ScriptServer::register_language(visual_script_language); - ClassDB::register_class<VisualScript>(); - ClassDB::register_virtual_class<VisualScriptNode>(); - ClassDB::register_class<VisualScriptFunctionState>(); - ClassDB::register_class<VisualScriptFunction>(); - ClassDB::register_virtual_class<VisualScriptLists>(); - ClassDB::register_class<VisualScriptComposeArray>(); - ClassDB::register_class<VisualScriptOperator>(); - ClassDB::register_class<VisualScriptVariableSet>(); - ClassDB::register_class<VisualScriptVariableGet>(); - ClassDB::register_class<VisualScriptConstant>(); - ClassDB::register_class<VisualScriptIndexGet>(); - ClassDB::register_class<VisualScriptIndexSet>(); - ClassDB::register_class<VisualScriptGlobalConstant>(); - ClassDB::register_class<VisualScriptClassConstant>(); - ClassDB::register_class<VisualScriptMathConstant>(); - ClassDB::register_class<VisualScriptBasicTypeConstant>(); - ClassDB::register_class<VisualScriptEngineSingleton>(); - ClassDB::register_class<VisualScriptSceneNode>(); - ClassDB::register_class<VisualScriptSceneTree>(); - ClassDB::register_class<VisualScriptResourcePath>(); - ClassDB::register_class<VisualScriptSelf>(); - ClassDB::register_class<VisualScriptCustomNode>(); - ClassDB::register_class<VisualScriptSubCall>(); - ClassDB::register_class<VisualScriptComment>(); - ClassDB::register_class<VisualScriptConstructor>(); - ClassDB::register_class<VisualScriptLocalVar>(); - ClassDB::register_class<VisualScriptLocalVarSet>(); - ClassDB::register_class<VisualScriptInputAction>(); - ClassDB::register_class<VisualScriptDeconstruct>(); - ClassDB::register_class<VisualScriptPreload>(); - ClassDB::register_class<VisualScriptTypeCast>(); - - ClassDB::register_class<VisualScriptFunctionCall>(); - ClassDB::register_class<VisualScriptPropertySet>(); - ClassDB::register_class<VisualScriptPropertyGet>(); + GDREGISTER_CLASS(VisualScript); + GDREGISTER_VIRTUAL_CLASS(VisualScriptNode); + GDREGISTER_CLASS(VisualScriptFunctionState); + GDREGISTER_CLASS(VisualScriptFunction); + GDREGISTER_VIRTUAL_CLASS(VisualScriptLists); + GDREGISTER_CLASS(VisualScriptComposeArray); + GDREGISTER_CLASS(VisualScriptOperator); + GDREGISTER_CLASS(VisualScriptVariableSet); + GDREGISTER_CLASS(VisualScriptVariableGet); + GDREGISTER_CLASS(VisualScriptConstant); + GDREGISTER_CLASS(VisualScriptIndexGet); + GDREGISTER_CLASS(VisualScriptIndexSet); + GDREGISTER_CLASS(VisualScriptGlobalConstant); + GDREGISTER_CLASS(VisualScriptClassConstant); + GDREGISTER_CLASS(VisualScriptMathConstant); + GDREGISTER_CLASS(VisualScriptBasicTypeConstant); + GDREGISTER_CLASS(VisualScriptEngineSingleton); + GDREGISTER_CLASS(VisualScriptSceneNode); + GDREGISTER_CLASS(VisualScriptSceneTree); + GDREGISTER_CLASS(VisualScriptResourcePath); + GDREGISTER_CLASS(VisualScriptSelf); + GDREGISTER_CLASS(VisualScriptCustomNode); + GDREGISTER_CLASS(VisualScriptSubCall); + GDREGISTER_CLASS(VisualScriptComment); + GDREGISTER_CLASS(VisualScriptConstructor); + GDREGISTER_CLASS(VisualScriptLocalVar); + GDREGISTER_CLASS(VisualScriptLocalVarSet); + GDREGISTER_CLASS(VisualScriptInputAction); + GDREGISTER_CLASS(VisualScriptDeconstruct); + GDREGISTER_CLASS(VisualScriptPreload); + GDREGISTER_CLASS(VisualScriptTypeCast); + + GDREGISTER_CLASS(VisualScriptFunctionCall); + GDREGISTER_CLASS(VisualScriptPropertySet); + GDREGISTER_CLASS(VisualScriptPropertyGet); //ClassDB::register_type<VisualScriptScriptCall>(); - ClassDB::register_class<VisualScriptEmitSignal>(); + GDREGISTER_CLASS(VisualScriptEmitSignal); - ClassDB::register_class<VisualScriptReturn>(); - ClassDB::register_class<VisualScriptCondition>(); - ClassDB::register_class<VisualScriptWhile>(); - ClassDB::register_class<VisualScriptIterator>(); - ClassDB::register_class<VisualScriptSequence>(); - //ClassDB::register_class<VisualScriptInputFilter>(); - ClassDB::register_class<VisualScriptSwitch>(); - ClassDB::register_class<VisualScriptSelect>(); + GDREGISTER_CLASS(VisualScriptReturn); + GDREGISTER_CLASS(VisualScriptCondition); + GDREGISTER_CLASS(VisualScriptWhile); + GDREGISTER_CLASS(VisualScriptIterator); + GDREGISTER_CLASS(VisualScriptSequence); + //GDREGISTER_CLASS(VisualScriptInputFilter); + GDREGISTER_CLASS(VisualScriptSwitch); + GDREGISTER_CLASS(VisualScriptSelect); - ClassDB::register_class<VisualScriptYield>(); - ClassDB::register_class<VisualScriptYieldSignal>(); + GDREGISTER_CLASS(VisualScriptYield); + GDREGISTER_CLASS(VisualScriptYieldSignal); - ClassDB::register_class<VisualScriptBuiltinFunc>(); + GDREGISTER_CLASS(VisualScriptBuiltinFunc); - ClassDB::register_class<VisualScriptExpression>(); + GDREGISTER_CLASS(VisualScriptExpression); register_visual_script_nodes(); register_visual_script_func_nodes(); @@ -114,7 +114,7 @@ void register_visual_script_types() { #ifdef TOOLS_ENABLED ClassDB::set_current_api(ClassDB::API_EDITOR); - ClassDB::register_class<_VisualScriptEditor>(); + GDREGISTER_CLASS(_VisualScriptEditor); ClassDB::set_current_api(ClassDB::API_CORE); vs_editor_singleton = memnew(_VisualScriptEditor); Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptEditor", _VisualScriptEditor::get_singleton())); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index e91ae46a57..c4b3f9ba44 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -725,7 +725,7 @@ int VisualScript::get_available_id() const { ///////////////////////////////// -bool VisualScript::can_instance() const { +bool VisualScript::can_instantiate() const { return true; // ScriptServer::is_scripting_enabled(); } @@ -784,8 +784,9 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) { variables.get_key_list(&keys); for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) { - if (!variables[E->get()]._export) + if (!variables[E->get()]._export) { continue; + } PropertyInfo p = variables[E->get()].info; p.name = String(E->get()); @@ -953,60 +954,10 @@ bool VisualScript::are_subnodes_edited() const { } #endif -Vector<ScriptNetData> VisualScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> VisualScript::get_rpc_methods() const { return rpc_functions; } -uint16_t VisualScript::get_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < rpc_functions.size(); i++) { - if (rpc_functions[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName VisualScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName()); - return rpc_functions[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode VisualScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode VisualScript::get_rpc_mode(const StringName &p_method) const { - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> VisualScript::get_rset_properties() const { - return rpc_variables; -} - -uint16_t VisualScript::get_rset_property_id(const StringName &p_variable) const { - for (int i = 0; i < rpc_variables.size(); i++) { - if (rpc_variables[i].name == p_variable) { - return i; - } - } - return UINT16_MAX; -} - -StringName VisualScript::get_rset_property(const uint16_t p_rset_property_id) const { - ERR_FAIL_COND_V(p_rset_property_id >= rpc_variables.size(), StringName()); - return rpc_variables[p_rset_property_id].name; -} - -MultiplayerAPI::RPCMode VisualScript::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const { - ERR_FAIL_COND_V(p_rset_variable_id >= rpc_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_variables[p_rset_variable_id].mode; -} - -MultiplayerAPI::RPCMode VisualScript::get_rset_mode(const StringName &p_variable) const { - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - void VisualScript::_set_data(const Dictionary &p_data) { Dictionary d = p_data; if (d.has("base_type")) { @@ -1064,7 +1015,6 @@ void VisualScript::_set_data(const Dictionary &p_data) { // Takes all the rpc methods. rpc_functions.clear(); - rpc_variables.clear(); List<StringName> fns; functions.get_key_list(&fns); for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) { @@ -1072,9 +1022,10 @@ void VisualScript::_set_data(const Dictionary &p_data) { Ref<VisualScriptFunction> vsf = nodes[functions[E->get()].func_id].node; if (vsf.is_valid()) { if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = E->get(); - nd.mode = vsf->get_rpc_mode(); + nd.rpc_mode = vsf->get_rpc_mode(); + nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO if (rpc_functions.find(nd) == -1) { rpc_functions.push_back(nd); } @@ -1084,7 +1035,7 @@ void VisualScript::_set_data(const Dictionary &p_data) { } // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<SortNetData>(); + rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); } Dictionary VisualScript::_get_data() const { @@ -1536,7 +1487,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p state->flow_stack_pos = flow_stack_pos; state->stack.resize(p_stack_size); state->pass = p_pass; - copymem(state->stack.ptrw(), p_stack, p_stack_size); + memcpy(state->stack.ptrw(), p_stack, p_stack_size); // Step 2, run away, return directly. r_error.error = Callable::CallError::CALL_OK; @@ -1606,7 +1557,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p } next = node->sequence_outputs[output]; - VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "NULL")); + VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "Null")); } if (flow_stack) { @@ -1801,7 +1752,7 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p sequence_bits[i] = false; // All starts as false. } - zeromem(pass_stack, f->pass_stack_size * sizeof(int)); + memset(pass_stack, 0, f->pass_stack_size * sizeof(int)); Map<int, VisualScriptNodeInstance *>::Element *E = instances.find(f->node); if (!E) { @@ -1881,46 +1832,10 @@ Ref<Script> VisualScriptInstance::get_script() const { return script; } -Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> VisualScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t VisualScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName VisualScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { - return script->get_rpc_method(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - return script->get_rpc_mode_by_id(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t VisualScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName VisualScriptInstance::get_rset_property(const uint16_t p_rset_property_id) const { - return script->get_rset_property(p_rset_property_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const { - return script->get_rset_mode_by_id(p_rset_variable_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) { script = p_script; owner = p_owner; @@ -2043,19 +1958,19 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) { Ref<VisualScriptNode> node = script->nodes[F->get()].node; - VisualScriptNodeInstance *instance = node->instance(this); // Create instance. + VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance. ERR_FAIL_COND(!instance); instance->base = node.ptr(); instance->id = F->get(); instance->input_port_count = node->get_input_value_port_count(); - instance->input_ports = NULL; + instance->input_ports = nullptr; instance->output_port_count = node->get_output_value_port_count(); - instance->output_ports = NULL; + instance->output_ports = nullptr; instance->sequence_output_count = node->get_output_sequence_port_count(); instance->sequence_index = function.node_count++; - instance->sequence_outputs = NULL; + instance->sequence_outputs = nullptr; instance->pass_idx = -1; if (instance->input_port_count) { @@ -2075,7 +1990,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o if (instance->sequence_output_count) { instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count); for (int i = 0; i < instance->sequence_output_count; i++) { - instance->sequence_outputs[i] = NULL; // If it remains null, flow ends here. + instance->sequence_outputs[i] = nullptr; // If it remains null, flow ends here. } } @@ -2085,10 +2000,11 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o StringName var_name; - if (Object::cast_to<VisualScriptLocalVar>(*node)) + if (Object::cast_to<VisualScriptLocalVar>(*node)) { var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges(); - else + } else { var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges(); + } if (!local_var_indices.has(var_name)) { local_var_indices[var_name] = function.max_stack; @@ -2252,6 +2168,7 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int } void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds) { + ERR_FAIL_NULL(p_obj); Vector<Variant> binds; for (int i = 0; i < p_binds.size(); i++) { binds.push_back(p_binds[i]); @@ -2287,7 +2204,7 @@ Variant VisualScriptFunctionState::resume(Array p_args) { void VisualScriptFunctionState::_bind_methods() { ClassDB::bind_method(D_METHOD("connect_to_signal", "obj", "signals", "args"), &VisualScriptFunctionState::connect_to_signal); - ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("is_valid"), &VisualScriptFunctionState::is_valid); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &VisualScriptFunctionState::_signal_callback, MethodInfo("_signal_callback")); } @@ -2333,6 +2250,10 @@ void VisualScriptLanguage::finish() { void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const { } +bool VisualScriptLanguage::is_control_flow_keyword(String p_keyword) const { + return false; +} + void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { } @@ -2341,7 +2262,7 @@ void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) con Ref<Script> VisualScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { Ref<VisualScript> script; - script.instance(); + script.instantiate(); script->set_instance_base_type(p_base_class_name); return script; } @@ -2355,7 +2276,7 @@ void VisualScriptLanguage::make_template(const String &p_class_name, const Strin script->set_instance_base_type(p_base_class_name); } -bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { return false; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 72362e0ef4..932ebeb27f 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -87,7 +87,7 @@ public: void set_breakpoint(bool p_breakpoint); bool is_breakpoint() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) = 0; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) = 0; struct TypeGuess { Variant::Type type = Variant::NIL; @@ -234,8 +234,7 @@ private: HashMap<StringName, Function> functions; HashMap<StringName, Variable> variables; Map<StringName, Vector<Argument>> custom_signals; - Vector<ScriptNetData> rpc_functions; - Vector<ScriptNetData> rpc_variables; + Vector<MultiplayerAPI::RPCConfig> rpc_functions; Map<Object *, VisualScriptInstance *> instances; @@ -326,7 +325,7 @@ public: void set_instance_base_type(const StringName &p_type); - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; virtual StringName get_instance_base_type() const override; @@ -363,17 +362,7 @@ public: virtual int get_member_line(const StringName &p_member) const override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_property) const override; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED virtual bool are_subnodes_edited() const; @@ -454,24 +443,14 @@ public: virtual ScriptLanguage *get_language(); - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_property) const; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; VisualScriptInstance(); ~VisualScriptInstance(); }; -class VisualScriptFunctionState : public Reference { - GDCLASS(VisualScriptFunctionState, Reference); +class VisualScriptFunctionState : public RefCounted { + GDCLASS(VisualScriptFunctionState, RefCounted); friend class VisualScriptInstance; ObjectID instance_id; @@ -586,12 +565,13 @@ public: /* EDITOR FUNCTIONS */ virtual void get_reserved_words(List<String> *p_words) const; + virtual bool is_control_flow_keyword(String p_keyword) const; virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; @@ -639,7 +619,7 @@ public: template <class T> static Ref<VisualScriptNode> create_node_generic(const String &p_name) { Ref<T> node; - node.instance(); + node.instantiate(); return node; } diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 7ca14fbca8..f17ad62531 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -33,7 +33,7 @@ #include "core/io/marshalls.h" #include "core/math/math_funcs.h" #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" @@ -132,6 +132,7 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const { case TEXT_PRINT: case TEXT_PRINTERR: case TEXT_PRINTRAW: + case MATH_SEED: return true; default: return false; @@ -723,7 +724,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in case VisualScriptBuiltinFunc::MATH_POSMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - *r_return = Math::posmod((int)*p_inputs[0], (int)*p_inputs[1]); + *r_return = Math::posmod((int64_t)*p_inputs[0], (int64_t)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FLOOR: { VALIDATE_ARG_NUM(0); @@ -1186,7 +1187,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptBuiltinFunc::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptBuiltinFunc::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceBuiltinFunc *instance = memnew(VisualScriptNodeInstanceBuiltinFunc); instance->node = this; instance->instance = p_instance; diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index 1fafaf1d98..7196d4b46a 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -139,7 +139,7 @@ public: void set_func(BuiltinFunc p_which); BuiltinFunc get_func(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func); VisualScriptBuiltinFunc(); diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index d520837d43..8712bfa06b 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -381,7 +381,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; - case Variant::QUAT: + case Variant::QUATERNION: color = Color(0.93, 0.41, 0.64); break; case Variant::AABB: @@ -390,7 +390,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::BASIS: color = Color(0.89, 0.93, 0.41); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: color = Color(0.96, 0.66, 0.43); break; @@ -487,7 +487,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; - case Variant::QUAT: + case Variant::QUATERNION: color = Color(0.93, 0.41, 0.64); break; case Variant::AABB: @@ -496,7 +496,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::BASIS: color = Color(0.7, 0.73, 0.1); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: color = Color(0.96, 0.56, 0.28); break; @@ -624,10 +624,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_theme_icon("Vector3i", "EditorIcons"), Control::get_theme_icon("Transform2D", "EditorIcons"), Control::get_theme_icon("Plane", "EditorIcons"), - Control::get_theme_icon("Quat", "EditorIcons"), + Control::get_theme_icon("Quaternion", "EditorIcons"), Control::get_theme_icon("AABB", "EditorIcons"), Control::get_theme_icon("Basis", "EditorIcons"), - Control::get_theme_icon("Transform", "EditorIcons"), + Control::get_theme_icon("Transform3D", "EditorIcons"), Control::get_theme_icon("Color", "EditorIcons"), Control::get_theme_icon("NodePath", "EditorIcons"), Control::get_theme_icon("RID", "EditorIcons"), @@ -710,7 +710,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { has_gnode_text = true; LineEdit *line_edit = memnew(LineEdit); line_edit->set_text(node->get_text()); - line_edit->set_expand_to_text_length(true); + line_edit->set_expand_to_text_length_enabled(true); line_edit->add_theme_font_override("font", get_theme_font("source", "EditorFonts")); gnode->add_child(line_edit); line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E->get())); @@ -739,22 +739,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) { } Color c = sbf->get_border_color(); + c = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85); Color ic = c; - c.a = 1; - if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) { - Color mono_color; - if (((c.r + c.g + c.b) / 3) < 0.7) { - mono_color = Color(1.0, 1.0, 1.0); - ic = Color(0.0, 0.0, 0.0, 0.7); - } else { - mono_color = Color(0.0, 0.0, 0.0); - ic = Color(1.0, 1.0, 1.0, 0.7); - } - mono_color.a = 0.85; - c = mono_color; - } gnode->add_theme_color_override("title_color", c); - c.a = 0.7; + c.a = 1; gnode->add_theme_color_override("close_color", c); gnode->add_theme_color_override("resizer_color", ic); gnode->add_theme_style_override("frame", sbf); @@ -843,7 +831,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { hbc->add_child(name_box); name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0)); name_box->set_text(left_name); - name_box->set_expand_to_text_length(true); + name_box->set_expand_to_text_length_enabled(true); name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get())); name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, true)); } else { @@ -938,7 +926,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { hbc->add_child(name_box); name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0)); name_box->set_text(right_name); - name_box->set_expand_to_text_length(true); + name_box->set_expand_to_text_length_enabled(true); name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get())); name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, false)); } else { @@ -1087,10 +1075,10 @@ void VisualScriptEditor::_update_members() { Control::get_theme_icon("Vector3i", "EditorIcons"), Control::get_theme_icon("Transform2D", "EditorIcons"), Control::get_theme_icon("Plane", "EditorIcons"), - Control::get_theme_icon("Quat", "EditorIcons"), + Control::get_theme_icon("Quaternion", "EditorIcons"), Control::get_theme_icon("AABB", "EditorIcons"), Control::get_theme_icon("Basis", "EditorIcons"), - Control::get_theme_icon("Transform", "EditorIcons"), + Control::get_theme_icon("Transform3D", "EditorIcons"), Control::get_theme_icon("Color", "EditorIcons"), Control::get_theme_icon("NodePath", "EditorIcons"), Control::get_theme_icon("RID", "EditorIcons"), @@ -1181,11 +1169,11 @@ void VisualScriptEditor::_member_selected() { selected = ti->get_metadata(0); - if (ti->get_parent() == members->get_root()->get_children()) { + if (ti->get_parent() == members->get_root()->get_first_child()) { #ifdef OSX_ENABLED bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META); #else - bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL); + bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL); #endif if (held_ctrl) { ERR_FAIL_COND(!script->has_function(selected)); @@ -1227,7 +1215,7 @@ void VisualScriptEditor::_member_edited() { TreeItem *root = members->get_root(); - if (ti->get_parent() == root->get_children()) { + if (ti->get_parent() == root->get_first_child()) { selected = new_name; int node_id = script->get_function_node_id(name); @@ -1268,7 +1256,7 @@ void VisualScriptEditor::_member_edited() { return; // Or crash because it will become invalid. } - if (ti->get_parent() == root->get_children()->get_next()) { + if (ti->get_parent() == root->get_first_child()->get_next()) { selected = new_name; undo_redo->create_action(TTR("Rename Variable")); undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name); @@ -1284,7 +1272,7 @@ void VisualScriptEditor::_member_edited() { return; // Or crash because it will become invalid. } - if (ti->get_parent() == root->get_children()->get_next()->get_next()) { + if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) { selected = new_name; undo_redo->create_action(TTR("Rename Signal")); undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name); @@ -1312,10 +1300,10 @@ void VisualScriptEditor::_create_function_dialog() { void VisualScriptEditor::_create_function() { String name = _validate_name((func_name_box->get_text() == "") ? "new_func" : func_name_box->get_text()); selected = name; - Vector2 ofs = _get_available_pos(); + Vector2 pos = _get_available_pos(); Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(name); for (int i = 0; i < func_input_vbox->get_child_count(); i++) { @@ -1334,7 +1322,7 @@ void VisualScriptEditor::_create_function() { undo_redo->create_action(TTR("Add Function")); undo_redo->add_do_method(script.ptr(), "add_function", name, func_node_id); undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", func_node_id); undo_redo->add_do_method(this, "_update_members"); undo_redo->add_undo_method(this, "_update_members"); @@ -1418,7 +1406,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt if (ti->get_parent() == root) { //main buttons - if (ti == root->get_children()) { + if (ti == root->get_first_child()) { // Add function, this one uses menu. if (p_button == 1) { @@ -1429,18 +1417,18 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt } else if (p_button == 0) { String name = _validate_name("new_function"); selected = name; - Vector2 ofs = _get_available_pos(); + Vector2 pos = _get_available_pos(); Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(name); int fn_id = script->get_available_id(); undo_redo->create_action(TTR("Add Function")); undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(script.ptr(), "remove_node", fn_id); + undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); undo_redo->add_do_method(this, "_update_members"); undo_redo->add_undo_method(this, "_update_members"); undo_redo->add_do_method(this, "_update_graph"); @@ -1455,7 +1443,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt return; // Or crash because it will become invalid. } - if (ti == root->get_children()->get_next()) { + if (ti == root->get_first_child()->get_next()) { // Add variable. String name = _validate_name("new_variable"); selected = name; @@ -1471,7 +1459,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt return; // Or crash because it will become invalid. } - if (ti == root->get_children()->get_next()->get_next()) { + if (ti == root->get_first_child()->get_next()->get_next()) { // Add variable. String name = _validate_name("new_signal"); selected = name; @@ -1486,7 +1474,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt undo_redo->commit_action(); return; // Or crash because it will become invalid. } - } else if (ti->get_parent() == root->get_children()) { + } else if (ti->get_parent() == root->get_first_child()) { selected = ti->get_text(0); function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10)); function_name_edit->popup(); @@ -1633,17 +1621,19 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id updating_graph = false; } -Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const { - if (centered) { - ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5; - } - +Vector2 VisualScriptEditor::_get_pos_in_graph(Vector2 p_point) const { + Vector2 pos = (graph->get_scroll_ofs() + p_point) / (graph->get_zoom() * EDSCALE); if (graph->is_using_snap()) { int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); + pos = pos.snapped(Vector2(snap, snap)); } + return pos; +} - ofs /= EDSCALE; +Vector2 VisualScriptEditor::_get_available_pos(bool p_centered, Vector2 p_pos) const { + if (p_centered) { + p_pos = _get_pos_in_graph(graph->get_size() * 0.5); + } while (true) { bool exists = false; @@ -1651,8 +1641,8 @@ Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const script->get_node_list(&existing); for (List<int>::Element *E = existing.front(); E; E = E->next()) { Point2 pos = script->get_node_position(E->get()); - if (pos.distance_to(ofs) < 50) { - ofs += Vector2(graph->get_snap(), graph->get_snap()); + if (pos.distance_to(p_pos) < 50) { + p_pos += Vector2(graph->get_snap(), graph->get_snap()); exists = true; break; } @@ -1663,7 +1653,7 @@ Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const break; } - return ofs; + return p_pos; } String VisualScriptEditor::_validate_name(const String &p_name) const { @@ -1826,6 +1816,8 @@ void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool n } void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) { + ERR_FAIL_COND(p_event.is_null()); + // GUI input for VS Editor Plugin Ref<InputEventMouseButton> key = p_event; @@ -1852,18 +1844,18 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) { TreeItem *ti = members->get_selected(); if (ti) { TreeItem *root = members->get_root(); - if (ti->get_parent() == root->get_children()) { + if (ti->get_parent() == root->get_first_child()) { member_type = MEMBER_FUNCTION; } - if (ti->get_parent() == root->get_children()->get_next()) { + if (ti->get_parent() == root->get_first_child()->get_next()) { member_type = MEMBER_VARIABLE; } - if (ti->get_parent() == root->get_children()->get_next()->get_next()) { + if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) { member_type = MEMBER_SIGNAL; } member_name = ti->get_text(0); } - if (ED_IS_SHORTCUT("visual_script_editor/delete_selected", p_event)) { + if (ED_IS_SHORTCUT("ui_graph_delete", p_event)) { _member_option(MEMBER_REMOVE); } if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) { @@ -1873,9 +1865,9 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseButton> btn = p_event; - if (btn.is_valid() && btn->is_doubleclick()) { + if (btn.is_valid() && btn->is_double_click()) { TreeItem *ti = members->get_selected(); - if (ti && ti->get_parent() == members->get_root()->get_children()) { // to check if it's a function + if (ti && ti->get_parent() == members->get_root()->get_first_child()) { // to check if it's a function _center_on_node(script->get_function_node_id(ti->get_metadata(0))); } } @@ -1957,13 +1949,13 @@ Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f Dictionary dd; TreeItem *root = members->get_root(); - if (it->get_parent() == root->get_children()) { + if (it->get_parent() == root->get_first_child()) { dd["type"] = "visual_script_function_drag"; dd["function"] = type; - } else if (it->get_parent() == root->get_children()->get_next()) { + } else if (it->get_parent() == root->get_first_child()->get_next()) { dd["type"] = "visual_script_variable_drag"; dd["variable"] = type; - } else if (it->get_parent() == root->get_children()->get_next()->get_next()) { + } else if (it->get_parent() == root->get_first_child()->get_next()->get_next()) { dd["type"] = "visual_script_signal_drag"; dd["signal"] = type; @@ -2059,16 +2051,9 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da return; } - Vector2 ofs = graph->get_scroll_ofs() + p_point; - - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } + Vector2 pos = _get_pos_in_graph(p_point); - ofs /= EDSCALE; - - int new_id = _create_new_node_from_name(d["node_type"], ofs); + int new_id = _create_new_node_from_name(d["node_type"], pos); Node *node = graph->get_node(itos(new_id)); if (node) { @@ -2081,25 +2066,19 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da #ifdef OSX_ENABLED bool use_set = Input::get_singleton()->is_key_pressed(KEY_META); #else - bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL); + bool use_set = Input::get_singleton()->is_key_pressed(KEY_CTRL); #endif - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptNode> vnode; if (use_set) { Ref<VisualScriptVariableSet> vnodes; - vnodes.instance(); + vnodes.instantiate(); vnodes->set_variable(d["variable"]); vnode = vnodes; } else { Ref<VisualScriptVariableGet> vnodeg; - vnodeg.instance(); + vnodeg.instantiate(); vnodeg->set_variable(d["variable"]); vnode = vnodeg; } @@ -2107,7 +2086,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2121,22 +2100,16 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "visual_script_function_drag") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptFunctionCall> vnode; - vnode.instance(); + vnode.instantiate(); vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type()); undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]); @@ -2153,22 +2126,16 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "visual_script_signal_drag") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptEmitSignal> vnode; - vnode.instance(); + vnode.instantiate(); vnode->set_signal(d["signal"]); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2182,22 +2149,16 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "resource") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptPreload> prnode; - prnode.instance(); + prnode.instantiate(); prnode->set_preload(d["resource"]); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Preload Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2211,13 +2172,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "files") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Array files = d["files"]; @@ -2234,14 +2189,14 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } Ref<VisualScriptPreload> prnode; - prnode.instance(); + prnode.instantiate(); prnode->set_preload(res); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); new_ids.push_back(new_id); new_id++; - ofs += Vector2(20, 20) * EDSCALE; + pos += Vector2(20, 20); } undo_redo->add_do_method(this, "_update_graph"); @@ -2269,18 +2224,12 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da #ifdef OSX_ENABLED bool use_node = Input::get_singleton()->is_key_pressed(KEY_META); #else - bool use_node = Input::get_singleton()->is_key_pressed(KEY_CONTROL); + bool use_node = Input::get_singleton()->is_key_pressed(KEY_CTRL); #endif Array nodes = d["nodes"]; - Vector2 ofs = graph->get_scroll_ofs() + p_point; - - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); undo_redo->create_action(TTR("Add Node(s) From Tree")); int base_id = script->get_available_id(); @@ -2300,13 +2249,13 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da if (use_node) { Ref<VisualScriptSceneNode> scene_node; - scene_node.instance(); + scene_node.instantiate(); scene_node->set_node_path(sn->get_path_to(node)); n = scene_node; } else { // ! Doesn't work properly. Ref<VisualScriptFunctionCall> call; - call.instance(); + call.instantiate(); call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH); call->set_base_path(sn->get_path_to(node)); call->set_base_type(node->get_class()); @@ -2315,11 +2264,11 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da selecting_method_id = base_id; } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", base_id); base_id++; - ofs += Vector2(25, 25); + pos += Vector2(25, 25); } undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2341,18 +2290,12 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } Node *node = Object::cast_to<Node>(obj); - Vector2 ofs = graph->get_scroll_ofs() + p_point; - - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } + Vector2 pos = _get_pos_in_graph(p_point); - ofs /= EDSCALE; #ifdef OSX_ENABLED bool use_get = Input::get_singleton()->is_key_pressed(KEY_META); #else - bool use_get = Input::get_singleton()->is_key_pressed(KEY_CONTROL); + bool use_get = Input::get_singleton()->is_key_pressed(KEY_CTRL); #endif if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { @@ -2368,7 +2311,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da if (!use_get) { Ref<VisualScriptPropertySet> pset; - pset.instance(); + pset.instantiate(); pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); pset->set_base_type(obj->get_class()); /*if (use_value) { @@ -2378,14 +2321,14 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da vnode = pset; } else { Ref<VisualScriptPropertyGet> pget; - pget.instance(); + pget.instantiate(); pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); pget->set_base_type(obj->get_class()); vnode = pget; } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); if (!use_get) { undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); @@ -2410,7 +2353,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da if (!use_get) { Ref<VisualScriptPropertySet> pset; - pset.instance(); + pset.instantiate(); if (sn == node) { pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); } else { @@ -2421,7 +2364,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da vnode = pset; } else { Ref<VisualScriptPropertyGet> pget; - pget.instance(); + pget.instantiate(); if (sn == node) { pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); } else { @@ -2430,7 +2373,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } vnode = pget; } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); if (!use_get) { undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); @@ -2676,7 +2619,7 @@ void VisualScriptEditor::add_callback(const String &p_function, PackedStringArra } Ref<VisualScriptFunction> func; - func.instance(); + func.instantiate(); for (int i = 0; i < p_args.size(); i++) { String name = p_args[i]; Variant::Type type = Variant::NIL; @@ -2721,6 +2664,10 @@ void VisualScriptEditor::set_debugger_active(bool p_active) { } } +Control *VisualScriptEditor::get_base_editor() const { + return graph; +} + void VisualScriptEditor::set_tooltip_request_func(String p_method, Object *p_obj) { } @@ -3015,9 +2962,9 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro if (!vsn.is_valid()) { return; } - if (vsn->get_output_value_port_count()) - + if (vsn->get_output_value_port_count() || vsn->get_output_sequence_port_count()) { port_action_pos = p_release_pos; + } if (p_from_slot < vsn->get_output_sequence_port_count()) { port_action_node = p_from.to_int(); @@ -3081,19 +3028,12 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac } void VisualScriptEditor::_port_action_menu(int p_option) { - Vector2 ofs = graph->get_scroll_ofs() + port_action_pos; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - ofs /= EDSCALE; - Set<int> vn; switch (p_option) { case CREATE_CALL_SET_GET: { Ref<VisualScriptFunctionCall> n; - n.instance(); + n.instantiate(); VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); @@ -3178,13 +3118,7 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua } void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) { - Vector2 ofs = graph->get_scroll_ofs() + port_action_pos; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - ofs /= EDSCALE; - ofs /= graph->get_zoom(); + Vector2 pos = _get_pos_in_graph(port_action_pos); Set<int> vn; @@ -3222,7 +3156,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, pos); if (vnode_old.is_valid() && p_connecting) { connect_seq(vnode_old, vnode_new, new_id); connect_data(vnode_old, vnode_new, new_id); @@ -3240,16 +3174,16 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri if (p_category == String("method")) { Ref<VisualScriptFunctionCall> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_category == String("set")) { Ref<VisualScriptPropertySet> n; - n.instance(); + n.instantiate(); vnode = n; script_prop_set = n; } else if (p_category == String("get")) { Ref<VisualScriptPropertyGet> n; - n.instance(); + n.instantiate(); n->set_property(p_text); vnode = n; } @@ -3257,35 +3191,35 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri if (p_category == String("action")) { if (p_text == "VisualScriptCondition") { Ref<VisualScriptCondition> n; - n.instance(); + n.instantiate(); vnode = n; } if (p_text == "VisualScriptSwitch") { Ref<VisualScriptSwitch> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptSequence") { Ref<VisualScriptSequence> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptIterator") { Ref<VisualScriptIterator> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptWhile") { Ref<VisualScriptWhile> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptReturn") { Ref<VisualScriptReturn> n; - n.instance(); + n.instantiate(); vnode = n; } } int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph", new_id); undo_redo->add_undo_method(this, "_update_graph", new_id); @@ -3474,7 +3408,7 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons selected = name; Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(name); int fn_id = script->get_available_id(); undo_redo->create_action(TTR("Add Function")); @@ -3484,18 +3418,18 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string); } - Vector2 ofs = _get_available_pos(); + Vector2 pos = _get_available_pos(); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { Ref<VisualScriptReturn> ret_node; - ret_node.instance(); + ret_node.instantiate(); ret_node->set_return_type(minfo.return_val.type); ret_node->set_enable_return_value(true); ret_node->set_name(name); int nid = script->get_available_id() + 1; - undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, ofs + Vector2(500, 0))); + undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, pos + Vector2(500, 0))); undo_redo->add_undo_method(script.ptr(), "remove_node", nid); } @@ -3621,32 +3555,33 @@ void VisualScriptEditor::_notification(int p_what) { bool dark_theme = tm->get_constant("dark_theme", "Editor"); - List<Pair<String, Color>> colors; if (dark_theme) { - colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96))); - colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51))); - colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81))); - colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87))); - colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96))); - colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69))); + node_colors["flow_control"] = Color(0.96, 0.96, 0.96); + node_colors["functions"] = Color(0.96, 0.52, 0.51); + node_colors["data"] = Color(0.5, 0.96, 0.81); + node_colors["operators"] = Color(0.67, 0.59, 0.87); + node_colors["custom"] = Color(0.5, 0.73, 0.96); + node_colors["constants"] = Color(0.96, 0.5, 0.69); } else { - colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26))); - colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38))); - colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51))); - colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82))); - colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95))); - colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49))); + node_colors["flow_control"] = Color(0.26, 0.26, 0.26); + node_colors["functions"] = Color(0.95, 0.4, 0.38); + node_colors["data"] = Color(0.07, 0.73, 0.51); + node_colors["operators"] = Color(0.51, 0.4, 0.82); + node_colors["custom"] = Color(0.31, 0.63, 0.95); + node_colors["constants"] = Color(0.94, 0.18, 0.49); } - for (List<Pair<String, Color>>::Element *E = colors.front(); E; E = E->next()) { - Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode"); + for (Map<StringName, Color>::Element *E = node_colors.front(); E; E = E->next()) { + const Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode"); + if (!sb.is_null()) { Ref<StyleBoxFlat> frame_style = sb->duplicate(); - Color c = sb->get_border_color(); - Color cn = E->get().second; - cn.a = c.a; - frame_style->set_border_color(cn); - node_styles[E->get().first] = frame_style; + // Adjust the border color to be close to the GraphNode's background color. + // This keeps the node's title area from being too distracting. + Color color = dark_theme ? E->get().darkened(0.75) : E->get().lightened(0.75); + color.a = 0.9; + frame_style->set_border_color(color); + node_styles[E->key()] = frame_style; } } @@ -3998,16 +3933,16 @@ void VisualScriptEditor::_menu_option(int p_what) { { String new_fn = _validate_name("new_function"); - Vector2 ofs = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150)); + Vector2 pos = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150)); Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(new_fn); undo_redo->create_action(TTR("Create Function")); undo_redo->add_do_method(script.ptr(), "add_function", new_fn, fn_id); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn); undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); undo_redo->add_do_method(this, "_update_members"); @@ -4046,12 +3981,12 @@ void VisualScriptEditor::_menu_option(int p_what) { int m = 1; for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) { Ref<VisualScriptReturn> ret_node; - ret_node.instance(); + ret_node.instantiate(); int ret_id = fn_id + (m++); selections.insert(ret_id); - Vector2 ofsi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100)); - undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, ofsi); + Vector2 posi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100)); + undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi); undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id); undo_redo->add_do_method(script.ptr(), "sequence_connect", G->get(), 0, ret_id); @@ -4121,32 +4056,32 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { Ref<Texture2D> edit_icon = Control::get_theme_icon("Edit", "EditorIcons"); - if (ti->get_parent() == root->get_children()) { + if (ti->get_parent() == root->get_first_child()) { member_type = MEMBER_FUNCTION; member_name = ti->get_text(0); member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE); + member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); member_popup->popup(); return; } - if (ti->get_parent() == root->get_children()->get_next()) { + if (ti->get_parent() == root->get_first_child()->get_next()) { member_type = MEMBER_VARIABLE; member_name = ti->get_text(0); member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE); + member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); member_popup->popup(); return; } - if (ti->get_parent() == root->get_children()->get_next()->get_next()) { + if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) { member_type = MEMBER_SIGNAL; member_name = ti->get_text(0); member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE); + member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); member_popup->popup(); return; } @@ -4248,9 +4183,9 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name); - ClassDB::bind_method("get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &VisualScriptEditor::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw); ClassDB::bind_method("_input", &VisualScriptEditor::_input); @@ -4320,7 +4255,7 @@ VisualScriptEditor::VisualScriptEditor() { function_name_box = memnew(LineEdit); function_name_edit->add_child(function_name_box); function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input)); - function_name_box->set_expand_to_text_length(true); + function_name_box->set_expand_to_text_length_enabled(true); add_child(function_name_edit); /// Actual Graph /// @@ -4534,7 +4469,7 @@ void VisualScriptEditor::register_editor() { Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_name) { Ref<VisualScriptCustomNode> node; - node.instance(); + node.instantiate(); node->set_script(singleton->custom_nodes[p_name]); return node; } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index bb6f194286..1f0f087be7 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -135,6 +135,7 @@ class VisualScriptEditor : public ScriptEditorBase { Vector<Pair<Variant::Type, String>> args; }; + Map<StringName, Color> node_colors; HashMap<StringName, Ref<StyleBox>> node_styles; void _update_graph_connections(); @@ -225,7 +226,8 @@ class VisualScriptEditor : public ScriptEditorBase { void _update_node_size(int p_id); void _port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input); - Vector2 _get_available_pos(bool centered = true, Vector2 ofs = Vector2()) const; + Vector2 _get_pos_in_graph(Vector2 p_point) const; + Vector2 _get_available_pos(bool p_centered = true, Vector2 p_pos = Vector2()) const; bool node_has_sequence_connections(int p_id); @@ -316,9 +318,12 @@ public: virtual void set_tooltip_request_func(String p_method, Object *p_obj) override; virtual Control *get_edit_menu() override; virtual void clear_edit_menu() override; + virtual void set_find_replace_bar(FindReplaceBar *p_bar) override { p_bar->hide(); }; // Not needed here. virtual bool can_lose_focus_on_node_selection() override { return false; } virtual void validate() override; + virtual Control *get_base_editor() const override; + static void register_editor(); static void free_clipboard(); diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index cb4230bea9..d63fbeb726 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -1498,7 +1498,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptExpression::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptExpression::instantiate(VisualScriptInstance *p_instance) { _compile_expression(); VisualScriptNodeInstanceExpression *instance = memnew(VisualScriptNodeInstanceExpression); instance->instance = p_instance; diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h index c35075ea53..ef16222b42 100644 --- a/modules/visual_script/visual_script_expression.h +++ b/modules/visual_script/visual_script_expression.h @@ -273,7 +273,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "operators"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptExpression(); ~VisualScriptExpression(); diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index e977f9c96b..af86f90b25 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -138,7 +138,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptReturn::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptReturn::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceReturn *instance = memnew(VisualScriptNodeInstanceReturn); instance->node = this; instance->instance = p_instance; @@ -154,7 +154,7 @@ VisualScriptReturn::VisualScriptReturn() { template <bool with_value> static Ref<VisualScriptNode> create_return_node(const String &p_name) { Ref<VisualScriptReturn> node; - node.instance(); + node.instantiate(); node->set_enable_return_value(with_value); return node; } @@ -231,7 +231,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptCondition::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptCondition::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceCondition *instance = memnew(VisualScriptNodeInstanceCondition); instance->node = this; instance->instance = p_instance; @@ -311,7 +311,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptWhile::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptWhile::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceWhile *instance = memnew(VisualScriptNodeInstanceWhile); instance->node = this; instance->instance = p_instance; @@ -435,7 +435,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptIterator::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptIterator::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIterator *instance = memnew(VisualScriptNodeInstanceIterator); instance->node = this; instance->instance = p_instance; @@ -534,7 +534,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSequence::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSequence::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSequence *instance = memnew(VisualScriptNodeInstanceSequence); instance->node = this; instance->instance = p_instance; @@ -618,7 +618,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSwitch::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSwitch::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSwitch *instance = memnew(VisualScriptNodeInstanceSwitch); instance->instance = p_instance; instance->case_count = case_values.size(); @@ -831,7 +831,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptTypeCast::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptTypeCast::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceTypeCast *instance = memnew(VisualScriptNodeInstanceTypeCast); instance->instance = p_instance; instance->base_type = base_type; diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index d9c4dedafd..73822fcc37 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -64,7 +64,7 @@ public: void set_enable_return_value(bool p_enable); bool is_return_value_enabled() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptReturn(); }; @@ -91,7 +91,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptCondition(); }; @@ -118,7 +118,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptWhile(); }; @@ -145,7 +145,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptIterator(); }; @@ -177,7 +177,7 @@ public: void set_steps(int p_steps); int get_steps() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSequence(); }; @@ -220,7 +220,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSwitch(); }; @@ -258,7 +258,7 @@ public: virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptTypeCast(); }; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 9310b86627..8f7b514881 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -513,19 +513,19 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "singleton") { if (call_mode != CALL_MODE_SINGLETON) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { List<Engine::Singleton> names; Engine::get_singleton()->get_singletons(&names); @@ -543,7 +543,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -614,7 +614,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } if (mc == 0) { - property.usage = 0; //do not show + property.usage = PROPERTY_USAGE_NONE; //do not show } else { property.hint_string = "0," + itos(mc) + ",1"; } @@ -622,7 +622,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (property.name == "rpc_call_mode") { if (call_mode == CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -737,20 +737,22 @@ public: } int to_id = 0; - bool reliable = true; + //bool reliable = true; if (rpc_mode >= VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) { to_id = *p_args[0]; p_args += 1; p_argcount -= 1; - if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { - reliable = false; - } - } else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) { - reliable = false; + //if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { + //reliable = false; + //} } + //else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) { + //reliable = false; + //} - node->rpcp(to_id, !reliable, function, p_args, p_argcount); + // TODO reliable? + node->rpcp(to_id, function, p_args, p_argcount); return true; } @@ -854,7 +856,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptFunctionCall::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptFunctionCall::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceFunctionCall *instance = memnew(VisualScriptNodeInstanceFunctionCall); instance->node = this; instance->instance = p_instance; @@ -889,7 +891,7 @@ VisualScriptFunctionCall::VisualScriptFunctionCall() { template <VisualScriptFunctionCall::CallMode cmode> static Ref<VisualScriptNode> create_function_call_node(const String &p_name) { Ref<VisualScriptFunctionCall> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } @@ -1276,19 +1278,19 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -1350,7 +1352,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { property.hint_string = options; property.type = Variant::STRING; if (options == "") { - property.usage = 0; //hide if type has no usable index + property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index } } } @@ -1585,7 +1587,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptPropertySet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptPropertySet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePropertySet *instance = memnew(VisualScriptNodeInstancePropertySet); instance->node = this; instance->instance = p_instance; @@ -1616,7 +1618,7 @@ VisualScriptPropertySet::VisualScriptPropertySet() { template <VisualScriptPropertySet::CallMode cmode> static Ref<VisualScriptNode> create_property_set_node(const String &p_name) { Ref<VisualScriptPropertySet> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } @@ -1954,19 +1956,19 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -2027,7 +2029,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { property.hint_string = options; property.type = Variant::STRING; if (options == "") { - property.usage = 0; //hide if type has no usable index + property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index } } } @@ -2173,7 +2175,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptPropertyGet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptPropertyGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePropertyGet *instance = memnew(VisualScriptNodeInstancePropertyGet); instance->node = this; instance->instance = p_instance; @@ -2195,7 +2197,7 @@ VisualScriptPropertyGet::VisualScriptPropertyGet() { template <VisualScriptPropertyGet::CallMode cmode> static Ref<VisualScriptNode> create_property_get_node(const String &p_name) { Ref<VisualScriptPropertyGet> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } @@ -2319,7 +2321,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptEmitSignal::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptEmitSignal::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEmitSignal *instance = memnew(VisualScriptNodeInstanceEmitSignal); instance->node = this; instance->instance = p_instance; @@ -2338,7 +2340,7 @@ static Ref<VisualScriptNode> create_basic_type_call_node(const String &p_name) { String method = path[3]; Ref<VisualScriptFunctionCall> node; - node.instance(); + node.instantiate(); Variant::Type type = Variant::VARIANT_MAX; diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 2ff9b7a981..eb17be1fbe 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -125,7 +125,7 @@ public: void set_rpc_call_mode(RPCCallMode p_mode); RPCCallMode get_rpc_call_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -231,7 +231,7 @@ public: void set_assign_op(AssignOp p_op); AssignOp get_assign_op() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; VisualScriptPropertySet(); @@ -314,7 +314,7 @@ public: void set_index(const StringName &p_type); StringName get_index() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptPropertyGet(); }; @@ -351,7 +351,7 @@ public: void set_signal(const StringName &p_type); StringName get_signal() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptEmitSignal(); }; diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index fed6637acb..b93c710652 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -296,7 +296,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptFunction::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptFunction::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceFunction *instance = memnew(VisualScriptNodeInstanceFunction); instance->node = this; instance->instance = p_instance; @@ -791,7 +791,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptComposeArray::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptComposeArray::instantiate(VisualScriptInstance *p_instance) { VisualScriptComposeArrayNode *instance = memnew(VisualScriptComposeArrayNode); instance->input_count = inputports.size(); return instance; @@ -912,73 +912,135 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const { return pinfo; } -static const char *op_names[] = { - //comparison - "Are Equal", //OP_EQUAL, - "Are Not Equal", //OP_NOT_EQUAL, - "Less Than", //OP_LESS, - "Less Than or Equal", //OP_LESS_EQUAL, - "Greater Than", //OP_GREATER, - "Greater Than or Equal", //OP_GREATER_EQUAL, - //mathematic - "Add", //OP_ADD, - "Subtract", //OP_SUBTRACT, - "Multiply", //OP_MULTIPLY, - "Divide", //OP_DIVIDE, - "Negate", //OP_NEGATE, - "Positive", //OP_POSITIVE, - "Remainder", //OP_MODULE, - "Concatenate", //OP_STRING_CONCAT, - //bitwise - "Bit Shift Left", //OP_SHIFT_LEFT, - "Bit Shift Right", //OP_SHIFT_RIGHT, - "Bit And", //OP_BIT_AND, - "Bit Or", //OP_BIT_OR, - "Bit Xor", //OP_BIT_XOR, - "Bit Negate", //OP_BIT_NEGATE, - //logic - "And", //OP_AND, - "Or", //OP_OR, - "Xor", //OP_XOR, - "Not", //OP_NOT, - //containment - "In", //OP_IN, -}; - String VisualScriptOperator::get_caption() const { - static const char32_t *op_names[] = { - //comparison - U"A = B", //OP_EQUAL, - U"A \u2260 B", //OP_NOT_EQUAL, - U"A < B", //OP_LESS, - U"A \u2264 B", //OP_LESS_EQUAL, - U"A > B", //OP_GREATER, - U"A \u2265 B", //OP_GREATER_EQUAL, - //mathematic - U"A + B", //OP_ADD, - U"A - B", //OP_SUBTRACT, - U"A \u00D7 B", //OP_MULTIPLY, - U"A \u00F7 B", //OP_DIVIDE, - U"\u00AC A", //OP_NEGATE, - U"+ A", //OP_POSITIVE, - U"A mod B", //OP_MODULE, - U"A .. B", //OP_STRING_CONCAT, - //bitwise - U"A << B", //OP_SHIFT_LEFT, - U"A >> B", //OP_SHIFT_RIGHT, - U"A & B", //OP_BIT_AND, - U"A | B", //OP_BIT_OR, - U"A ^ B", //OP_BIT_XOR, - U"~A", //OP_BIT_NEGATE, - //logic - U"A and B", //OP_AND, - U"A or B", //OP_OR, - U"A xor B", //OP_XOR, - U"not A", //OP_NOT, - U"A in B", //OP_IN, - - }; - return op_names[op]; + switch (op) { + // comparison + case Variant::OP_EQUAL: + return U"A = B"; + case Variant::OP_NOT_EQUAL: + return U"A \u2260 B"; + case Variant::OP_LESS: + return U"A < B"; + case Variant::OP_LESS_EQUAL: + return U"A \u2264 B"; + case Variant::OP_GREATER: + return U"A > B"; + case Variant::OP_GREATER_EQUAL: + return U"A \u2265 B"; + + // mathematic + case Variant::OP_ADD: + return U"A + B"; + case Variant::OP_SUBTRACT: + return U"A - B"; + case Variant::OP_MULTIPLY: + return U"A \u00D7 B"; + case Variant::OP_DIVIDE: + return U"A \u00F7 B"; + case Variant::OP_NEGATE: + return U"\u00AC A"; + case Variant::OP_POSITIVE: + return U"+ A"; + case Variant::OP_MODULE: + return U"A mod B"; + + // bitwise + case Variant::OP_SHIFT_LEFT: + return U"A << B"; + case Variant::OP_SHIFT_RIGHT: + return U"A >> B"; + case Variant::OP_BIT_AND: + return U"A & B"; + case Variant::OP_BIT_OR: + return U"A | B"; + case Variant::OP_BIT_XOR: + return U"A ^ B"; + case Variant::OP_BIT_NEGATE: + return U"~A"; + + // logic + case Variant::OP_AND: + return U"A and B"; + case Variant::OP_OR: + return U"A or B"; + case Variant::OP_XOR: + return U"A xor B"; + case Variant::OP_NOT: + return U"not A"; + case Variant::OP_IN: + return U"A in B"; + + default: { + ERR_FAIL_V_MSG( + U"Unknown node", + U"Unknown node type encountered, caption not available."); + } + } +} + +String VisualScriptOperator::get_operator_name(Variant::Operator p_op) { + switch (p_op) { + // comparison + case Variant::OP_EQUAL: + return "Are Equal"; + case Variant::OP_NOT_EQUAL: + return "Are Not Equal"; + case Variant::OP_LESS: + return "Less Than"; + case Variant::OP_LESS_EQUAL: + return "Less Than or Equal"; + case Variant::OP_GREATER: + return "Greater Than"; + case Variant::OP_GREATER_EQUAL: + return "Greater Than or Equal"; + + // mathematic + case Variant::OP_ADD: + return "Add"; + case Variant::OP_SUBTRACT: + return "Subtract"; + case Variant::OP_MULTIPLY: + return "Multiply"; + case Variant::OP_DIVIDE: + return "Divide"; + case Variant::OP_NEGATE: + return "Negate"; + case Variant::OP_POSITIVE: + return "Positive"; + case Variant::OP_MODULE: + return "Remainder"; + + // bitwise + case Variant::OP_SHIFT_LEFT: + return "Bit Shift Left"; + case Variant::OP_SHIFT_RIGHT: + return "Bit Shift Right"; + case Variant::OP_BIT_AND: + return "Bit And"; + case Variant::OP_BIT_OR: + return "Bit Or"; + case Variant::OP_BIT_XOR: + return "Bit Xor"; + case Variant::OP_BIT_NEGATE: + return "Bit Negate"; + + // logic + case Variant::OP_AND: + return "And"; + case Variant::OP_OR: + return "Or"; + case Variant::OP_XOR: + return "Xor"; + case Variant::OP_NOT: + return "Not"; + case Variant::OP_IN: + return "In"; + + default: { + ERR_FAIL_INDEX_V(p_op, Variant::OP_MAX, ""); + return "Unknown Operator"; + } + } } void VisualScriptOperator::set_operator(Variant::Operator p_op) { @@ -1018,7 +1080,7 @@ void VisualScriptOperator::_bind_methods() { if (i > 0) { types += ","; } - types += op_names[i]; + types += get_operator_name(static_cast<Variant::Operator>(i)); } String argt = "Any"; @@ -1051,9 +1113,9 @@ public: r_error_str = *p_outputs[0]; } else { if (unary) { - r_error_str = String(op_names[op]) + RTR(": Invalid argument of type: ") + Variant::get_type_name(p_inputs[0]->get_type()); + r_error_str = String(Variant::get_operator_name(op)) + RTR(": Invalid argument of type: ") + Variant::get_type_name(p_inputs[0]->get_type()); } else { - r_error_str = String(op_names[op]) + RTR(": Invalid arguments: ") + "A: " + Variant::get_type_name(p_inputs[0]->get_type()) + " B: " + Variant::get_type_name(p_inputs[1]->get_type()); + r_error_str = String(Variant::get_operator_name(op)) + RTR(": Invalid arguments: ") + "A: " + Variant::get_type_name(p_inputs[0]->get_type()) + " B: " + Variant::get_type_name(p_inputs[1]->get_type()); } } } @@ -1062,7 +1124,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptOperator::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptOperator::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceOperator *instance = memnew(VisualScriptNodeInstanceOperator); instance->unary = get_input_value_port_count() == 1; instance->op = op; @@ -1077,7 +1139,7 @@ VisualScriptOperator::VisualScriptOperator() { template <Variant::Operator OP> static Ref<VisualScriptNode> create_op_node(const String &p_name) { Ref<VisualScriptOperator> node; - node.instance(); + node.instantiate(); node->set_operator(OP); return node; } @@ -1169,7 +1231,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSelect::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSelect::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect); return instance; } @@ -1277,7 +1339,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptVariableGet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptVariableGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceVariableGet *instance = memnew(VisualScriptNodeInstanceVariableGet); instance->node = this; instance->instance = p_instance; @@ -1389,7 +1451,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptVariableSet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptVariableSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceVariableSet *instance = memnew(VisualScriptNodeInstanceVariableSet); instance->node = this; instance->instance = p_instance; @@ -1472,7 +1534,7 @@ void VisualScriptConstant::_validate_property(PropertyInfo &property) const { if (property.name == "value") { property.type = type; if (type == Variant::NIL) { - property.usage = 0; //do not save if nil + property.usage = PROPERTY_USAGE_NONE; //do not save if nil } } } @@ -1504,7 +1566,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceConstant *instance = memnew(VisualScriptNodeInstanceConstant); instance->constant = value; return instance; @@ -1597,7 +1659,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptPreload::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptPreload::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePreload *instance = memnew(VisualScriptNodeInstancePreload); instance->preload = preload; return instance; @@ -1662,7 +1724,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptIndexGet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptIndexGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIndexGet *instance = memnew(VisualScriptNodeInstanceIndexGet); return instance; } @@ -1732,7 +1794,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptIndexSet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptIndexSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIndexSet *instance = memnew(VisualScriptNodeInstanceIndexSet); return instance; } @@ -1798,7 +1860,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptGlobalConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptGlobalConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceGlobalConstant *instance = memnew(VisualScriptNodeInstanceGlobalConstant); instance->index = index; return instance; @@ -1916,7 +1978,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptClassConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptClassConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceClassConstant *instance = memnew(VisualScriptNodeInstanceClassConstant); instance->value = ClassDB::get_integer_constant(base_type, name, &instance->valid); return instance; @@ -2050,7 +2112,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant); instance->value = Variant::get_constant_value(type, name, &instance->valid); return instance; @@ -2062,7 +2124,7 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) c Variant::get_constants_for_type(type, &constants); if (constants.size() == 0) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } property.hint_string = ""; @@ -2174,7 +2236,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptMathConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptMathConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceMathConstant *instance = memnew(VisualScriptNodeInstanceMathConstant); instance->value = const_value[constant]; return instance; @@ -2268,7 +2330,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptEngineSingleton::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptEngineSingleton::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton); instance->singleton = Engine::get_singleton()->get_singleton_object(singleton); return instance; @@ -2394,7 +2456,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSceneNode::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSceneNode::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSceneNode *instance = memnew(VisualScriptNodeInstanceSceneNode); instance->node = this; instance->instance = p_instance; @@ -2574,7 +2636,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSceneTree::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSceneTree::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSceneTree *instance = memnew(VisualScriptNodeInstanceSceneTree); instance->node = this; instance->instance = p_instance; @@ -2655,7 +2717,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptResourcePath::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptResourcePath::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceResourcePath *instance = memnew(VisualScriptNodeInstanceResourcePath); instance->path = path; return instance; @@ -2727,7 +2789,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSelf::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSelf::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSelf *instance = memnew(VisualScriptNodeInstanceSelf); instance->instance = p_instance; return instance; @@ -2908,7 +2970,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptCustomNode::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceCustomNode *instance = memnew(VisualScriptNodeInstanceCustomNode); instance->instance = p_instance; instance->node = this; @@ -3059,7 +3121,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSubCall::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSubCall::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSubCall *instance = memnew(VisualScriptNodeInstanceSubCall); instance->instance = p_instance; Ref<Script> script = get_script(); @@ -3172,7 +3234,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptComment::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptComment::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceComment *instance = memnew(VisualScriptNodeInstanceComment); instance->instance = p_instance; return instance; @@ -3279,7 +3341,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptConstructor::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptConstructor::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceConstructor *instance = memnew(VisualScriptNodeInstanceConstructor); instance->instance = p_instance; instance->type = type; @@ -3308,7 +3370,7 @@ static Ref<VisualScriptNode> create_constructor_node(const String &p_name) { ERR_FAIL_COND_V(!constructor_map.has(p_name), Ref<VisualScriptNode>()); Ref<VisualScriptConstructor> vsc; - vsc.instance(); + vsc.instantiate(); vsc->set_constructor_type(constructor_map[p_name].first); vsc->set_constructor(constructor_map[p_name].second); @@ -3389,7 +3451,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptLocalVar::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptLocalVar::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceLocalVar *instance = memnew(VisualScriptNodeInstanceLocalVar); instance->instance = p_instance; instance->name = name; @@ -3497,7 +3559,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptLocalVarSet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptLocalVarSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceLocalVarSet *instance = memnew(VisualScriptNodeInstanceLocalVarSet); instance->instance = p_instance; instance->name = name; @@ -3634,7 +3696,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptInputAction::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptInputAction::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceInputAction *instance = memnew(VisualScriptNodeInstanceInputAction); instance->instance = p_instance; instance->action = name; @@ -3812,7 +3874,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptDeconstruct::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptDeconstruct::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceDeconstruct *instance = memnew(VisualScriptNodeInstanceDeconstruct); instance->instance = p_instance; instance->outputs.resize(elements.size()); @@ -3849,7 +3911,7 @@ VisualScriptDeconstruct::VisualScriptDeconstruct() { template <Variant::Type T> static Ref<VisualScriptNode> create_node_deconst_typed(const String &p_name) { Ref<VisualScriptDeconstruct> node; - node.instance(); + node.instantiate(); node->set_deconstruct_type(T); return node; } @@ -3918,10 +3980,10 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUAT), create_node_deconst_typed<Variant::Type::QUAT>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUATERNION), create_node_deconst_typed<Variant::Type::QUATERNION>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::AABB), create_node_deconst_typed<Variant::Type::AABB>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::BASIS), create_node_deconst_typed<Variant::Type::BASIS>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM), create_node_deconst_typed<Variant::Type::TRANSFORM>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM3D), create_node_deconst_typed<Variant::Type::TRANSFORM3D>); VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>); for (int i = 1; i < Variant::VARIANT_MAX; i++) { diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 7392443e4e..b599b92b3a 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -97,7 +97,7 @@ public: void set_rpc_mode(MultiplayerAPI::RPCMode p_mode); MultiplayerAPI::RPCMode get_rpc_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual void reset_state() override; @@ -192,7 +192,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "functions"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptComposeArray(); }; @@ -227,7 +227,9 @@ public: void set_typed(Variant::Type p_op); Variant::Type get_typed() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + static String get_operator_name(Variant::Operator p_op); + + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptOperator(); }; @@ -259,7 +261,7 @@ public: void set_typed(Variant::Type p_op); Variant::Type get_typed() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSelect(); }; @@ -291,7 +293,7 @@ public: void set_variable(StringName p_variable); StringName get_variable() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptVariableGet(); }; @@ -323,7 +325,7 @@ public: void set_variable(StringName p_variable); StringName get_variable() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptVariableSet(); }; @@ -359,7 +361,7 @@ public: void set_constant_value(Variant p_value); Variant get_constant_value() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptConstant(); }; @@ -390,7 +392,7 @@ public: void set_preload(const Ref<Resource> &p_preload); Ref<Resource> get_preload() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptPreload(); }; @@ -413,7 +415,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "operators"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptIndexGet(); }; @@ -436,7 +438,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "operators"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptIndexSet(); }; @@ -466,7 +468,7 @@ public: void set_global_constant(int p_which); int get_global_constant(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptGlobalConstant(); }; @@ -502,7 +504,7 @@ public: void set_base_type(const StringName &p_which); StringName get_base_type(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptClassConstant(); }; @@ -539,7 +541,7 @@ public: void set_basic_type(Variant::Type p_which); Variant::Type get_basic_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptBasicTypeConstant(); }; @@ -586,7 +588,7 @@ public: void set_math_constant(MathConstant p_which); MathConstant get_math_constant(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptMathConstant(); }; @@ -621,7 +623,7 @@ public: void set_singleton(const String &p_string); String get_singleton(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -655,7 +657,7 @@ public: void set_node_path(const NodePath &p_path); NodePath get_node_path(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -684,7 +686,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "data"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -717,7 +719,7 @@ public: void set_resource_path(const String &p_path); String get_resource_path(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptResourcePath(); }; @@ -743,7 +745,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "data"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -788,7 +790,7 @@ public: virtual String get_text() const override; virtual String get_category() const override; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; void _script_changed(); @@ -819,7 +821,7 @@ public: virtual String get_text() const override; virtual String get_category() const override; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSubCall(); }; @@ -859,7 +861,7 @@ public: void set_size(const Size2 &p_size); Size2 get_size() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptComment(); }; @@ -894,7 +896,7 @@ public: void set_constructor(const Dictionary &p_info); Dictionary get_constructor() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptConstructor(); }; @@ -929,7 +931,7 @@ public: void set_var_type(Variant::Type p_type); Variant::Type get_var_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptLocalVar(); }; @@ -965,7 +967,7 @@ public: void set_var_type(Variant::Type p_type); Variant::Type get_var_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptLocalVarSet(); }; @@ -1010,7 +1012,7 @@ public: void set_action_mode(Mode p_mode); Mode get_action_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptInputAction(); }; @@ -1056,7 +1058,7 @@ public: void set_deconstruct_type(Variant::Type p_type); Variant::Type get_deconstruct_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptDeconstruct(); }; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index 862cac5c67..79addc5828 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -59,7 +59,7 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) { search_box->accept_event(); TreeItem *root = search_options->get_root(); - if (!root->get_children()) { + if (!root->get_first_child()) { break; } @@ -108,10 +108,10 @@ void VisualScriptPropertySelector::_update_search() { vbc->get_theme_icon("Vector3", "EditorIcons"), vbc->get_theme_icon("Transform2D", "EditorIcons"), vbc->get_theme_icon("Plane", "EditorIcons"), - vbc->get_theme_icon("Quat", "EditorIcons"), + vbc->get_theme_icon("Quaternion", "EditorIcons"), vbc->get_theme_icon("AABB", "EditorIcons"), vbc->get_theme_icon("Basis", "EditorIcons"), - vbc->get_theme_icon("Transform", "EditorIcons"), + vbc->get_theme_icon("Transform3D", "EditorIcons"), vbc->get_theme_icon("Color", "EditorIcons"), vbc->get_theme_icon("Path", "EditorIcons"), vbc->get_theme_icon("RID", "EditorIcons"), @@ -265,7 +265,7 @@ void VisualScriptPropertySelector::_update_search() { item->set_metadata(2, connecting); } - if (category && category->get_children() == nullptr) { + if (category && category->get_first_child() == nullptr) { memdelete(category); //old category was unused } } @@ -310,7 +310,7 @@ void VisualScriptPropertySelector::_update_search() { found = true; } - get_ok_button()->set_disabled(root->get_children() == nullptr); + get_ok_button()->set_disabled(root->get_first_child() == nullptr); } void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) { @@ -469,10 +469,11 @@ void VisualScriptPropertySelector::_item_selected() { at_class = ClassDB::get_parent_class_nocheck(at_class); } - Map<String, DocData::ClassDoc>::Element *T = dd->class_list.find(class_type); + Vector<String> functions = name.rsplit("/", false); + at_class = functions.size() > 3 ? functions[functions.size() - 2] : class_type; + Map<String, DocData::ClassDoc>::Element *T = dd->class_list.find(at_class); if (T) { for (int i = 0; i < T->get().methods.size(); i++) { - Vector<String> functions = name.rsplit("/", false, 1); if (T->get().methods[i].name == functions[functions.size() - 1]) { text = DTR(T->get().methods[i].description); } diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 52fe659983..d8bc926a1d 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -113,7 +113,7 @@ public: } Ref<VisualScriptFunctionState> state; - state.instance(); + state.instantiate(); int ret = STEP_YIELD_BIT; switch (mode) { @@ -138,7 +138,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptYield::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptYield::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceYield *instance = memnew(VisualScriptNodeInstanceYield); //instance->instance=p_instance; instance->mode = yield_mode; @@ -174,7 +174,7 @@ float VisualScriptYield::get_wait_time() { void VisualScriptYield::_validate_property(PropertyInfo &property) const { if (property.name == "wait_time") { if (yield_mode != YIELD_WAIT) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -202,7 +202,7 @@ VisualScriptYield::VisualScriptYield() { template <VisualScriptYield::YieldMode MODE> static Ref<VisualScriptNode> create_yield_node(const String &p_name) { Ref<VisualScriptYield> node; - node.instance(); + node.instantiate(); node->set_yield_mode(MODE); return node; } @@ -421,7 +421,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -548,7 +548,7 @@ public: } Ref<VisualScriptFunctionState> state; - state.instance(); + state.instantiate(); state->connect_to_signal(object, signal, Array()); @@ -559,7 +559,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptYieldSignal::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptYieldSignal::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceYieldSignal *instance = memnew(VisualScriptNodeInstanceYieldSignal); instance->node = this; instance->instance = p_instance; @@ -578,7 +578,7 @@ VisualScriptYieldSignal::VisualScriptYieldSignal() { template <VisualScriptYieldSignal::CallMode cmode> static Ref<VisualScriptNode> create_yield_signal_node(const String &p_name) { Ref<VisualScriptYieldSignal> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index cc7ce0a1c6..fa596173a6 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -76,7 +76,7 @@ public: void set_wait_time(float p_time); float get_wait_time(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptYield(); }; @@ -135,7 +135,7 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptYieldSignal(); }; diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub index 67d3f1bebd..4334cf732b 100644 --- a/modules/webm/libvpx/SCsub +++ b/modules/webm/libvpx/SCsub @@ -235,7 +235,7 @@ if env["platform"] == "uwp": else: import platform - is_x11_or_server_arm = (env["platform"] == "linuxbsd" or env["platform"] == "server") and ( + 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")) @@ -314,12 +314,7 @@ if webm_cpu_x86: 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" - or env["platform"] == "server" - ): + 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" diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp index 82157a71c9..8f690a6892 100644 --- a/modules/webm/register_types.cpp +++ b/modules/webm/register_types.cpp @@ -35,10 +35,10 @@ static Ref<ResourceFormatLoaderWebm> resource_loader_webm; void register_webm_types() { - resource_loader_webm.instance(); + resource_loader_webm.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_webm, true); - ClassDB::register_class<VideoStreamWebm>(); + GDREGISTER_CLASS(VideoStreamWebm); } void unregister_webm_types() { diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index 101001cba0..12e0f5bd25 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -31,7 +31,7 @@ #include "video_stream_webm.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "servers/audio_server.h" @@ -62,10 +62,10 @@ public: virtual int Read(long long pos, long len, unsigned char *buf) { if (file) { - if (file->get_position() != (size_t)pos) { + if (file->get_position() != (uint64_t)pos) { file->seek(pos); } - if (file->get_buffer(buf, len) == len) { + if (file->get_buffer(buf, len) == (uint64_t)len) { return 0; } } @@ -74,7 +74,7 @@ public: virtual int Length(long long *total, long long *available) { if (file) { - const size_t len = file->get_len(); + const uint64_t len = file->get_length(); if (total) { *total = len; } @@ -116,7 +116,7 @@ bool VideoStreamPlaybackWebm::open_file(const String &p_file) { frame_data.resize((webm->getWidth() * webm->getHeight()) << 2); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(webm->getWidth(), webm->getHeight(), false, Image::FORMAT_RGBA8); texture->create_from_image(img); @@ -194,7 +194,7 @@ float VideoStreamPlaybackWebm::get_playback_position() const { } void VideoStreamPlaybackWebm::seek(float p_time) { - //Not implemented + 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) { diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index b304c4824f..5bebad2b53 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -30,6 +30,7 @@ #include "image_loader_webp.h" +#include "core/config/project_settings.h" #include "core/io/marshalls.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -68,13 +69,78 @@ static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quali w[1] = 'E'; w[2] = 'B'; w[3] = 'P'; - copymem(&w[4], dst_buff, dst_size); - free(dst_buff); + memcpy(&w[4], dst_buff, dst_size); + WebPFree(dst_buff); return dst; } -static Ref<Image> _webp_lossy_unpack(const Vector<uint8_t> &p_buffer) { +static Vector<uint8_t> _webp_lossless_pack(const Ref<Image> &p_image) { + ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>()); + + int compression_level = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/webp_compression_level"); + compression_level = CLAMP(compression_level, 0, 9); + + Ref<Image> img = p_image->duplicate(); + if (img->detect_alpha()) { + img->convert(Image::FORMAT_RGBA8); + } else { + img->convert(Image::FORMAT_RGB8); + } + + Size2 s(img->get_width(), img->get_height()); + Vector<uint8_t> data = img->get_data(); + const uint8_t *r = data.ptr(); + + // we need to use the more complex API in order to access the 'exact' flag... + + WebPConfig config; + WebPPicture pic; + if (!WebPConfigInit(&config) || !WebPConfigLosslessPreset(&config, compression_level) || !WebPPictureInit(&pic)) { + ERR_FAIL_V(Vector<uint8_t>()); + } + + WebPMemoryWriter wrt; + config.exact = 1; + pic.use_argb = 1; + pic.width = s.width; + pic.height = s.height; + pic.writer = WebPMemoryWrite; + pic.custom_ptr = &wrt; + WebPMemoryWriterInit(&wrt); + + bool success_import = false; + if (img->get_format() == Image::FORMAT_RGB8) { + success_import = WebPPictureImportRGB(&pic, r, 3 * s.width); + } else { + success_import = WebPPictureImportRGBA(&pic, r, 4 * s.width); + } + bool success_encode = false; + if (success_import) { + success_encode = WebPEncode(&config, &pic); + } + WebPPictureFree(&pic); + + if (!success_encode) { + WebPMemoryWriterClear(&wrt); + ERR_FAIL_V_MSG(Vector<uint8_t>(), "WebP packing failed."); + } + + // copy from wrt + Vector<uint8_t> dst; + dst.resize(4 + wrt.size); + uint8_t *w = dst.ptrw(); + w[0] = 'W'; + w[1] = 'E'; + w[2] = 'B'; + w[3] = 'P'; + memcpy(&w[4], wrt.mem, wrt.size); + WebPMemoryWriterClear(&wrt); + + return dst; +} + +static Ref<Image> _webp_unpack(const Vector<uint8_t> &p_buffer) { int size = p_buffer.size() - 4; ERR_FAIL_COND_V(size <= 0, Ref<Image>()); const uint8_t *r = p_buffer.ptr(); @@ -139,7 +205,7 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = webp_load_image_from_buffer(img.ptr(), p_png, p_size); ERR_FAIL_COND_V(err, Ref<Image>()); return img; @@ -147,7 +213,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; - int src_image_len = f->get_len(); + uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); src_image.resize(src_image_len); @@ -168,6 +234,7 @@ void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) cons ImageLoaderWEBP::ImageLoaderWEBP() { Image::_webp_mem_loader_func = _webp_mem_loader_func; - Image::lossy_packer = _webp_lossy_pack; - Image::lossy_unpacker = _webp_lossy_unpack; + Image::webp_lossy_packer = _webp_lossy_pack; + Image::webp_lossless_packer = _webp_lossless_pack; + Image::webp_unpacker = _webp_unpack; } diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py index 0a075ccef1..3281415f38 100644 --- a/modules/webrtc/config.py +++ b/modules/webrtc/config.py @@ -10,7 +10,7 @@ def get_doc_classes(): return [ "WebRTCPeerConnection", "WebRTCDataChannel", - "WebRTCMultiplayer", + "WebRTCMultiplayerPeer", ] diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 5b9459bc27..26c5bfa6ce 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCMultiplayer" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> A simple interface to create a peer-to-peer mesh network composed of [WebRTCPeerConnection] that is compatible with the [MultiplayerAPI]. </brief_description> <description> This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.network_peer]. You can add each [WebRTCPeerConnection] via [method add_peer] or remove them via [method remove_peer]. Peers must be added in [constant WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate channels. This class will not create offers nor set descriptions, it will only poll them, and notify connections and disconnections. - [signal NetworkedMultiplayerPeer.connection_succeeded] and [signal NetworkedMultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [NetworkedMultiplayerPeer]. + [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [MultiplayerPeer]. </description> <tutorials> </tutorials> @@ -66,8 +66,8 @@ </argument> <description> Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647). - If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant NetworkedMultiplayerPeer.CONNECTION_CONNECTED] and [signal NetworkedMultiplayerPeer.connection_succeeded] will not be emitted. - If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal NetworkedMultiplayerPeer.peer_connected] signals until a peer with id [constant NetworkedMultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal NetworkedMultiplayerPeer.connection_succeeded]. After that the signal [signal NetworkedMultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal NetworkedMultiplayerPeer.server_disconnected] will be emitted and state will become [constant NetworkedMultiplayerPeer.CONNECTION_CONNECTED]. + If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted. + If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal MultiplayerPeer.peer_connected] signals until a peer with id [constant MultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal MultiplayerPeer.connection_succeeded]. After that the signal [signal MultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal MultiplayerPeer.server_disconnected] will be emitted and state will become [constant MultiplayerPeer.CONNECTION_CONNECTED]. </description> </method> <method name="remove_peer"> @@ -76,13 +76,13 @@ <argument index="0" name="peer_id" type="int"> </argument> <description> - Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal NetworkedMultiplayerPeer.peer_connected] was emitted for it, then [signal NetworkedMultiplayerPeer.peer_disconnected] will be emitted. + Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal MultiplayerPeer.peer_connected] was emitted for it, then [signal MultiplayerPeer.peer_disconnected] will be emitted. </description> </method> </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> </members> <constants> </constants> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index e21dee8eff..62e524825d 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCPeerConnection" inherits="Reference" version="4.0"> +<class name="WebRTCPeerConnection" inherits="RefCounted" version="4.0"> <brief_description> Interface to a WebRTC peer connection. </brief_description> @@ -48,7 +48,7 @@ Valid [code]options[/code] are: [codeblock] { - "negotiated": true, # When set to true (default off), means the channel is negotiated out of band. "id" must be set too. data_channel_received will not be called. + "negotiated": true, # When set to true (default off), means the channel is negotiated out of band. "id" must be set too. "data_channel_received" will not be called. "id": 1, # When "negotiated" is true this value must also be set to the same value on both peer. # Only one of maxRetransmits and maxPacketLifeTime can be specified, not both. They make the channel unreliable (but also better at real time). diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp index ecfaed9089..63ecc03a4c 100644 --- a/modules/webrtc/register_types.cpp +++ b/modules/webrtc/register_types.cpp @@ -41,7 +41,7 @@ #include "webrtc_data_channel_gdnative.h" #include "webrtc_peer_connection_gdnative.h" #endif -#include "webrtc_multiplayer.h" +#include "webrtc_multiplayer_peer.h" void register_webrtc_types() { #define _SET_HINT(NAME, _VAL_, _MAX_) \ @@ -58,11 +58,11 @@ void register_webrtc_types() { ClassDB::register_custom_instance_class<WebRTCPeerConnection>(); #ifdef WEBRTC_GDNATIVE_ENABLED - ClassDB::register_class<WebRTCPeerConnectionGDNative>(); - ClassDB::register_class<WebRTCDataChannelGDNative>(); + GDREGISTER_CLASS(WebRTCPeerConnectionGDNative); + GDREGISTER_CLASS(WebRTCDataChannelGDNative); #endif - ClassDB::register_virtual_class<WebRTCDataChannel>(); - ClassDB::register_class<WebRTCMultiplayer>(); + GDREGISTER_VIRTUAL_CLASS(WebRTCDataChannel); + GDREGISTER_CLASS(WebRTCMultiplayerPeer); } void unregister_webrtc_types() {} diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp index d4cf464c7c..f3009dde2f 100644 --- a/modules/webrtc/webrtc_data_channel_gdnative.cpp +++ b/modules/webrtc/webrtc_data_channel_gdnative.cpp @@ -31,6 +31,7 @@ #ifdef WEBRTC_GDNATIVE_ENABLED #include "webrtc_data_channel_gdnative.h" + #include "core/io/resource_loader.h" #include "modules/gdnative/nativescript/nativescript.h" diff --git a/modules/webrtc/webrtc_multiplayer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 741cad5640..ac75f9e860 100644 --- a/modules/webrtc/webrtc_multiplayer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_multiplayer.cpp */ +/* webrtc_multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,43 +28,43 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "webrtc_multiplayer.h" +#include "webrtc_multiplayer_peer.h" #include "core/io/marshalls.h" #include "core/os/os.h" -void WebRTCMultiplayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayer::initialize, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayer::add_peer, DEFVAL(1)); - ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayer::remove_peer); - ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayer::has_peer); - ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayer::get_peer); - ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayer::get_peers); - ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayer::close); +void WebRTCMultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1)); + ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer); + ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer); + ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayerPeer::get_peer); + ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayerPeer::get_peers); + ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } -void WebRTCMultiplayer::set_transfer_mode(TransferMode p_mode) { +void WebRTCMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } -NetworkedMultiplayerPeer::TransferMode WebRTCMultiplayer::get_transfer_mode() const { +MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_transfer_mode() const { return transfer_mode; } -void WebRTCMultiplayer::set_target_peer(int p_peer_id) { +void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) { target_peer = p_peer_id; } -/* Returns the ID of the NetworkedMultiplayerPeer who sent the most recent packet: */ -int WebRTCMultiplayer::get_packet_peer() const { +/* Returns the ID of the MultiplayerPeer who sent the most recent packet: */ +int WebRTCMultiplayerPeer::get_packet_peer() const { return next_packet_peer; } -bool WebRTCMultiplayer::is_server() const { +bool WebRTCMultiplayerPeer::is_server() const { return unique_id == TARGET_PEER_SERVER; } -void WebRTCMultiplayer::poll() { +void WebRTCMultiplayerPeer::poll() { if (peer_map.size() == 0) { return; } @@ -147,7 +147,7 @@ void WebRTCMultiplayer::poll() { } } -void WebRTCMultiplayer::_find_next_peer() { +void WebRTCMultiplayerPeer::_find_next_peer() { Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer); if (E) { E = E->next(); @@ -180,19 +180,19 @@ void WebRTCMultiplayer::_find_next_peer() { next_packet_peer = 0; } -void WebRTCMultiplayer::set_refuse_new_connections(bool p_enable) { +void WebRTCMultiplayerPeer::set_refuse_new_connections(bool p_enable) { refuse_connections = p_enable; } -bool WebRTCMultiplayer::is_refusing_new_connections() const { +bool WebRTCMultiplayerPeer::is_refusing_new_connections() const { return refuse_connections; } -NetworkedMultiplayerPeer::ConnectionStatus WebRTCMultiplayer::get_connection_status() const { +MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() const { return connection_status; } -Error WebRTCMultiplayer::initialize(int p_self_id, bool p_server_compat) { +Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat) { ERR_FAIL_COND_V(p_self_id < 0 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); unique_id = p_self_id; server_compat = p_server_compat; @@ -206,12 +206,12 @@ Error WebRTCMultiplayer::initialize(int p_self_id, bool p_server_compat) { return OK; } -int WebRTCMultiplayer::get_unique_id() const { +int WebRTCMultiplayerPeer::get_unique_id() const { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, 1); return unique_id; } -void WebRTCMultiplayer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { +void WebRTCMultiplayerPeer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { Array channels; for (List<Ref<WebRTCDataChannel>>::Element *F = p_connected_peer->channels.front(); F; F = F->next()) { channels.push_back(F->get()); @@ -221,18 +221,18 @@ void WebRTCMultiplayer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dicti r_dict["channels"] = channels; } -bool WebRTCMultiplayer::has_peer(int p_peer_id) { +bool WebRTCMultiplayerPeer::has_peer(int p_peer_id) { return peer_map.has(p_peer_id); } -Dictionary WebRTCMultiplayer::get_peer(int p_peer_id) { +Dictionary WebRTCMultiplayerPeer::get_peer(int p_peer_id) { ERR_FAIL_COND_V(!peer_map.has(p_peer_id), Dictionary()); Dictionary out; _peer_to_dict(peer_map[p_peer_id], out); return out; } -Dictionary WebRTCMultiplayer::get_peers() { +Dictionary WebRTCMultiplayerPeer::get_peers() { Dictionary out; for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) { Dictionary d; @@ -242,7 +242,7 @@ Dictionary WebRTCMultiplayer::get_peers() { return out; } -Error WebRTCMultiplayer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { +Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(refuse_connections, ERR_UNAUTHORIZED); @@ -277,7 +277,7 @@ Error WebRTCMultiplayer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_i return OK; } -void WebRTCMultiplayer::remove_peer(int p_peer_id) { +void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) { ERR_FAIL_COND(!peer_map.has(p_peer_id)); Ref<ConnectedPeer> peer = peer_map[p_peer_id]; peer_map.erase(p_peer_id); @@ -291,7 +291,7 @@ void WebRTCMultiplayer::remove_peer(int p_peer_id) { } } -Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { +Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { // Peer not available if (next_packet_peer == 0 || !peer_map.has(next_packet_peer)) { _find_next_peer(); @@ -309,7 +309,7 @@ Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size ERR_FAIL_V(ERR_BUG); } -Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { +Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED); int ch = CH_RELIABLE; @@ -351,7 +351,7 @@ Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size) return OK; } -int WebRTCMultiplayer::get_available_packet_count() const { +int WebRTCMultiplayerPeer::get_available_packet_count() const { if (next_packet_peer == 0) { return 0; // To be sure next call to get_packet works if size > 0 . } @@ -364,11 +364,11 @@ int WebRTCMultiplayer::get_available_packet_count() const { return size; } -int WebRTCMultiplayer::get_max_packet_size() const { +int WebRTCMultiplayerPeer::get_max_packet_size() const { return 1200; } -void WebRTCMultiplayer::close() { +void WebRTCMultiplayerPeer::close() { peer_map.clear(); unique_id = 0; next_packet_peer = 0; @@ -376,7 +376,7 @@ void WebRTCMultiplayer::close() { connection_status = CONNECTION_DISCONNECTED; } -WebRTCMultiplayer::WebRTCMultiplayer() { +WebRTCMultiplayerPeer::WebRTCMultiplayerPeer() { unique_id = 0; next_packet_peer = 0; target_peer = 0; @@ -387,6 +387,6 @@ WebRTCMultiplayer::WebRTCMultiplayer() { server_compat = false; } -WebRTCMultiplayer::~WebRTCMultiplayer() { +WebRTCMultiplayerPeer::~WebRTCMultiplayerPeer() { close(); } diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 6b4ae6fcc8..1d9387b6dc 100644 --- a/modules/webrtc/webrtc_multiplayer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_multiplayer.h */ +/* webrtc_multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,11 +31,11 @@ #ifndef WEBRTC_MULTIPLAYER_H #define WEBRTC_MULTIPLAYER_H -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "webrtc_peer_connection.h" -class WebRTCMultiplayer : public NetworkedMultiplayerPeer { - GDCLASS(WebRTCMultiplayer, NetworkedMultiplayerPeer); +class WebRTCMultiplayerPeer : public MultiplayerPeer { + GDCLASS(WebRTCMultiplayerPeer, MultiplayerPeer); protected: static void _bind_methods(); @@ -48,7 +48,7 @@ private: CH_RESERVED_MAX = 3 }; - class ConnectedPeer : public Reference { + class ConnectedPeer : public RefCounted { public: Ref<WebRTCPeerConnection> connection; List<Ref<WebRTCDataChannel>> channels; @@ -77,8 +77,8 @@ private: void _find_next_peer(); public: - WebRTCMultiplayer(); - ~WebRTCMultiplayer(); + WebRTCMultiplayerPeer(); + ~WebRTCMultiplayerPeer(); Error initialize(int p_self_id, bool p_server_compat = false); Error add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime = 1); @@ -94,7 +94,7 @@ public: int get_available_packet_count() const override; int get_max_packet_size() const override; - // NetworkedMultiplayerPeer + // MultiplayerPeer void set_transfer_mode(TransferMode p_mode) override; TransferMode get_transfer_mode() const override; void set_target_peer(int p_peer_id) override; diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h index ae75864489..fcfb9ae9ae 100644 --- a/modules/webrtc/webrtc_peer_connection.h +++ b/modules/webrtc/webrtc_peer_connection.h @@ -34,8 +34,8 @@ #include "core/io/packet_peer.h" #include "modules/webrtc/webrtc_data_channel.h" -class WebRTCPeerConnection : public Reference { - GDCLASS(WebRTCPeerConnection, Reference); +class WebRTCPeerConnection : public RefCounted { + GDCLASS(WebRTCPeerConnection, RefCounted); public: enum ConnectionState { diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp index 8879f7d6ec..2b63e76358 100644 --- a/modules/webrtc/webrtc_peer_connection_js.cpp +++ b/modules/webrtc/webrtc_peer_connection_js.cpp @@ -34,7 +34,6 @@ #include "webrtc_data_channel_js.h" -#include "core/io/json.h" #include "emscripten.h" void WebRTCPeerConnectionJS::_on_ice_candidate(void *p_obj, const char *p_mid_name, int p_mline_idx, const char *p_candidate) { @@ -100,7 +99,7 @@ Error WebRTCPeerConnectionJS::initialize(Dictionary p_config) { } _conn_state = STATE_NEW; - String config = JSON::print(p_config); + String config = Variant(p_config).to_json_string(); _js_id = godot_js_rtc_pc_create(config.utf8().get_data(), this, &_on_connection_state_changed, &_on_ice_candidate, &_on_data_channel); return _js_id ? OK : FAILED; } @@ -108,7 +107,7 @@ Error WebRTCPeerConnectionJS::initialize(Dictionary p_config) { Ref<WebRTCDataChannel> WebRTCPeerConnectionJS::create_data_channel(String p_channel, Dictionary p_channel_config) { ERR_FAIL_COND_V(_conn_state != STATE_NEW, nullptr); - String config = JSON::print(p_channel_config); + String config = Variant(p_channel_config).to_json_string(); int id = godot_js_rtc_pc_datachannel_create(_js_id, p_channel.utf8().get_data(), config.utf8().get_data()); ERR_FAIL_COND_V(id == 0, nullptr); return memnew(WebRTCDataChannelJS(id)); diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml index 45db49c913..40c0ad17ad 100644 --- a/modules/websocket/doc_classes/WebSocketClient.xml +++ b/modules/websocket/doc_classes/WebSocketClient.xml @@ -6,7 +6,7 @@ <description> This class implements a WebSocket client compatible with any RFC 6455-compliant WebSocket server. This client can be optionally used as a network peer for the [MultiplayerAPI]. - After starting the client ([method connect_to_url]), you will need to [method NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). + After starting the client ([method connect_to_url]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). You will receive appropriate signals when connecting, disconnecting, or when new data is available. </description> <tutorials> @@ -17,17 +17,18 @@ </return> <argument index="0" name="url" type="String"> </argument> - <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()"> </argument> <argument index="2" name="gd_mp_api" type="bool" default="false"> </argument> - <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()"> </argument> <description> Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested. If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a network peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted. If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]). You can optionally pass a list of [code]custom_headers[/code] to be added to the handshake HTTP request. + [b]Note:[/b] To avoid mixed content warnings or errors in HTML5, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's SSL certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the SSL certificate. [b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in HTML5 exports due to browsers restrictions. </description> </method> diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index 0679acf78a..ee1b60f739 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketMultiplayerPeer" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="WebSocketMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> Base class for WebSocket server and client. </brief_description> @@ -39,7 +39,7 @@ </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> </members> <signals> <signal name="peer_packet"> diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index f7805209e2..26e09fd8b3 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -5,7 +5,7 @@ </brief_description> <description> This class implements a WebSocket server that can also support the high-level multiplayer API. - After starting the server ([method listen]), you will need to [method NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal. + After starting the server ([method listen]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal. [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> @@ -63,7 +63,7 @@ </return> <argument index="0" name="port" type="int"> </argument> - <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()"> </argument> <argument index="2" name="gd_mp_api" type="bool" default="false"> </argument> @@ -89,6 +89,9 @@ <member name="ca_chain" type="X509Certificate" setter="set_ca_chain" getter="get_ca_chain"> When using SSL (see [member private_key] and [member ssl_certificate]), you can set this to a valid [X509Certificate] to be provided as additional CA chain information during the SSL handshake. </member> + <member name="handshake_timeout" type="float" setter="set_handshake_timeout" getter="get_handshake_timeout" default="3.0"> + The time in seconds before a pending client (i.e. a client that has not yet finished the HTTP handshake) is considered stale and forcefully disconnected. + </member> <member name="private_key" type="CryptoKey" setter="set_private_key" getter="get_private_key"> When set to a valid [CryptoKey] (along with [member ssl_certificate]) will cause the server to require SSL instead of regular TCP (i.e. the [code]wss://[/code] protocol). </member> diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor_debugger_server_websocket.cpp index b02d212c42..2e61cbfc08 100644 --- a/modules/websocket/editor_debugger_server_websocket.cpp +++ b/modules/websocket/editor_debugger_server_websocket.cpp @@ -50,9 +50,9 @@ void EditorDebuggerServerWebSocket::poll() { Error EditorDebuggerServerWebSocket::start() { int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); - Vector<String> protocols; - protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer. - return server->listen(remote_port, protocols); + Vector<String> compatible_protocols; + compatible_protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer. + return server->listen(remote_port, compatible_protocols); } void EditorDebuggerServerWebSocket::stop() { diff --git a/modules/websocket/editor_debugger_server_websocket.h b/modules/websocket/editor_debugger_server_websocket.h index 2f73b98c3d..d9543bb647 100644 --- a/modules/websocket/editor_debugger_server_websocket.h +++ b/modules/websocket/editor_debugger_server_websocket.h @@ -28,12 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SCRIPT_EDITOR_DEBUGGER_WEBSOCKET_H -#define SCRIPT_EDITOR_DEBUGGER_WEBSOCKET_H - -#include "modules/websocket/websocket_server.h" +#ifndef EDITOR_DEBUGGER_SERVER_WEBSOCKET_H +#define EDITOR_DEBUGGER_SERVER_WEBSOCKET_H #include "editor/debugger/editor_debugger_server.h" +#include "modules/websocket/websocket_server.h" class EditorDebuggerServerWebSocket : public EditorDebuggerServer { GDCLASS(EditorDebuggerServerWebSocket, EditorDebuggerServer); @@ -59,4 +58,4 @@ public: ~EditorDebuggerServerWebSocket(); }; -#endif // SCRIPT_EDITOR_DEBUGGER_WEBSOCKET_H +#endif // EDITOR_DEBUGGER_SERVER_WEBSOCKET_H diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 25b6d6ef0e..744053b6e2 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -107,7 +107,7 @@ Ref<WebSocketPeer> EMWSClient::get_peer(int p_peer_id) const { return _peer; } -NetworkedMultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const { +MultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const { if (_peer->is_connected_to_host()) { if (_is_connecting) return CONNECTION_CONNECTING; @@ -121,8 +121,8 @@ void EMWSClient::disconnect_from_host(int p_code, String p_reason) { _peer->close(p_code, p_reason); } -IP_Address EMWSClient::get_connected_host() const { - ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export."); +IPAddress EMWSClient::get_connected_host() const { + ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export."); } uint16_t EMWSClient::get_connected_port() const { diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h index 2ab7dc83d0..ca2d7ed986 100644 --- a/modules/websocket/emws_client.h +++ b/modules/websocket/emws_client.h @@ -56,7 +56,7 @@ public: Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()); Ref<WebSocketPeer> get_peer(int p_peer_id) const; void disconnect_from_host(int p_code = 1000, String p_reason = ""); - IP_Address get_connected_host() const; + IPAddress get_connected_host() const; uint16_t get_connected_port() const; virtual ConnectionStatus get_connection_status() const; int get_max_packet_size() const; diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index 5e75e10d68..1ad3bdc825 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -93,8 +93,8 @@ void EMWSPeer::close(int p_code, String p_reason) { peer_sock = -1; }; -IP_Address EMWSPeer::get_connected_host() const { - ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export."); +IPAddress EMWSPeer::get_connected_host() const { + ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export."); }; uint16_t EMWSPeer::get_connected_port() const { diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h index abe5bf2bdb..73e701720b 100644 --- a/modules/websocket/emws_peer.h +++ b/modules/websocket/emws_peer.h @@ -73,7 +73,7 @@ public: virtual void close(int p_code = 1000, String p_reason = ""); virtual bool is_connected_to_host() const; - virtual IP_Address get_connected_host() const; + virtual IPAddress get_connected_host() const; virtual uint16_t get_connected_port() const; virtual WriteMode get_write_mode() const; diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp index a35d84f372..4a4f09a943 100644 --- a/modules/websocket/emws_server.cpp +++ b/modules/websocket/emws_server.cpp @@ -58,8 +58,8 @@ Vector<String> EMWSServer::get_protocols() const { return out; } -IP_Address EMWSServer::get_peer_address(int p_peer_id) const { - return IP_Address(); +IPAddress EMWSServer::get_peer_address(int p_peer_id) const { + return IPAddress(); } int EMWSServer::get_peer_port(int p_peer_id) const { diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h index 4179b20ffe..d36e3a3557 100644 --- a/modules/websocket/emws_server.h +++ b/modules/websocket/emws_server.h @@ -33,7 +33,7 @@ #ifdef JAVASCRIPT_ENABLED -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "emws_peer.h" #include "websocket_server.h" @@ -47,7 +47,7 @@ public: bool is_listening() const; bool has_peer(int p_id) const; Ref<WebSocketPeer> get_peer(int p_id) const; - IP_Address get_peer_address(int p_peer_id) const; + IPAddress get_peer_address(int p_peer_id) const; int get_peer_port(int p_peer_id) const; void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); int get_max_packet_size() const; diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h index ed756363cf..e99a379767 100644 --- a/modules/websocket/packet_buffer.h +++ b/modules/websocket/packet_buffer.h @@ -31,7 +31,6 @@ #ifndef PACKET_BUFFER_H #define PACKET_BUFFER_H -#include "core/os/copymem.h" #include "core/templates/ring_buffer.h" template <class T> @@ -66,7 +65,7 @@ public: if (p_info) { _Packet p; p.size = p_size; - copymem(&p.info, p_info, sizeof(T)); + memcpy(&p.info, p_info, sizeof(T)); _packets.write(p); } @@ -86,7 +85,7 @@ public: ERR_FAIL_COND_V(p_bytes < (int)p.size, ERR_OUT_OF_MEMORY); r_read = p.size; - copymem(r_info, &p.info, sizeof(T)); + memcpy(r_info, &p.info, sizeof(T)); _payload.read(r_payload, p.size); return OK; } diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp index 5a02509c4a..7c742b1b89 100644 --- a/modules/websocket/register_types.cpp +++ b/modules/websocket/register_types.cpp @@ -63,7 +63,7 @@ void register_websocket_types() { WSLServer::make_default(); #endif - ClassDB::register_virtual_class<WebSocketMultiplayerPeer>(); + GDREGISTER_VIRTUAL_CLASS(WebSocketMultiplayerPeer); ClassDB::register_custom_instance_class<WebSocketServer>(); ClassDB::register_custom_instance_class<WebSocketClient>(); ClassDB::register_custom_instance_class<WebSocketPeer>(); diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h index 03c60fb480..590d925dcc 100644 --- a/modules/websocket/remote_debugger_peer_websocket.h +++ b/modules/websocket/remote_debugger_peer_websocket.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SCRIPT_DEBUGGER_WEBSOCKET_H -#define SCRIPT_DEBUGGER_WEBSOCKET_H +#ifndef REMOTE_DEBUGGER_PEER_WEBSOCKET_H +#define REMOTE_DEBUGGER_PEER_WEBSOCKET_H #ifdef JAVASCRIPT_ENABLED #include "modules/websocket/emws_client.h" @@ -62,4 +62,4 @@ public: RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer = Ref<WebSocketPeer>()); }; -#endif // SCRIPT_DEBUGGER_WEBSOCKET_H +#endif // REMOTE_DEBUGGER_PEER_WEBSOCKET_H diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp index 425013f811..af1dc8ff54 100644 --- a/modules/websocket/websocket_client.cpp +++ b/modules/websocket/websocket_client.cpp @@ -42,35 +42,22 @@ Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_proto _is_multiplayer = gd_mp_api; String host = p_url; - String path = "/"; - int p_len = -1; - int port = 80; + String path; + String scheme; + int port = 0; + Error err = p_url.parse_url(scheme, host, port, path); + ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url); + bool ssl = false; - if (host.begins_with("wss://")) { - ssl = true; // we should implement this - host = host.substr(6, host.length() - 6); - port = 443; - } else { - ssl = false; - if (host.begins_with("ws://")) { - host = host.substr(5, host.length() - 5); - } + if (scheme == "wss://") { + ssl = true; } - - // Path - p_len = host.find("/"); - if (p_len != -1) { - path = host.substr(p_len, host.length() - p_len); - host = host.substr(0, p_len); + if (port == 0) { + port = ssl ? 443 : 80; } - - // Port - p_len = host.rfind(":"); - if (p_len != -1 && p_len == host.find(":")) { - port = host.substr(p_len, host.length() - p_len).to_int(); - host = host.substr(0, p_len); + if (path.is_empty()) { + path = "/"; } - return connect_to_host(host, path, port, ssl, p_protocols, p_custom_headers); } @@ -139,12 +126,12 @@ void WebSocketClient::_bind_methods() { ClassDB::bind_method(D_METHOD("set_verify_ssl_enabled", "enabled"), &WebSocketClient::set_verify_ssl_enabled); ClassDB::bind_method(D_METHOD("is_verify_ssl_enabled"), &WebSocketClient::is_verify_ssl_enabled); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled"); + 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); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_trusted_ssl_certificate", "get_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"); ADD_SIGNAL(MethodInfo("data_received")); ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol"))); diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h index 0225c9b3d3..c7f17f1ffb 100644 --- a/modules/websocket/websocket_client.h +++ b/modules/websocket/websocket_client.h @@ -57,7 +57,7 @@ public: virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) = 0; virtual void disconnect_from_host(int p_code = 1000, String p_reason = "") = 0; - virtual IP_Address get_connected_host() const = 0; + virtual IPAddress get_connected_host() const = 0; virtual uint16_t get_connected_port() const = 0; virtual bool is_server() const override; diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 758ed66c80..1beeb67b91 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -99,6 +99,8 @@ Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buff _current_packet.data = nullptr; } + ERR_FAIL_COND_V(_incoming_packets.size() == 0, ERR_UNAVAILABLE); + _current_packet = _incoming_packets.front()->get(); _incoming_packets.pop_front(); @@ -121,13 +123,13 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer } // -// NetworkedMultiplayerPeer +// MultiplayerPeer // void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { // Websocket uses TCP, reliable } -NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { +MultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { // Websocket uses TCP, reliable return TRANSFER_MODE_RELIABLE; } @@ -168,10 +170,10 @@ Vector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_fr out.resize(PROTO_SIZE + p_data_size); uint8_t *w = out.ptrw(); - copymem(&w[0], &p_type, 1); - copymem(&w[1], &p_from, 4); - copymem(&w[5], &p_to, 4); - copymem(&w[PROTO_SIZE], p_data, p_data_size); + memcpy(&w[0], &p_type, 1); + memcpy(&w[1], &p_from, 4); + memcpy(&w[5], &p_to, 4); + memcpy(&w[PROTO_SIZE], p_data, p_data_size); return out; } @@ -211,7 +213,7 @@ void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, cons packet.size = p_data_size; packet.source = p_source; packet.destination = p_dest; - copymem(packet.data, &p_data[PROTO_SIZE], p_data_size); + memcpy(packet.data, &p_data[PROTO_SIZE], p_data_size); _incoming_packets.push_back(packet); emit_signal("peer_packet", p_source); } @@ -263,9 +265,9 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u uint8_t type = 0; uint32_t from = 0; int32_t to = 0; - copymem(&type, in_buffer, 1); - copymem(&from, &in_buffer[1], 4); - copymem(&to, &in_buffer[5], 4); + memcpy(&type, in_buffer, 1); + memcpy(&from, &in_buffer[1], 4); + memcpy(&to, &in_buffer[5], 4); if (is_server()) { // Server can resend @@ -299,7 +301,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u // System message ERR_FAIL_COND(data_size < 4); int id = 0; - copymem(&id, &in_buffer[PROTO_SIZE], 4); + memcpy(&id, &in_buffer[PROTO_SIZE], 4); switch (type) { case SYS_ADD: // Add peer diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 48a6607d89..e3ccd1a795 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -32,12 +32,12 @@ #define WEBSOCKET_MULTIPLAYER_PEER_H #include "core/error/error_list.h" -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "core/templates/list.h" #include "websocket_peer.h" -class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer { - GDCLASS(WebSocketMultiplayerPeer, NetworkedMultiplayerPeer); +class WebSocketMultiplayerPeer : public MultiplayerPeer { + GDCLASS(WebSocketMultiplayerPeer, MultiplayerPeer); private: Vector<uint8_t> _make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size); @@ -78,7 +78,7 @@ protected: int _gen_unique_id() const; public: - /* NetworkedMultiplayerPeer */ + /* MultiplayerPeer */ void set_transfer_mode(TransferMode p_mode) override; TransferMode get_transfer_mode() const override; void set_target_peer(int p_target_peer) override; diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h index 2ba83637f9..e9bb20f21f 100644 --- a/modules/websocket/websocket_peer.h +++ b/modules/websocket/websocket_peer.h @@ -55,7 +55,7 @@ public: virtual void close(int p_code = 1000, String p_reason = "") = 0; virtual bool is_connected_to_host() const = 0; - virtual IP_Address get_connected_host() const = 0; + virtual IPAddress get_connected_host() const = 0; virtual uint16_t get_connected_port() const = 0; virtual bool was_string_packet() const = 0; virtual void set_no_delay(bool p_enabled) = 0; diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp index f57e8d959c..b996852f28 100644 --- a/modules/websocket/websocket_server.cpp +++ b/modules/websocket/websocket_server.cpp @@ -34,7 +34,7 @@ GDCINULL(WebSocketServer); WebSocketServer::WebSocketServer() { _peer_id = 1; - bind_ip = IP_Address("*"); + bind_ip = IPAddress("*"); } WebSocketServer::~WebSocketServer() { @@ -55,15 +55,19 @@ void WebSocketServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key); ClassDB::bind_method(D_METHOD("set_private_key"), &WebSocketServer::set_private_key); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", 0), "set_private_key", "get_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); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_ssl_certificate", "get_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); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_ca_chain", "get_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); + ClassDB::bind_method(D_METHOD("set_handshake_timeout", "timeout"), &WebSocketServer::set_handshake_timeout); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout"); ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close"))); @@ -71,11 +75,11 @@ void WebSocketServer::_bind_methods() { ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id"))); } -IP_Address WebSocketServer::get_bind_ip() const { +IPAddress WebSocketServer::get_bind_ip() const { return bind_ip; } -void WebSocketServer::set_bind_ip(const IP_Address &p_bind_ip) { +void WebSocketServer::set_bind_ip(const IPAddress &p_bind_ip) { ERR_FAIL_COND(is_listening()); ERR_FAIL_COND(!p_bind_ip.is_valid() && !p_bind_ip.is_wildcard()); bind_ip = p_bind_ip; @@ -108,7 +112,16 @@ void WebSocketServer::set_ca_chain(Ref<X509Certificate> p_ca_chain) { ca_chain = p_ca_chain; } -NetworkedMultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const { +float WebSocketServer::get_handshake_timeout() const { + return handshake_timeout / 1000.0; +} + +void WebSocketServer::set_handshake_timeout(float p_timeout) { + ERR_FAIL_COND(p_timeout <= 0.0); + handshake_timeout = p_timeout * 1000; +} + +MultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const { if (is_listening()) { return CONNECTION_CONNECTED; } diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h index 3fbd5e3b95..26864f3085 100644 --- a/modules/websocket/websocket_server.h +++ b/modules/websocket/websocket_server.h @@ -32,7 +32,7 @@ #define WEBSOCKET_H #include "core/crypto/crypto.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "websocket_multiplayer_peer.h" #include "websocket_peer.h" @@ -40,7 +40,7 @@ class WebSocketServer : public WebSocketMultiplayerPeer { GDCLASS(WebSocketServer, WebSocketMultiplayerPeer); GDCICLASS(WebSocketServer); - IP_Address bind_ip; + IPAddress bind_ip; protected: static void _bind_methods(); @@ -48,6 +48,7 @@ protected: Ref<CryptoKey> private_key; Ref<X509Certificate> ssl_cert; Ref<X509Certificate> ca_chain; + uint32_t handshake_timeout = 3000; public: virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0; @@ -57,7 +58,7 @@ public: virtual bool is_server() const override; ConnectionStatus get_connection_status() const override; - virtual IP_Address get_peer_address(int p_peer_id) const = 0; + virtual IPAddress get_peer_address(int p_peer_id) const = 0; virtual int get_peer_port(int p_peer_id) const = 0; virtual void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") = 0; @@ -66,8 +67,8 @@ public: void _on_disconnect(int32_t p_peer_id, bool p_was_clean); void _on_close_request(int32_t p_peer_id, int p_code, String p_reason); - IP_Address get_bind_ip() const; - void set_bind_ip(const IP_Address &p_bind_ip); + IPAddress get_bind_ip() const; + void set_bind_ip(const IPAddress &p_bind_ip); Ref<CryptoKey> get_private_key() const; void set_private_key(Ref<CryptoKey> p_key); @@ -78,6 +79,9 @@ public: Ref<X509Certificate> get_ca_chain() const; void set_ca_chain(Ref<X509Certificate> p_ca_chain); + float get_handshake_timeout() const; + void set_handshake_timeout(float p_timeout); + WebSocketServer(); ~WebSocketServer(); }; diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index a075ae3982..49997b42d3 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -158,9 +158,10 @@ bool WSLClient::_verify_headers(String &r_protocol) { Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocols, const Vector<String> p_custom_headers) { ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER); _peer = Ref<WSLPeer>(memnew(WSLPeer)); - IP_Address addr; + IPAddress addr; if (!p_host.is_valid_ip_address()) { addr = IP::get_singleton()->resolve_hostname(p_host); @@ -287,7 +288,7 @@ Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const { return _peer; } -NetworkedMultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const { +MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const { if (_peer->is_connected_to_host()) { return CONNECTION_CONNECTED; } @@ -316,8 +317,8 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) { _resp_pos = 0; } -IP_Address WSLClient::get_connected_host() const { - ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IP_Address()); +IPAddress WSLClient::get_connected_host() const { + ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IPAddress()); return _peer->get_connected_host(); } @@ -337,8 +338,8 @@ Error WSLClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer } WSLClient::WSLClient() { - _peer.instance(); - _tcp.instance(); + _peer.instantiate(); + _tcp.instantiate(); disconnect_from_host(); } diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h index e7c91ed333..849639ee8b 100644 --- a/modules/websocket/wsl_client.h +++ b/modules/websocket/wsl_client.h @@ -75,7 +75,7 @@ public: int get_max_packet_size() const; Ref<WebSocketPeer> get_peer(int p_peer_id) const; void disconnect_from_host(int p_code = 1000, String p_reason = ""); - IP_Address get_connected_host() const; + IPAddress get_connected_host() const; uint16_t get_connected_port() const; virtual ConnectionStatus get_connection_status() const; virtual void poll(); diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index dbbf86d0da..1dbadfed74 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -305,8 +305,8 @@ void WSLPeer::close(int p_code, String p_reason) { _packet_buffer.resize(0); } -IP_Address WSLPeer::get_connected_host() const { - ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IP_Address()); +IPAddress WSLPeer::get_connected_host() const { + ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IPAddress()); return _data->tcp->get_connected_host(); } diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h index 5e6a7e8554..f1ea98d384 100644 --- a/modules/websocket/wsl_peer.h +++ b/modules/websocket/wsl_peer.h @@ -90,7 +90,7 @@ public: virtual void close_now(); virtual void close(int p_code = 1000, String p_reason = ""); virtual bool is_connected_to_host() const; - virtual IP_Address get_connected_host() const; + virtual IPAddress get_connected_host() const; virtual uint16_t get_connected_port() const; virtual WriteMode get_write_mode() const; diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index 437eb2061b..c889562732 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -95,28 +95,33 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols) { return true; } -Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols) { - if (OS::get_singleton()->get_ticks_msec() - time > WSL_SERVER_TIMEOUT) { +Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout) { + if (OS::get_singleton()->get_ticks_msec() - time > p_timeout) { + print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", p_timeout * 0.001)); return ERR_TIMEOUT; } + if (use_ssl) { Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL>>(connection); if (ssl.is_null()) { - return FAILED; + ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerSSL for WebSocket handshake."); } ssl->poll(); if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) { return ERR_BUSY; } else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) { + print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerSSL status code %d).", ssl->get_status())); return FAILED; } } + if (!has_request) { int read = 0; while (true) { - ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "Response headers too big."); + ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "WebSocket response headers are too big."); Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); if (err != OK) { // Got an error + print_verbose(vformat("WebSocket error while getting partial data (StreamPeer error code %d).", err)); return FAILED; } else if (read != 1) { // Busy, wait next poll return ERR_BUSY; @@ -143,17 +148,21 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols) { req_pos += 1; } } + if (has_request && response_sent < response.size() - 1) { int sent = 0; Error err = connection->put_partial_data((const uint8_t *)response.get_data() + response_sent, response.size() - response_sent - 1, sent); if (err != OK) { + print_verbose(vformat("WebSocket error while putting partial data (StreamPeer error code %d).", err)); return err; } response_sent += sent; } + if (response_sent < response.size() - 1) { return ERR_BUSY; } + return OK; } @@ -188,7 +197,7 @@ void WSLServer::poll() { List<Ref<PendingPeer>> remove_peers; for (List<Ref<PendingPeer>>::Element *E = _pending.front(); E; E = E->next()) { Ref<PendingPeer> ppeer = E->get(); - Error err = ppeer->do_handshake(_protocols); + Error err = ppeer->do_handshake(_protocols, handshake_timeout); if (err == ERR_BUSY) { continue; } else if (err != OK) { @@ -272,8 +281,8 @@ Ref<WebSocketPeer> WSLServer::get_peer(int p_id) const { return _peer_map[p_id]; } -IP_Address WSLServer::get_peer_address(int p_peer_id) const { - ERR_FAIL_COND_V(!has_peer(p_peer_id), IP_Address()); +IPAddress WSLServer::get_peer_address(int p_peer_id) const { + ERR_FAIL_COND_V(!has_peer(p_peer_id), IPAddress()); return _peer_map[p_peer_id]->get_connected_host(); } @@ -301,7 +310,7 @@ Error WSLServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer } WSLServer::WSLServer() { - _server.instance(); + _server.instantiate(); } WSLServer::~WSLServer() { diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h index 75669e12ee..a428c89f4f 100644 --- a/modules/websocket/wsl_server.h +++ b/modules/websocket/wsl_server.h @@ -40,13 +40,11 @@ #include "core/io/stream_peer_tcp.h" #include "core/io/tcp_server.h" -#define WSL_SERVER_TIMEOUT 1000 - class WSLServer : public WebSocketServer { GDCIIMPL(WSLServer, WebSocketServer); private: - class PendingPeer : public Reference { + class PendingPeer : public RefCounted { private: bool _parse_request(const Vector<String> p_protocols); @@ -64,7 +62,7 @@ private: CharString response; int response_sent = 0; - Error do_handshake(const Vector<String> p_protocols); + Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout); }; int _in_buf_size = DEF_BUF_SHIFT; @@ -73,7 +71,7 @@ private: int _out_pkt_size = DEF_PKT_SHIFT; List<Ref<PendingPeer>> _pending; - Ref<TCP_Server> _server; + Ref<TCPServer> _server; Vector<String> _protocols; public: @@ -84,7 +82,7 @@ public: int get_max_packet_size() const; bool has_peer(int p_id) const; Ref<WebSocketPeer> get_peer(int p_id) const; - IP_Address get_peer_address(int p_peer_id) const; + IPAddress get_peer_address(int p_peer_id) const; int get_peer_port(int p_peer_id) const; void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); virtual void poll(); diff --git a/modules/webxr/config.py b/modules/webxr/config.py index 9efebed4e6..f676ef3483 100644 --- a/modules/webxr/config.py +++ b/modules/webxr/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index 2407d44496..9b3a063ef5 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -7,7 +7,7 @@ WebXR is an open standard that allows creating VR and AR applications that run in the web browser. As such, this interface is only available when running in an HTML5 export. WebXR supports a wide range of devices, from the very capable (like Valve Index, HTC Vive, Oculus Rift and Quest) down to the much less capable (like Google Cardboard, Oculus Go, GearVR, or plain smartphones). - Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to intialize than other AR/VR interfaces. + Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to initialize than other AR/VR interfaces. Here's the minimum code required to start an immersive VR session: [codeblock] extends Node3D diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js index 8e9ef8a73c..6e19a8ac6e 100644 --- a/modules/webxr/native/library_godot_webxr.js +++ b/modules/webxr/native/library_godot_webxr.js @@ -71,10 +71,8 @@ const GodotWebXR = { // enabled or disabled. When using the WebXR API Emulator, this // gets picked up automatically, however, in the Oculus Browser // on the Quest, we need to pause and resume the main loop. - Browser.pauseAsyncCallbacks(); Browser.mainLoop.pause(); window.setTimeout(function () { - Browser.resumeAsyncCallbacks(); Browser.mainLoop.resume(); }, 0); }, diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp index 8baf7e05b8..078a6547cf 100644 --- a/modules/webxr/register_types.cpp +++ b/modules/webxr/register_types.cpp @@ -34,11 +34,11 @@ #include "webxr_interface_js.h" void register_webxr_types() { - ClassDB::register_virtual_class<WebXRInterface>(); + GDREGISTER_VIRTUAL_CLASS(WebXRInterface); #ifdef JAVASCRIPT_ENABLED Ref<WebXRInterfaceJS> webxr; - webxr.instance(); + webxr.instantiate(); XRServer::get_singleton()->add_interface(webxr); #endif } diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h index c5b2dc8d73..366235fcd5 100644 --- a/modules/webxr/webxr_interface.h +++ b/modules/webxr/webxr_interface.h @@ -57,7 +57,7 @@ public: virtual void set_requested_reference_space_types(String p_requested_reference_space_types) = 0; virtual String get_requested_reference_space_types() const = 0; virtual String get_reference_space_type() const = 0; - virtual XRPositionalTracker *get_controller(int p_controller_id) const = 0; + virtual Ref<XRPositionalTracker> get_controller(int p_controller_id) const = 0; virtual String get_visibility_state() const = 0; virtual PackedVector3Array get_bounds_geometry() const = 0; }; diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 10076327e2..01cc05aa0b 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -160,7 +160,7 @@ String WebXRInterfaceJS::get_reference_space_type() const { return reference_space_type; } -XRPositionalTracker *WebXRInterfaceJS::get_controller(int p_controller_id) const { +Ref<XRPositionalTracker> WebXRInterfaceJS::get_controller(int p_controller_id) const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, nullptr); @@ -202,8 +202,8 @@ int WebXRInterfaceJS::get_capabilities() const { return XRInterface::XR_STEREO | XRInterface::XR_MONO; }; -bool WebXRInterfaceJS::is_stereo() { - return godot_webxr_get_view_count() == 2; +uint32_t WebXRInterfaceJS::get_view_count() { + return godot_webxr_get_view_count(); }; bool WebXRInterfaceJS::is_initialized() const { @@ -253,7 +253,7 @@ bool WebXRInterfaceJS::initialize() { void WebXRInterfaceJS::uninitialize() { if (initialized) { XRServer *xr_server = XRServer::get_singleton(); - if (xr_server != NULL) { + if (xr_server != nullptr) { // no longer our primary interface xr_server->clear_primary_interface_if(this); } @@ -265,8 +265,8 @@ void WebXRInterfaceJS::uninitialize() { }; }; -Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { - Transform transform; +Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { + Transform3D transform; transform.basis.elements[0].x = p_js_matrix[0]; transform.basis.elements[1].x = p_js_matrix[1]; @@ -305,13 +305,30 @@ Size2 WebXRInterfaceJS::get_render_targetsize() { return render_targetsize; }; -Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { - Transform transform_for_eye; +Transform3D WebXRInterfaceJS::get_camera_transform() { + Transform3D transform_for_eye; XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, transform_for_eye); - float *js_matrix = godot_webxr_get_transform_for_eye(p_eye); + float *js_matrix = godot_webxr_get_transform_for_eye(0); + if (!initialized || js_matrix == nullptr) { + return transform_for_eye; + } + + transform_for_eye = _js_matrix_to_transform(js_matrix); + free(js_matrix); + + return xr_server->get_reference_frame() * transform_for_eye; +}; + +Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + Transform3D transform_for_eye; + + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, transform_for_eye); + + float *js_matrix = godot_webxr_get_transform_for_eye(p_view + 1); if (!initialized || js_matrix == nullptr) { transform_for_eye = p_cam_transform; return transform_for_eye; @@ -323,10 +340,10 @@ Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye; }; -CameraMatrix WebXRInterfaceJS::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { CameraMatrix eye; - float *js_matrix = godot_webxr_get_projection_for_eye(p_eye); + float *js_matrix = godot_webxr_get_projection_for_eye(p_view + 1); if (!initialized || js_matrix == nullptr) { return eye; } @@ -380,10 +397,10 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1); + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1); if (godot_webxr_is_controller_connected(p_controller_id)) { - if (tracker == nullptr) { - tracker = memnew(XRPositionalTracker); + if (tracker.is_null()) { + tracker.instantiate(); tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); // Controller id's 0 and 1 are always the left and right hands. if (p_controller_id < 2) { @@ -399,7 +416,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id); if (tracker_matrix) { - Transform transform = _js_matrix_to_transform(tracker_matrix); + Transform3D transform = _js_matrix_to_transform(tracker_matrix); tracker->set_position(transform.origin); tracker->set_orientation(transform.basis); free(tracker_matrix); @@ -408,7 +425,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { int *buttons = godot_webxr_get_controller_buttons(p_controller_id); if (buttons) { for (int i = 0; i < buttons[0]; i++) { - input->joy_button(p_controller_id + 100, i, *((float *)buttons + (i + 1))); + input->joy_button(p_controller_id + 100, (JoyButton)i, *((float *)buttons + (i + 1))); } free(buttons); } @@ -419,11 +436,11 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { Input::JoyAxisValue joy_axis; joy_axis.min = -1; joy_axis.value = *((float *)axes + (i + 1)); - input->joy_axis(p_controller_id + 100, i, joy_axis); + input->joy_axis(p_controller_id + 100, (JoyAxis)i, joy_axis); } free(axes); } - } else if (tracker) { + } else if (tracker.is_valid()) { xr_server->remove_tracker(tracker); } } diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index 49299b252f..3b5509adeb 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -56,7 +56,7 @@ private: bool controllers_state[2]; Size2 render_targetsize; - Transform _js_matrix_to_transform(float *p_js_matrix); + Transform3D _js_matrix_to_transform(float *p_js_matrix); void _update_tracker(int p_controller_id); public: @@ -71,7 +71,7 @@ public: virtual String get_requested_reference_space_types() const override; void _set_reference_space_type(String p_reference_space_type); virtual String get_reference_space_type() const override; - virtual XRPositionalTracker *get_controller(int p_controller_id) const override; + virtual Ref<XRPositionalTracker> get_controller(int p_controller_id) const override; virtual String get_visibility_state() const override; virtual PackedVector3Array get_bounds_geometry() const override; @@ -83,9 +83,10 @@ public: virtual void uninitialize() override; virtual Size2 get_render_targetsize() override; - virtual bool is_stereo() override; - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override; virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp index e1f9521a48..8913ef1b65 100644 --- a/modules/xatlas_unwrap/register_types.cpp +++ b/modules/xatlas_unwrap/register_types.cpp @@ -29,26 +29,19 @@ /*************************************************************************/ #include "register_types.h" - -#include "core/error/error_macros.h" - #include "core/crypto/crypto_core.h" - #include "thirdparty/xatlas/xatlas.h" -#include <stdio.h> -#include <stdlib.h> +extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y); -extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache); - -bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uvs, int **r_vertices, int *r_vertex_count, int **r_indices, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache) { +bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) { CryptoCore::MD5Context ctx; ctx.start(); ctx.update((unsigned char *)&p_texel_size, sizeof(float)); ctx.update((unsigned char *)p_indices, sizeof(int) * p_index_count); - ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count); - ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count); + ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count * 3); + ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count * 3); unsigned char hash[16]; ctx.finish(hash); @@ -56,38 +49,37 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver bool cached = false; unsigned int cache_idx = 0; - if (r_used_cache && r_cache_size) { - //Check if hash is in cache data + *r_mesh_cache = nullptr; + *r_mesh_cache_size = 0; - int *cache_data = r_cache_data; + if (p_cache_data) { + //Check if hash is in cache data + int *cache_data = (int *)p_cache_data; int n_entries = cache_data[0]; - unsigned int r_idx = 1; + unsigned int read_idx = 1; for (int i = 0; i < n_entries; ++i) { - if (memcmp(&cache_data[r_idx], hash, 16) == 0) { + if (memcmp(&cache_data[read_idx], hash, 16) == 0) { cached = true; - cache_idx = r_idx; + cache_idx = read_idx; break; } - r_idx += 4; // hash - r_idx += 2; // size hint + read_idx += 4; // hash + read_idx += 2; // size hint - int vertex_count = cache_data[r_idx]; - r_idx += 1; // vertex count - r_idx += vertex_count; // vertex - r_idx += vertex_count * 2; // uvs + int vertex_count = cache_data[read_idx]; + read_idx += 1; // vertex count + read_idx += vertex_count; // vertex + read_idx += vertex_count * 2; // uvs - int index_count = cache_data[r_idx]; - r_idx += 1; // index count - r_idx += index_count; // indices + int index_count = cache_data[read_idx]; + read_idx += 1; // index count + read_idx += index_count; // indices } } - if (r_used_cache && cached) { - int *cache_data = r_cache_data; - - // Return cache data pointer to the caller - r_cache_data = &cache_data[cache_idx]; + if (cached) { + int *cache_data = (int *)p_cache_data; cache_idx += 4; @@ -99,96 +91,92 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver // Load vertices *r_vertex_count = cache_data[cache_idx]; cache_idx++; - *r_vertices = &cache_data[cache_idx]; + *r_vertex = &cache_data[cache_idx]; cache_idx += *r_vertex_count; // Load UVs - *r_uvs = (float *)&cache_data[cache_idx]; + *r_uv = (float *)&cache_data[cache_idx]; cache_idx += *r_vertex_count * 2; // Load indices *r_index_count = cache_data[cache_idx]; cache_idx++; - *r_indices = &cache_data[cache_idx]; - - // Return cache data size to the caller - r_cache_size = sizeof(int) * (4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count); // hash + size hint + vertex_count + vertices + uvs + index_count + indices - r_used_cache = true; - return true; - } - - //set up input mesh - xatlas::MeshDecl input_mesh; - input_mesh.indexData = p_indices; - input_mesh.indexCount = p_index_count; - input_mesh.indexFormat = xatlas::IndexFormat::UInt32; - - input_mesh.vertexCount = p_vertex_count; - input_mesh.vertexPositionData = p_vertices; - input_mesh.vertexPositionStride = sizeof(float) * 3; - input_mesh.vertexNormalData = p_normals; - input_mesh.vertexNormalStride = sizeof(uint32_t) * 3; - input_mesh.vertexUvData = nullptr; - input_mesh.vertexUvStride = 0; - - xatlas::ChartOptions chart_options; - xatlas::PackOptions pack_options; - - pack_options.maxChartSize = 4096; - pack_options.blockAlign = true; - pack_options.padding = 1; - pack_options.texelsPerUnit = 1.0 / p_texel_size; + *r_index = &cache_data[cache_idx]; + } else { + // set up input mesh + xatlas::MeshDecl input_mesh; + input_mesh.indexData = p_indices; + input_mesh.indexCount = p_index_count; + input_mesh.indexFormat = xatlas::IndexFormat::UInt32; + + input_mesh.vertexCount = p_vertex_count; + input_mesh.vertexPositionData = p_vertices; + input_mesh.vertexPositionStride = sizeof(float) * 3; + input_mesh.vertexNormalData = p_normals; + input_mesh.vertexNormalStride = sizeof(uint32_t) * 3; + input_mesh.vertexUvData = NULL; + input_mesh.vertexUvStride = 0; + + xatlas::ChartOptions chart_options; + chart_options.fixWinding = true; + + xatlas::PackOptions pack_options; + pack_options.padding = 1; + pack_options.maxChartSize = 4094; // Lightmap atlassing needs 2 for padding between meshes, so 4096-2 + pack_options.blockAlign = true; + pack_options.texelsPerUnit = 1.0 / p_texel_size; + + xatlas::Atlas *atlas = xatlas::Create(); + + xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1); + ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err)); + + xatlas::Generate(atlas, chart_options, pack_options); + + *r_size_hint_x = atlas->width; + *r_size_hint_y = atlas->height; + + float w = *r_size_hint_x; + float h = *r_size_hint_y; + + if (w == 0 || h == 0) { + xatlas::Destroy(atlas); + return false; //could not bake because there is no area + } - xatlas::Atlas *atlas = xatlas::Create(); - printf("Adding mesh..\n"); - xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1); - ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err)); + const xatlas::Mesh &output = atlas->meshes[0]; + + *r_vertex = (int *)memalloc(sizeof(int) * output.vertexCount); + ERR_FAIL_NULL_V_MSG(*r_vertex, false, "Out of memory."); + *r_uv = (float *)memalloc(sizeof(float) * output.vertexCount * 2); + ERR_FAIL_NULL_V_MSG(*r_uv, false, "Out of memory."); + *r_index = (int *)memalloc(sizeof(int) * output.indexCount); + ERR_FAIL_NULL_V_MSG(*r_index, false, "Out of memory."); + + float max_x = 0; + float max_y = 0; + for (uint32_t i = 0; i < output.vertexCount; i++) { + (*r_vertex)[i] = output.vertexArray[i].xref; + (*r_uv)[i * 2 + 0] = output.vertexArray[i].uv[0] / w; + (*r_uv)[i * 2 + 1] = output.vertexArray[i].uv[1] / h; + max_x = MAX(max_x, output.vertexArray[i].uv[0]); + max_y = MAX(max_y, output.vertexArray[i].uv[1]); + } - printf("Generate..\n"); - xatlas::Generate(atlas, chart_options, pack_options); + *r_vertex_count = output.vertexCount; - *r_size_hint_x = atlas->width; - *r_size_hint_y = atlas->height; + for (uint32_t i = 0; i < output.indexCount; i++) { + (*r_index)[i] = output.indexArray[i]; + } - float w = *r_size_hint_x; - float h = *r_size_hint_y; + *r_index_count = output.indexCount; - if (w == 0 || h == 0) { xatlas::Destroy(atlas); - return false; //could not bake because there is no area - } - - const xatlas::Mesh &output = atlas->meshes[0]; - - *r_vertices = (int *)malloc(sizeof(int) * output.vertexCount); - ERR_FAIL_NULL_V_MSG(*r_vertices, false, "Out of memory."); - *r_uvs = (float *)malloc(sizeof(float) * output.vertexCount * 2); - ERR_FAIL_NULL_V_MSG(*r_uvs, false, "Out of memory."); - *r_indices = (int *)malloc(sizeof(int) * output.indexCount); - ERR_FAIL_NULL_V_MSG(*r_indices, false, "Out of memory."); - - float max_x = 0.0; - float max_y = 0.0; - for (uint32_t i = 0; i < output.vertexCount; i++) { - (*r_vertices)[i] = output.vertexArray[i].xref; - (*r_uvs)[i * 2 + 0] = output.vertexArray[i].uv[0] / w; - (*r_uvs)[i * 2 + 1] = output.vertexArray[i].uv[1] / h; - max_x = MAX(max_x, output.vertexArray[i].uv[0]); - max_y = MAX(max_y, output.vertexArray[i].uv[1]); } - printf("Final texture size: %f,%f - max %f,%f\n", w, h, max_x, max_y); - *r_vertex_count = output.vertexCount; + if (*r_use_cache) { + // Build cache data for current mesh - for (uint32_t i = 0; i < output.indexCount; i++) { - (*r_indices)[i] = output.indexArray[i]; - } - - *r_index_count = output.indexCount; - - xatlas::Destroy(atlas); - - if (r_used_cache) { unsigned int new_cache_size = 4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count; // hash + size hint + vertex_count + vertices + uvs + index_count + indices new_cache_size *= sizeof(int); int *new_cache_data = (int *)memalloc(new_cache_size); @@ -208,11 +196,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver new_cache_idx++; // vertices - memcpy(&new_cache_data[new_cache_idx], *r_vertices, sizeof(int) * *r_vertex_count); + memcpy(&new_cache_data[new_cache_idx], *r_vertex, sizeof(int) * (*r_vertex_count)); new_cache_idx += *r_vertex_count; // uvs - memcpy(&new_cache_data[new_cache_idx], *r_uvs, sizeof(float) * *r_vertex_count * 2); + memcpy(&new_cache_data[new_cache_idx], *r_uv, sizeof(float) * (*r_vertex_count) * 2); new_cache_idx += *r_vertex_count * 2; // index count @@ -220,15 +208,15 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver new_cache_idx++; // indices - memcpy(&new_cache_data[new_cache_idx], *r_indices, sizeof(int) * *r_index_count); - new_cache_idx += *r_index_count; + memcpy(&new_cache_data[new_cache_idx], *r_index, sizeof(int) * (*r_index_count)); // Return cache data to the caller - r_cache_data = new_cache_data; - r_cache_size = new_cache_size; - r_used_cache = false; + *r_mesh_cache = (uint8_t *)new_cache_data; + *r_mesh_cache_size = new_cache_size; } + *r_use_cache = cached; // Return whether cache was used. + return true; } |