diff options
Diffstat (limited to 'modules')
921 files changed, 26056 insertions, 54672 deletions
diff --git a/modules/SCsub b/modules/SCsub index 5ff4623743..fcc01e2c1b 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -22,36 +22,45 @@ 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), - env.Run( - modules_builders.generate_modules_tests, - "Generating modules tests header.", - # NOTE: No need to run in subprocess since this is still executed serially. - subprocess=False, - ), - ) - env.AlwaysBuild("modules_tests.gen.h") vs_sources = [] +test_headers = [] # libmodule_<name>.a for each active module. for name, path in env.module_list.items(): env.modules_sources = [] - if not os.path.isabs(path): - SConscript(name + "/SCsub") # Built-in. - else: - SConscript(path + "/SCsub") # Custom. + # Name for built-in modules, (absolute) path for custom ones. + base_path = path if os.path.isabs(path) else name + SConscript(base_path + "/SCsub") lib = env_modules.add_library("module_%s" % name, env.modules_sources) env.Prepend(LIBS=[lib]) if env["vsproj"]: vs_sources += env.modules_sources + if env["tests"]: + # Lookup potential headers in `tests` subfolder. + import glob + + module_tests = sorted(glob.glob(os.path.join(base_path, "tests", "*.h"))) + if module_tests != []: + test_headers += module_tests + + +# Generate header to be included in `tests/test_main.cpp` to run module-specific tests. +if env["tests"]: + env.Depends("modules_tests.gen.h", test_headers) + env.CommandNoCache( + "modules_tests.gen.h", + test_headers, + env.Run( + modules_builders.generate_modules_tests, + "Generating modules tests header.", + # NOTE: No need to run in subprocess since this is still executed serially. + subprocess=False, + ), + ) + # libmodules.a with only register_module_types. # Must be last so that all libmodule_<name>.a libraries are on the right side # in the linker command. diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub index 1f9fde966d..a44a7f0db3 100644 --- a/modules/basis_universal/SCsub +++ b/modules/basis_universal/SCsub @@ -13,16 +13,14 @@ thirdparty_obj = [] thirdparty_dir = "#thirdparty/basis_universal/" # 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_opencl.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", @@ -31,7 +29,7 @@ encoder_sources = [ "basisu_ssim.cpp", "basisu_uastc_enc.cpp", "jpgd.cpp", - "lodepng.cpp", + "pvpngreader.cpp", ] encoder_sources = [thirdparty_dir + "encoder/" + file for file in encoder_sources] transcoder_sources = [thirdparty_dir + "transcoder/basisu_transcoder.cpp"] diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index d2105d7c5d..e80d453df7 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,7 +32,6 @@ #include "core/os/os.h" #include "servers/rendering_server.h" -#include "texture_basisu.h" #ifdef TOOLS_ENABLED #include <encoder/basisu_comp.h> @@ -50,8 +49,6 @@ enum BasisDecompressFormat { //workaround for lack of ETC2 RG #define USE_RG_AS_RGBA -basist::etc1_global_selector_codebook *sel_codebook = nullptr; - #ifdef TOOLS_ENABLED static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) { Vector<uint8_t> budata; @@ -78,18 +75,14 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image:: memcpy(buimg.get_ptr(), r, vec.size()); } - //image->save_png("pepeche.png"); - basisu::basis_compressor_params params; + params.m_uastc = true; params.m_max_endpoint_clusters = 512; params.m_max_selector_clusters = 512; params.m_multithreading = true; - //params.m_no_hybrid_sel_cb = true; //fixme, default on this causes crashes //seems fixed? - params.m_pSel_codebook = sel_codebook; //params.m_quality_level = 0; //params.m_disable_hierarchical_endpoint_codebooks = true; //params.m_no_selector_rdo = true; - params.m_auto_global_sel_pal = false; basisu::job_pool jpool(OS::get_singleton()->get_processor_count()); params.m_pJob_pool = &jpool; @@ -150,12 +143,11 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image:: } #endif // TOOLS_ENABLED -static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { +static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { Ref<Image> image; - const uint8_t *r = p_buffer.ptr(); - const uint8_t *ptr = r; - int size = p_buffer.size(); + const uint8_t *ptr = p_data; + int size = p_size; basist::transcoder_texture_format format = basist::transcoder_texture_format::cTFTotalTextureFormats; Image::Format imgfmt = Image::FORMAT_MAX; @@ -226,7 +218,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { ptr += 4; size -= 4; - basist::basisu_transcoder tr(nullptr); + basist::basisu_transcoder tr; ERR_FAIL_COND_V(!tr.validate_header(ptr, size), image); @@ -252,7 +244,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format); if (!ret) { - printf("failed! on level %i\n", i); + printf("failed! on level %u\n", i); break; }; @@ -266,19 +258,37 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { return image; } -void register_basis_universal_types() { +static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { + Ref<Image> image; + + const uint8_t *r = p_buffer.ptr(); + int size = p_buffer.size(); + return basis_universal_unpacker_ptr(r, size); +} + +void initialize_basis_universal_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #ifdef TOOLS_ENABLED - sel_codebook = new basist::etc1_global_selector_codebook(basist::g_global_selector_cb_size, basist::g_global_selector_cb); + using namespace basisu; + using namespace basist; + basisu_encoder_init(); Image::basis_universal_packer = basis_universal_packer; #endif Image::basis_universal_unpacker = basis_universal_unpacker; - //GDREGISTER_CLASS(TextureBasisU); + Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr; } -void unregister_basis_universal_types() { +void uninitialize_basis_universal_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #ifdef TOOLS_ENABLED - delete sel_codebook; Image::basis_universal_packer = nullptr; #endif Image::basis_universal_unpacker = nullptr; + Image::basis_universal_unpacker_ptr = nullptr; } diff --git a/modules/basis_universal/register_types.h b/modules/basis_universal/register_types.h index 30b465e344..68d5dd64f3 100644 --- a/modules/basis_universal/register_types.h +++ b/modules/basis_universal/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef BASIS_UNIVERSAL_REGISTER_TYPES_H #define BASIS_UNIVERSAL_REGISTER_TYPES_H -void register_basis_universal_types(); -void unregister_basis_universal_types(); +#include "modules/register_module_types.h" + +void initialize_basis_universal_module(ModuleInitializationLevel p_level); +void uninitialize_basis_universal_module(ModuleInitializationLevel p_level); #endif // BASIS_UNIVERSAL_REGISTER_TYPES_H diff --git a/modules/basis_universal/texture_basisu.cpp b/modules/basis_universal/texture_basisu.cpp deleted file mode 100644 index 9e917420ce..0000000000 --- a/modules/basis_universal/texture_basisu.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/*************************************************************************/ -/* texture_basisu.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_basisu.h" -#if 0 -#include "core/os/os.h" - -#ifdef TOOLS_ENABLED -#include <encoder/basisu_comp.h> -#endif - -#include <transcoder/basisu_transcoder.h> - -void TextureBasisU::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_basisu_data", "data"), &TextureBasisU::set_basisu_data); - ClassDB::bind_method(D_METHOD("get_basisu_data"), &TextureBasisU::get_data); - ClassDB::bind_method(D_METHOD("import"), &TextureBasisU::import); - - ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "basisu_data"), "set_basisu_data", "get_basisu_data"); -}; - -int TextureBasisU::get_width() const { - return tex_size.x; -}; - -int TextureBasisU::get_height() const { - return tex_size.y; -}; - -RID TextureBasisU::get_rid() const { - return texture; -}; - - -bool TextureBasisU::has_alpha() const { - return false; -}; - -void TextureBasisU::set_flags(uint32_t p_flags) { - flags = p_flags; - RenderingServer::get_singleton()->texture_set_flags(texture, p_flags); -}; - -uint32_t TextureBasisU::get_flags() const { - return flags; -}; - - -void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) { - -#ifdef TOOLS_ENABLED - data = p_data; -#endif - - const uint8_t* r = p_data.ptr(); - const void* ptr = r.ptr(); - int size = p_data.size(); - - basist::transcoder_texture_format format; - Image::Format imgfmt; - - if (OS::get_singleton()->has_feature("s3tc")) { - format = basist::cTFBC3; // get this from renderer - imgfmt = Image::FORMAT_DXT5; - - } else if (OS::get_singleton()->has_feature("etc2")) { - format = basist::cTFETC2; - imgfmt = Image::FORMAT_ETC2_RGBA8; - }; - - basist::basisu_transcoder tr(nullptr); - - ERR_FAIL_COND(!tr.validate_header(ptr, size)); - - basist::basisu_image_info info; - tr.get_image_info(ptr, size, info, 0); - tex_size = Size2(info.m_width, info.m_height); - - int block_size = basist::basis_get_bytes_per_block(format); - Vector<uint8_t> gpudata; - gpudata.resize(info.m_total_blocks * block_size); - - { - uint8_t* w = gpudata.ptrw(); - uint8_t* dst = w.ptr(); - for (int i=0; i<gpudata.size(); i++) - dst[i] = 0x00; - - int ofs = 0; - tr.start_transcoding(ptr, size); - for (int i=0; i<info.m_total_levels; i++) { - basist::basisu_image_level_info level; - tr.get_image_level_info(ptr, size, level, 0, i); - - bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format); - if (!ret) { - printf("failed! on level %i\n", i); - break; - }; - - ofs += level.m_total_blocks * block_size; - }; - }; - - Ref<Image> img; - 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); - RenderingServer::get_singleton()->texture_set_data(texture, img); -}; - -Error TextureBasisU::import(const Ref<Image>& p_img) { - -#ifdef TOOLS_ENABLED - - Vector<uint8_t> budata; - - { - Image::Format format = p_img->get_format(); - if (format != Image::FORMAT_RGB8 && format != Image::FORMAT_RGBA8) { - ERR_FAIL_V(ERR_INVALID_PARAMETER); - return ERR_INVALID_PARAMETER; - }; - - Ref<Image> copy = p_img->duplicate(); - if (format == Image::FORMAT_RGB8) - copy->convert(Image::FORMAT_RGBA8); - - basisu::image buimg(p_img->get_width(), p_img->get_height()); - int size = p_img->get_width() * p_img->get_height() * 4; - - Vector<uint8_t> vec = copy->get_data(); - { - const uint8_t* r = vec.ptr(); - memcpy(buimg.get_ptr(), r.ptr(), size); - }; - - basisu::basis_compressor_params params; - params.m_max_endpoint_clusters = 512; - params.m_max_selector_clusters = 512; - params.m_multithreading = true; - - basisu::job_pool jpool(1); - params.m_pJob_pool = &jpool; - - params.m_mip_gen = p_img->get_mipmap_count() > 0; - params.m_source_images.push_back(buimg); - - basisu::basis_compressor c; - c.init(params); - - int buerr = c.process(); - if (buerr != basisu::basis_compressor::cECSuccess) { - ERR_FAIL_V(ERR_INVALID_PARAMETER); - return ERR_INVALID_PARAMETER; - }; - - const basisu::uint8_vec& buvec = c.get_output_basis_file(); - budata.resize(buvec.size()); - - { - uint8_t* w = budata.ptrw(); - memcpy(w.ptr(), &buvec[0], budata.size()); - }; - }; - - set_basisu_data(budata); - - return OK; -#else - - return ERR_UNAVAILABLE; -#endif -}; - - -Vector<uint8_t> TextureBasisU::get_basisu_data() const { - return data; -}; - -TextureBasisU::TextureBasisU() { - texture = RenderingServer::get_singleton()->texture_create(); -}; - - -TextureBasisU::~TextureBasisU() { - RenderingServer::get_singleton()->free(texture); -}; - -#endif diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index 3d47055247..8813c3827a 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -200,8 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, return err; } -Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, - bool p_force_linear, float p_scale) { +Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { bmp_header_s bmp_header; Error err = ERR_INVALID_DATA; @@ -241,7 +240,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, case BI_CMYKRLE8: case BI_CMYKRLE4: { // Stop parsing. - f->close(); ERR_FAIL_V_MSG(ERR_UNAVAILABLE, vformat("Compressed BMP files are not supported: %s", f->get_path())); } break; @@ -283,7 +281,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, err = convert_to_image(p_image, bmp_buffer_r, bmp_color_table_r, color_table_size, bmp_header); } - f->close(); } } return err; @@ -294,12 +291,14 @@ void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const } static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) { - FileAccessMemory memfile; - Error open_memfile_error = memfile.open_custom(p_bmp, p_size); + Ref<FileAccessMemory> memfile; + memfile.instantiate(); + 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.instantiate(); - Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f); + 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/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h index 379e971458..63dee0a969 100644 --- a/modules/bmp/image_loader_bmp.h +++ b/modules/bmp/image_loader_bmp.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -83,8 +83,7 @@ protected: const bmp_header_s &p_header); public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, - bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderBMP(); }; diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp index d36ce9cdaf..7c4a2085b2 100644 --- a/modules/bmp/register_types.cpp +++ b/modules/bmp/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,19 @@ static ImageLoaderBMP *image_loader_bmp = nullptr; -void register_bmp_types() { +void initialize_bmp_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + image_loader_bmp = memnew(ImageLoaderBMP); ImageLoader::add_image_format_loader(image_loader_bmp); } -void unregister_bmp_types() { +void uninitialize_bmp_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + memdelete(image_loader_bmp); } diff --git a/modules/bmp/register_types.h b/modules/bmp/register_types.h index 3ce81eba1b..45c8499c58 100644 --- a/modules/bmp/register_types.h +++ b/modules/bmp/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef BMP_REGISTER_TYPES_H #define BMP_REGISTER_TYPES_H -void register_bmp_types(); -void unregister_bmp_types(); +#include "modules/register_module_types.h" + +void initialize_bmp_module(ModuleInitializationLevel p_level); +void uninitialize_bmp_module(ModuleInitializationLevel p_level); #endif // BMP_REGISTER_TYPES_H diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub deleted file mode 100644 index 09509abc44..0000000000 --- a/modules/bullet/SCsub +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_bullet = env_modules.Clone() - -# Thirdparty source files - -thirdparty_obj = [] - -if env["builtin_bullet"]: - # Build only "Bullet2" API (not "Bullet3" folders). - # Sync file list with relevant upstream CMakeLists.txt for each folder. - if env["float"] == "64": - env.Append(CPPDEFINES=["BT_USE_DOUBLE_PRECISION=1"]) - thirdparty_dir = "#thirdparty/bullet/" - - bullet2_src = [ - # BulletCollision - "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp", - "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", - "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp", - "BulletCollision/BroadphaseCollision/btDbvt.cpp", - "BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp", - "BulletCollision/BroadphaseCollision/btDispatcher.cpp", - "BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", - "BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp", - "BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", - "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp", - "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp", - "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp", - "BulletCollision/CollisionDispatch/btCollisionObject.cpp", - "BulletCollision/CollisionDispatch/btCollisionWorld.cpp", - "BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp", - "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp", - "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btGhostObject.cpp", - "BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp", - "BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp", - "BulletCollision/CollisionDispatch/btManifoldResult.cpp", - "BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp", - "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp", - "BulletCollision/CollisionDispatch/btUnionFind.cpp", - "BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp", - "BulletCollision/CollisionShapes/btBoxShape.cpp", - "BulletCollision/CollisionShapes/btBox2dShape.cpp", - "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp", - "BulletCollision/CollisionShapes/btCapsuleShape.cpp", - "BulletCollision/CollisionShapes/btCollisionShape.cpp", - "BulletCollision/CollisionShapes/btCompoundShape.cpp", - "BulletCollision/CollisionShapes/btConcaveShape.cpp", - "BulletCollision/CollisionShapes/btConeShape.cpp", - "BulletCollision/CollisionShapes/btConvexHullShape.cpp", - "BulletCollision/CollisionShapes/btConvexInternalShape.cpp", - "BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp", - "BulletCollision/CollisionShapes/btConvexPolyhedron.cpp", - "BulletCollision/CollisionShapes/btConvexShape.cpp", - "BulletCollision/CollisionShapes/btConvex2dShape.cpp", - "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp", - "BulletCollision/CollisionShapes/btCylinderShape.cpp", - "BulletCollision/CollisionShapes/btEmptyShape.cpp", - "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp", - "BulletCollision/CollisionShapes/btMiniSDF.cpp", - "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp", - "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp", - "BulletCollision/CollisionShapes/btMultiSphereShape.cpp", - "BulletCollision/CollisionShapes/btOptimizedBvh.cpp", - "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp", - "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp", - "BulletCollision/CollisionShapes/btSdfCollisionShape.cpp", - "BulletCollision/CollisionShapes/btShapeHull.cpp", - "BulletCollision/CollisionShapes/btSphereShape.cpp", - "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp", - "BulletCollision/CollisionShapes/btStridingMeshInterface.cpp", - "BulletCollision/CollisionShapes/btTetrahedronShape.cpp", - "BulletCollision/CollisionShapes/btTriangleBuffer.cpp", - "BulletCollision/CollisionShapes/btTriangleCallback.cpp", - "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp", - "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp", - "BulletCollision/CollisionShapes/btTriangleMesh.cpp", - "BulletCollision/CollisionShapes/btTriangleMeshShape.cpp", - "BulletCollision/CollisionShapes/btUniformScalingShape.cpp", - "BulletCollision/Gimpact/btContactProcessing.cpp", - "BulletCollision/Gimpact/btGenericPoolAllocator.cpp", - "BulletCollision/Gimpact/btGImpactBvh.cpp", - "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp", - "BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp", - "BulletCollision/Gimpact/btGImpactShape.cpp", - "BulletCollision/Gimpact/btTriangleShapeEx.cpp", - "BulletCollision/Gimpact/gim_box_set.cpp", - "BulletCollision/Gimpact/gim_contact.cpp", - "BulletCollision/Gimpact/gim_memory.cpp", - "BulletCollision/Gimpact/gim_tri_collision.cpp", - "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp", - "BulletCollision/NarrowPhaseCollision/btConvexCast.cpp", - "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp", - "BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp", - "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp", - "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp", - "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp", - "BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp", - "BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp", - "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp", - "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp", - "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp", - # BulletDynamics - "BulletDynamics/Character/btKinematicCharacterController.cpp", - "BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp", - "BulletDynamics/ConstraintSolver/btContactConstraint.cpp", - "BulletDynamics/ConstraintSolver/btFixedConstraint.cpp", - "BulletDynamics/ConstraintSolver/btGearConstraint.cpp", - "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp", - "BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp", - "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp", - "BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp", - "BulletDynamics/ConstraintSolver/btHingeConstraint.cpp", - "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp", - "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp", - "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp", - "BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp", - "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp", - "BulletDynamics/ConstraintSolver/btSliderConstraint.cpp", - "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp", - "BulletDynamics/ConstraintSolver/btTypedConstraint.cpp", - "BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp", - "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp", - "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp", - "BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp", - "BulletDynamics/Dynamics/btRigidBody.cpp", - "BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp", - # "BulletDynamics/Dynamics/Bullet-C-API.cpp", - "BulletDynamics/Vehicle/btRaycastVehicle.cpp", - "BulletDynamics/Vehicle/btWheelInfo.cpp", - "BulletDynamics/Featherstone/btMultiBody.cpp", - "BulletDynamics/Featherstone/btMultiBodyConstraint.cpp", - "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp", - "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp", - "BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp", - "BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp", - "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp", - "BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp", - "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp", - "BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp", - "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp", - "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp", - "BulletDynamics/MLCPSolvers/btDantzigLCP.cpp", - "BulletDynamics/MLCPSolvers/btMLCPSolver.cpp", - "BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp", - # BulletInverseDynamics - "BulletInverseDynamics/IDMath.cpp", - "BulletInverseDynamics/MultiBodyTree.cpp", - "BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp", - "BulletInverseDynamics/details/MultiBodyTreeImpl.cpp", - # BulletSoftBody - "BulletSoftBody/btSoftBody.cpp", - "BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp", - "BulletSoftBody/btSoftBodyHelpers.cpp", - "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp", - "BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp", - "BulletSoftBody/btSoftRigidDynamicsWorld.cpp", - "BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp", - "BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp", - "BulletSoftBody/btDefaultSoftBodySolver.cpp", - "BulletSoftBody/btDeformableBackwardEulerObjective.cpp", - "BulletSoftBody/btDeformableBodySolver.cpp", - "BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp", - "BulletSoftBody/btDeformableContactProjection.cpp", - "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp", - "BulletSoftBody/btDeformableContactConstraint.cpp", - "BulletSoftBody/poly34.cpp", - # clew - "clew/clew.c", - # LinearMath - "LinearMath/btAlignedAllocator.cpp", - "LinearMath/btConvexHull.cpp", - "LinearMath/btConvexHullComputer.cpp", - "LinearMath/btGeometryUtil.cpp", - "LinearMath/btPolarDecomposition.cpp", - "LinearMath/btQuickprof.cpp", - "LinearMath/btReducedVector.cpp", - "LinearMath/btSerializer.cpp", - "LinearMath/btSerializer64.cpp", - "LinearMath/btThreads.cpp", - "LinearMath/btVector3.cpp", - "LinearMath/TaskScheduler/btTaskScheduler.cpp", - "LinearMath/TaskScheduler/btThreadSupportPosix.cpp", - "LinearMath/TaskScheduler/btThreadSupportWin32.cpp", - ] - - thirdparty_sources = [thirdparty_dir + file for file in bullet2_src] - - env_bullet.Prepend(CPPPATH=[thirdparty_dir]) - if env["target"] == "debug" or env["target"] == "release_debug": - env_bullet.Append(CPPDEFINES=["DEBUG"]) - - env_bullet.Append(CPPDEFINES=["BT_USE_OLD_DAMPING_METHOD", "BT_THREADSAFE"]) - - env_thirdparty = env_bullet.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_bullet.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/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp deleted file mode 100644 index 10a71d65df..0000000000 --- a/modules/bullet/area_bullet.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/*************************************************************************/ -/* area_bullet.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 "area_bullet.h" - -#include "bullet_physics_server.h" -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "collision_object_bullet.h" -#include "space_bullet.h" - -#include <BulletCollision/CollisionDispatch/btGhostObject.h> -#include <btBulletCollisionCommon.h> - -/** - @author AndreaCatania -*/ - -AreaBullet::AreaBullet() : - RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA) { - btGhost = bulletnew(btGhostObject); - reload_shapes(); - setupBulletCollisionObject(btGhost); - /// Collision objects with a callback still have collision response with dynamic rigid bodies. - /// In order to use collision objects as trigger, you have to disable the collision response. - set_collision_enabled(false); - - for (int i = 0; i < 5; ++i) { - call_event_res_ptr[i] = &call_event_res[i]; - } -} - -AreaBullet::~AreaBullet() { - // signal are handled by godot, so just clear without notify - for (int i = 0; i < overlapping_shapes.size(); i++) { - overlapping_shapes[i].other_object->on_exit_area(this); - } -} - -void AreaBullet::dispatch_callbacks() { - if (!isScratched) { - return; - } - isScratched = false; - - // Reverse order so items can be removed. - for (int i = overlapping_shapes.size() - 1; i >= 0; i--) { - OverlappingShapeData &overlapping_shape = overlapping_shapes.write[i]; - - switch (overlapping_shape.state) { - case OVERLAP_STATE_ENTER: - overlapping_shape.state = OVERLAP_STATE_INSIDE; - call_event(overlapping_shape, PhysicsServer3D::AREA_BODY_ADDED); - if (_overlapping_shape_count(overlapping_shape.other_object) == 1) { - // This object's first shape being added. - overlapping_shape.other_object->on_enter_area(this); - } - break; - case OVERLAP_STATE_EXIT: - call_event(overlapping_shape, PhysicsServer3D::AREA_BODY_REMOVED); - if (_overlapping_shape_count(overlapping_shape.other_object) == 1) { - // This object's last shape being removed. - overlapping_shape.other_object->on_exit_area(this); - } - overlapping_shapes.remove_at(i); // Remove after callback - break; - case OVERLAP_STATE_INSIDE: { - if (overlapping_shape.other_object->getType() == TYPE_RIGID_BODY) { - RigidBodyBullet *body = static_cast<RigidBodyBullet *>(overlapping_shape.other_object); - body->scratch_space_override_modificator(); - } - break; - } - case OVERLAP_STATE_DIRTY: - break; - } - } -} - -void AreaBullet::call_event(const OverlappingShapeData &p_overlapping_shape, PhysicsServer3D::AreaBodyStatus p_status) { - InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_overlapping_shape.other_object->getType())]; - - if (!event.event_callback.is_valid()) { - event.event_callback = Callable(); - return; - } - - call_event_res[0] = p_status; - call_event_res[1] = p_overlapping_shape.other_object->get_self(); // RID - call_event_res[2] = p_overlapping_shape.other_object->get_instance_id(); // Object ID - call_event_res[3] = p_overlapping_shape.other_shape_id; // Other object's shape ID - call_event_res[4] = p_overlapping_shape.our_shape_id; // This area's shape ID - - Callable::CallError outResp; - Variant ret; - event.event_callback.call((const Variant **)call_event_res, 5, ret, outResp); -} - -int AreaBullet::_overlapping_shape_count(CollisionObjectBullet *p_other_object) { - int count = 0; - for (int i = 0; i < overlapping_shapes.size(); i++) { - if (overlapping_shapes[i].other_object == p_other_object) { - count++; - } - } - return count; -} - -int AreaBullet::_find_overlapping_shape(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id) { - for (int i = 0; i < overlapping_shapes.size(); i++) { - const OverlappingShapeData &overlapping_shape = overlapping_shapes[i]; - if (overlapping_shape.other_object == p_other_object && overlapping_shape.other_shape_id == p_other_shape_id && overlapping_shape.our_shape_id == p_our_shape_id) { - return i; - } - } - return -1; -} - -void AreaBullet::mark_all_overlaps_dirty() { - OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw(); - for (int i = 0; i < overlapping_shapes.size(); i++) { - // Don't overwrite OVERLAP_STATE_ENTER state. - if (overlapping_shapes_w[i].state != OVERLAP_STATE_ENTER) { - overlapping_shapes_w[i].state = OVERLAP_STATE_DIRTY; - } - } -} - -void AreaBullet::mark_object_overlaps_inside(CollisionObjectBullet *p_other_object) { - OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw(); - for (int i = 0; i < overlapping_shapes.size(); i++) { - if (overlapping_shapes_w[i].other_object == p_other_object && overlapping_shapes_w[i].state == OVERLAP_STATE_DIRTY) { - overlapping_shapes_w[i].state = OVERLAP_STATE_INSIDE; - } - } -} - -void AreaBullet::set_overlap(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id) { - int i = _find_overlapping_shape(p_other_object, p_other_shape_id, p_our_shape_id); - if (i == -1) { // Not found, create new one. - OverlappingShapeData overlapping_shape(p_other_object, OVERLAP_STATE_ENTER, p_other_shape_id, p_our_shape_id); - overlapping_shapes.push_back(overlapping_shape); - p_other_object->notify_new_overlap(this); - isScratched = true; - } else { - overlapping_shapes.ptrw()[i].state = OVERLAP_STATE_INSIDE; - } -} - -void AreaBullet::mark_all_dirty_overlaps_as_exit() { - OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw(); - for (int i = 0; i < overlapping_shapes.size(); i++) { - if (overlapping_shapes[i].state == OVERLAP_STATE_DIRTY) { - overlapping_shapes_w[i].state = OVERLAP_STATE_EXIT; - isScratched = true; - } - } -} - -void AreaBullet::remove_object_overlaps(CollisionObjectBullet *p_object) { - // Reverse order so items can be removed. - for (int i = overlapping_shapes.size() - 1; i >= 0; i--) { - if (overlapping_shapes[i].other_object == p_object) { - overlapping_shapes.remove_at(i); - } - } -} - -void AreaBullet::clear_overlaps() { - for (int i = 0; i < overlapping_shapes.size(); i++) { - call_event(overlapping_shapes[i], PhysicsServer3D::AREA_BODY_REMOVED); - overlapping_shapes[i].other_object->on_exit_area(this); - } - overlapping_shapes.clear(); -} - -void AreaBullet::set_monitorable(bool p_monitorable) { - monitorable = p_monitorable; - updated = true; -} - -bool AreaBullet::is_monitoring() const { - return get_godot_object_flags() & GOF_IS_MONITORING_AREA; -} - -void AreaBullet::main_shape_changed() { - CRASH_COND(!get_main_shape()); - btGhost->setCollisionShape(get_main_shape()); - updated = true; -} - -void AreaBullet::reload_body() { - if (space) { - space->remove_area(this); - space->add_area(this); - } -} - -void AreaBullet::set_space(SpaceBullet *p_space) { - // Clear the old space if there is one - if (space) { - clear_overlaps(); - isScratched = false; - - // Remove this object form the physics world - space->remove_area(this); - } - - space = p_space; - - if (space) { - space->add_area(this); - } -} - -void AreaBullet::on_collision_filters_change() { - if (space) { - space->reload_collision_filters(this); - } - updated = true; -} - -void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) { - switch (p_param) { - case PhysicsServer3D::AREA_PARAM_GRAVITY: - set_spOv_gravityMag(p_value); - break; - case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: - set_spOv_gravityVec(p_value); - break; - case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: - set_spOv_linearDump(p_value); - break; - case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: - set_spOv_angularDump(p_value); - break; - case PhysicsServer3D::AREA_PARAM_PRIORITY: - set_spOv_priority(p_value); - break; - case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: - set_spOv_gravityPoint(p_value); - break; - case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: - set_spOv_gravityPointDistanceScale(p_value); - break; - case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: - set_spOv_gravityPointAttenuation(p_value); - break; - default: - WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param)); - } - isScratched = true; -} - -Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const { - switch (p_param) { - case PhysicsServer3D::AREA_PARAM_GRAVITY: - return spOv_gravityMag; - case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: - return spOv_gravityVec; - case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: - return spOv_linearDump; - case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: - return spOv_angularDump; - case PhysicsServer3D::AREA_PARAM_PRIORITY: - return spOv_priority; - case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: - return spOv_gravityPoint; - case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: - return spOv_gravityPointDistanceScale; - case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: - return spOv_gravityPointAttenuation; - default: - WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param)); - return Variant(); - } -} - -void AreaBullet::set_event_callback(Type p_callbackObjectType, const Callable &p_callback) { - InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)]; - ev.event_callback = p_callback; - - /// Set if monitoring - if (!eventsCallbacks[0].event_callback.is_null() || !eventsCallbacks[1].event_callback.is_null()) { - set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA); - } else { - set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA)); - clear_overlaps(); - } -} - -bool AreaBullet::has_event_callback(Type p_callbackObjectType) { - return !eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback.is_null(); -} - -void AreaBullet::on_enter_area(AreaBullet *p_area) { -} - -void AreaBullet::on_exit_area(AreaBullet *p_area) { - CollisionObjectBullet::on_exit_area(p_area); -} diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h deleted file mode 100644 index 3bff364cc1..0000000000 --- a/modules/bullet/area_bullet.h +++ /dev/null @@ -1,166 +0,0 @@ -/*************************************************************************/ -/* area_bullet.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 AREABULLET_H -#define AREABULLET_H - -#include "collision_object_bullet.h" -#include "core/templates/vector.h" -#include "servers/physics_server_3d.h" -#include "space_bullet.h" - -/** - @author AndreaCatania -*/ - -class btGhostObject; - -class AreaBullet : public RigidCollisionObjectBullet { -public: - struct InOutEventCallback { - Callable event_callback; - - InOutEventCallback() {} - }; - - enum OverlapState { - OVERLAP_STATE_DIRTY = 0, // Mark processed overlaps - OVERLAP_STATE_INSIDE, // Mark old overlap - OVERLAP_STATE_ENTER, // Mark just enter overlap - OVERLAP_STATE_EXIT // Mark ended overlaps - }; - - struct OverlappingShapeData { - CollisionObjectBullet *other_object = nullptr; - OverlapState state = OVERLAP_STATE_DIRTY; - uint32_t other_shape_id = 0; - uint32_t our_shape_id = 0; - - OverlappingShapeData() {} - - OverlappingShapeData(CollisionObjectBullet *p_other_object, OverlapState p_state, uint32_t p_other_shape_id, uint32_t p_our_shape_id) : - other_object(p_other_object), - state(p_state), - other_shape_id(p_other_shape_id), - our_shape_id(p_our_shape_id) {} - }; - -private: - // These are used by function callEvent. Instead to create this each call I create if one time. - Variant call_event_res[5]; - Variant *call_event_res_ptr[5] = {}; - - btGhostObject *btGhost = nullptr; - Vector<OverlappingShapeData> overlapping_shapes; - int _overlapping_shape_count(CollisionObjectBullet *p_other_object); - int _find_overlapping_shape(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id); - bool monitorable = true; - - PhysicsServer3D::AreaSpaceOverrideMode spOv_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; - bool spOv_gravityPoint = false; - real_t spOv_gravityPointDistanceScale = 0.0; - real_t spOv_gravityPointAttenuation = 1.0; - Vector3 spOv_gravityVec = Vector3(0, -1, 0); - real_t spOv_gravityMag = 10.0; - real_t spOv_linearDump = 0.1; - real_t spOv_angularDump = 0.1; - int spOv_priority = 0; - - bool isScratched = false; - - InOutEventCallback eventsCallbacks[2]; - -public: - AreaBullet(); - ~AreaBullet(); - - _FORCE_INLINE_ btGhostObject *get_bt_ghost() const { return btGhost; } - - void set_monitorable(bool p_monitorable); - _FORCE_INLINE_ bool is_monitorable() const { return monitorable; } - - bool is_monitoring() const; - - _FORCE_INLINE_ void set_spOv_mode(PhysicsServer3D::AreaSpaceOverrideMode p_mode) { spOv_mode = p_mode; } - _FORCE_INLINE_ PhysicsServer3D::AreaSpaceOverrideMode get_spOv_mode() { return spOv_mode; } - - _FORCE_INLINE_ void set_spOv_gravityPoint(bool p_isGP) { spOv_gravityPoint = p_isGP; } - _FORCE_INLINE_ bool is_spOv_gravityPoint() { return spOv_gravityPoint; } - - _FORCE_INLINE_ void set_spOv_gravityPointDistanceScale(real_t p_GPDS) { spOv_gravityPointDistanceScale = p_GPDS; } - _FORCE_INLINE_ real_t get_spOv_gravityPointDistanceScale() { return spOv_gravityPointDistanceScale; } - - _FORCE_INLINE_ void set_spOv_gravityPointAttenuation(real_t p_GPA) { spOv_gravityPointAttenuation = p_GPA; } - _FORCE_INLINE_ real_t get_spOv_gravityPointAttenuation() { return spOv_gravityPointAttenuation; } - - _FORCE_INLINE_ void set_spOv_gravityVec(Vector3 p_vec) { spOv_gravityVec = p_vec; } - _FORCE_INLINE_ const Vector3 &get_spOv_gravityVec() const { return spOv_gravityVec; } - - _FORCE_INLINE_ void set_spOv_gravityMag(real_t p_gravityMag) { spOv_gravityMag = p_gravityMag; } - _FORCE_INLINE_ real_t get_spOv_gravityMag() { return spOv_gravityMag; } - - _FORCE_INLINE_ void set_spOv_linearDump(real_t p_linearDump) { spOv_linearDump = p_linearDump; } - _FORCE_INLINE_ real_t get_spOv_linearDamp() { return spOv_linearDump; } - - _FORCE_INLINE_ void set_spOv_angularDump(real_t p_angularDump) { spOv_angularDump = p_angularDump; } - _FORCE_INLINE_ real_t get_spOv_angularDamp() { return spOv_angularDump; } - - _FORCE_INLINE_ void set_spOv_priority(int p_priority) { spOv_priority = p_priority; } - _FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; } - - virtual void main_shape_changed(); - virtual void reload_body(); - virtual void set_space(SpaceBullet *p_space); - - virtual void dispatch_callbacks(); - void call_event(const OverlappingShapeData &p_overlapping_shape, PhysicsServer3D::AreaBodyStatus p_status); - - virtual void on_collision_filters_change(); - virtual void on_collision_checker_start() {} - virtual void on_collision_checker_end() { updated = false; } - - void mark_all_overlaps_dirty(); - void mark_object_overlaps_inside(CollisionObjectBullet *p_other_object); - void set_overlap(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id); - void mark_all_dirty_overlaps_as_exit(); - void remove_object_overlaps(CollisionObjectBullet *p_object); - void clear_overlaps(); - - void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value); - Variant get_param(PhysicsServer3D::AreaParameter p_param) const; - - void set_event_callback(Type p_callbackObjectType, const Callable &p_callback); - bool has_event_callback(Type p_callbackObjectType); - - virtual void on_enter_area(AreaBullet *p_area); - virtual void on_exit_area(AreaBullet *p_area); -}; - -#endif diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp deleted file mode 100644 index 109854c9dd..0000000000 --- a/modules/bullet/btRayShape.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************/ -/* btRayShape.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 "btRayShape.h" - -#include "core/math/math_funcs.h" - -#include <LinearMath/btAabbUtil2.h> - -/** - @author AndreaCatania -*/ - -btRayShape::btRayShape(btScalar length) : - btConvexInternalShape() { - m_shapeType = CUSTOM_CONVEX_SHAPE_TYPE; - setLength(length); -} - -btRayShape::~btRayShape() { -} - -void btRayShape::setLength(btScalar p_length) { - m_length = p_length; - reload_cache(); -} - -void btRayShape::setMargin(btScalar margin) { - btConvexInternalShape::setMargin(margin); - reload_cache(); -} - -void btRayShape::setSlipsOnSlope(bool p_slipsOnSlope) { - slipsOnSlope = p_slipsOnSlope; -} - -btVector3 btRayShape::localGetSupportingVertex(const btVector3 &vec) const { - return localGetSupportingVertexWithoutMargin(vec) + (m_shapeAxis * m_collisionMargin); -} - -btVector3 btRayShape::localGetSupportingVertexWithoutMargin(const btVector3 &vec) const { - if (vec.z() > 0) { - return m_shapeAxis * m_cacheScaledLength; - } else { - return btVector3(0, 0, 0); - } -} - -void btRayShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const { - for (int i = 0; i < numVectors; ++i) { - supportVerticesOut[i] = localGetSupportingVertexWithoutMargin(vectors[i]); - } -} - -void btRayShape::getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const { - btVector3 localAabbMin(0, 0, 0); - btVector3 localAabbMax(m_shapeAxis * m_cacheScaledLength); - btTransformAabb(localAabbMin, localAabbMax, m_collisionMargin, t, aabbMin, aabbMax); -} - -void btRayShape::calculateLocalInertia(btScalar mass, btVector3 &inertia) const { - inertia.setZero(); -} - -int btRayShape::getNumPreferredPenetrationDirections() const { - return 0; -} - -void btRayShape::getPreferredPenetrationDirection(int index, btVector3 &penetrationVector) const { - penetrationVector.setZero(); -} - -void btRayShape::reload_cache() { - m_cacheScaledLength = m_length * m_localScaling[2]; - - m_cacheSupportPoint.setIdentity(); - m_cacheSupportPoint.setOrigin(m_shapeAxis * m_cacheScaledLength); -} diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h deleted file mode 100644 index 330755aa31..0000000000 --- a/modules/bullet/btRayShape.h +++ /dev/null @@ -1,95 +0,0 @@ -/*************************************************************************/ -/* btRayShape.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. */ -/*************************************************************************/ - -/// IMPORTANT The class name and filename was created by following Bullet writing rules for an easy (eventually) porting to bullet -/// This shape is a custom shape that is not present to Bullet physics engine -#ifndef BTRAYSHAPE_H -#define BTRAYSHAPE_H - -#include <BulletCollision/CollisionShapes/btConvexInternalShape.h> - -/** - @author AndreaCatania -*/ - -/// Ray shape around z axis -ATTRIBUTE_ALIGNED16(class) -btRayShape : public btConvexInternalShape { - btScalar m_length = 0; - bool slipsOnSlope = false; - /// The default axis is the z - btVector3 m_shapeAxis = btVector3(0, 0, 1); - - btTransform m_cacheSupportPoint; - btScalar m_cacheScaledLength; - -public: - BT_DECLARE_ALIGNED_ALLOCATOR(); - - btRayShape(btScalar length); - virtual ~btRayShape(); - - void setLength(btScalar p_length); - btScalar getLength() const { return m_length; } - - virtual void setMargin(btScalar margin); - - void setSlipsOnSlope(bool p_slipsOnSlope); - bool getSlipsOnSlope() const { return slipsOnSlope; } - - const btTransform &getSupportPoint() const { return m_cacheSupportPoint; } - const btScalar &getScaledLength() const { return m_cacheScaledLength; } - - virtual btVector3 localGetSupportingVertex(const btVector3 &vec) const; -#ifndef __SPU__ - virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3 &vec) const; -#endif //#ifndef __SPU__ - - virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const; - - ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. - virtual void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const; - -#ifndef __SPU__ - virtual void calculateLocalInertia(btScalar mass, btVector3 & inertia) const; - - virtual const char *getName() const { - return "RayZ"; - } -#endif //__SPU__ - - virtual int getNumPreferredPenetrationDirections() const; - virtual void getPreferredPenetrationDirection(int index, btVector3 &penetrationVector) const; - -private: - void reload_cache(); -}; - -#endif // BTRAYSHAPE_H diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp deleted file mode 100644 index 684a20cf4d..0000000000 --- a/modules/bullet/bullet_physics_server.cpp +++ /dev/null @@ -1,1539 +0,0 @@ -/*************************************************************************/ -/* bullet_physics_server.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 "bullet_physics_server.h" - -#include "bullet_utilities.h" -#include "cone_twist_joint_bullet.h" -#include "core/error/error_macros.h" -#include "core/object/class_db.h" -#include "core/string/ustring.h" -#include "generic_6dof_joint_bullet.h" -#include "hinge_joint_bullet.h" -#include "pin_joint_bullet.h" -#include "shape_bullet.h" -#include "slider_joint_bullet.h" - -#include <LinearMath/btVector3.h> - -#include <assert.h> - -/** - @author AndreaCatania -*/ - -#define CreateThenReturnRID(owner, ridData) \ - RID rid = owner.make_rid(ridData); \ - ridData->set_self(rid); \ - ridData->_set_physics_server(this); \ - return rid; - -// <--------------- Joint creation asserts -/// Assert the body is assigned to a space -#define JointAssertSpace(body, bIndex, ret) \ - if (!body->get_space()) { \ - ERR_PRINT("Before create a joint the Body" + String(bIndex) + " must be added to a space!"); \ - return ret; \ - } - -/// Assert the two bodies of joint are in the same space -#define JointAssertSameSpace(bodyA, bodyB, ret) \ - if (bodyA->get_space() != bodyB->get_space()) { \ - ERR_PRINT("In order to create a joint the Body_A and Body_B must be in the same space!"); \ - return RID(); \ - } - -#define AddJointToSpace(body, joint) \ - body->get_space()->add_constraint(joint, joint->is_disabled_collisions_between_bodies()); -// <--------------- Joint creation asserts - -void BulletPhysicsServer3D::_bind_methods() { - //ClassDB::bind_method(D_METHOD("DoTest"), &BulletPhysicsServer3D::DoTest); -} - -BulletPhysicsServer3D::BulletPhysicsServer3D() : - PhysicsServer3D() {} - -BulletPhysicsServer3D::~BulletPhysicsServer3D() {} - -RID BulletPhysicsServer3D::shape_create(ShapeType p_shape) { - ShapeBullet *shape = nullptr; - - switch (p_shape) { - case SHAPE_WORLD_BOUNDARY: { - shape = bulletnew(WorldBoundaryShapeBullet); - } break; - case SHAPE_SPHERE: { - shape = bulletnew(SphereShapeBullet); - } break; - case SHAPE_BOX: { - shape = bulletnew(BoxShapeBullet); - } break; - case SHAPE_CAPSULE: { - shape = bulletnew(CapsuleShapeBullet); - } break; - case SHAPE_CYLINDER: { - shape = bulletnew(CylinderShapeBullet); - } break; - case SHAPE_CONVEX_POLYGON: { - shape = bulletnew(ConvexPolygonShapeBullet); - } break; - case SHAPE_CONCAVE_POLYGON: { - shape = bulletnew(ConcavePolygonShapeBullet); - } break; - case SHAPE_HEIGHTMAP: { - shape = bulletnew(HeightMapShapeBullet); - } break; - case SHAPE_RAY: { - shape = bulletnew(RayShapeBullet); - } break; - case SHAPE_CUSTOM: - default: - ERR_FAIL_V(RID()); - break; - } - - CreateThenReturnRID(shape_owner, shape) -} - -void BulletPhysicsServer3D::shape_set_data(RID p_shape, const Variant &p_data) { - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND(!shape); - shape->set_data(p_data); -} - -void BulletPhysicsServer3D::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { - //WARN_PRINT("Bias not supported by Bullet physics engine"); -} - -PhysicsServer3D::ShapeType BulletPhysicsServer3D::shape_get_type(RID p_shape) const { - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, PhysicsServer3D::SHAPE_CUSTOM); - return shape->get_type(); -} - -Variant BulletPhysicsServer3D::shape_get_data(RID p_shape) const { - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, Variant()); - return shape->get_data(); -} - -void BulletPhysicsServer3D::shape_set_margin(RID p_shape, real_t p_margin) { - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND(!shape); - shape->set_margin(p_margin); -} - -real_t BulletPhysicsServer3D::shape_get_margin(RID p_shape) const { - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, 0.0); - return shape->get_margin(); -} - -real_t BulletPhysicsServer3D::shape_get_custom_solver_bias(RID p_shape) const { - //WARN_PRINT("Bias not supported by Bullet physics engine"); - return 0.; -} - -RID BulletPhysicsServer3D::space_create() { - SpaceBullet *space = bulletnew(SpaceBullet); - CreateThenReturnRID(space_owner, space); -} - -void BulletPhysicsServer3D::space_set_active(RID p_space, bool p_active) { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND(!space); - - if (space_is_active(p_space) == p_active) { - return; - } - - if (p_active) { - ++active_spaces_count; - active_spaces.push_back(space); - } else { - --active_spaces_count; - active_spaces.erase(space); - } -} - -bool BulletPhysicsServer3D::space_is_active(RID p_space) const { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND_V(!space, false); - - return -1 != active_spaces.find(space); -} - -void BulletPhysicsServer3D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND(!space); - space->set_param(p_param, p_value); -} - -real_t BulletPhysicsServer3D::space_get_param(RID p_space, SpaceParameter p_param) const { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND_V(!space, 0); - return space->get_param(p_param); -} - -PhysicsDirectSpaceState3D *BulletPhysicsServer3D::space_get_direct_state(RID p_space) { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND_V(!space, nullptr); - - return space->get_direct_state(); -} - -void BulletPhysicsServer3D::space_set_debug_contacts(RID p_space, int p_max_contacts) { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND(!space); - - space->set_debug_contacts(p_max_contacts); -} - -Vector<Vector3> BulletPhysicsServer3D::space_get_contacts(RID p_space) const { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND_V(!space, Vector<Vector3>()); - - return space->get_debug_contacts(); -} - -int BulletPhysicsServer3D::space_get_contact_count(RID p_space) const { - SpaceBullet *space = space_owner.get_or_null(p_space); - ERR_FAIL_COND_V(!space, 0); - - return space->get_debug_contact_count(); -} - -RID BulletPhysicsServer3D::area_create() { - AreaBullet *area = bulletnew(AreaBullet); - area->set_collision_layer(1); - area->set_collision_mask(1); - CreateThenReturnRID(area_owner, area) -} - -void BulletPhysicsServer3D::area_set_space(RID p_area, RID p_space) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - SpaceBullet *space = nullptr; - if (p_space.is_valid()) { - space = space_owner.get_or_null(p_space); - ERR_FAIL_COND(!space); - } - area->set_space(space); -} - -RID BulletPhysicsServer3D::area_get_space(RID p_area) const { - AreaBullet *area = area_owner.get_or_null(p_area); - return area->get_space()->get_self(); -} - -void BulletPhysicsServer3D::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_spOv_mode(p_mode); -} - -PhysicsServer3D::AreaSpaceOverrideMode BulletPhysicsServer3D::area_get_space_override_mode(RID p_area) const { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED); - - return area->get_spOv_mode(); -} - -void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND(!shape); - - area->add_shape(shape, p_transform, p_disabled); -} - -void BulletPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND(!shape); - - area->set_shape(p_shape_idx, shape); -} - -void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_shape_transform(p_shape_idx, p_transform); -} - -int BulletPhysicsServer3D::area_get_shape_count(RID p_area) const { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, 0); - - return area->get_shape_count(); -} - -RID BulletPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, RID()); - - return area->get_shape(p_shape_idx)->get_self(); -} - -Transform3D BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, Transform3D()); - - return area->get_shape_transform(p_shape_idx); -} - -void BulletPhysicsServer3D::area_remove_shape(RID p_area, int p_shape_idx) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - return area->remove_shape_full(p_shape_idx); -} - -void BulletPhysicsServer3D::area_clear_shapes(RID p_area) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - for (int i = area->get_shape_count(); 0 < i; --i) { - area->remove_shape_full(0); - } -} - -void BulletPhysicsServer3D::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_shape_disabled(p_shape_idx, p_disabled); -} - -void BulletPhysicsServer3D::area_attach_object_instance_id(RID p_area, ObjectID p_id) { - if (space_owner.owns(p_area)) { - return; - } - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - area->set_instance_id(p_id); -} - -ObjectID BulletPhysicsServer3D::area_get_object_instance_id(RID p_area) const { - if (space_owner.owns(p_area)) { - return ObjectID(); - } - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, ObjectID()); - return area->get_instance_id(); -} - -void BulletPhysicsServer3D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { - if (space_owner.owns(p_area)) { - SpaceBullet *space = space_owner.get_or_null(p_area); - if (space) { - space->set_param(p_param, p_value); - } - } else { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_param(p_param, p_value); - } -} - -Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param) const { - if (space_owner.owns(p_area)) { - SpaceBullet *space = space_owner.get_or_null(p_area); - return space->get_param(p_param); - } else { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, Variant()); - - return area->get_param(p_param); - } -} - -void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform3D &p_transform) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - area->set_transform(p_transform); -} - -Transform3D BulletPhysicsServer3D::area_get_transform(RID p_area) const { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND_V(!area, Transform3D()); - return area->get_transform(); -} - -void BulletPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - area->set_collision_mask(p_mask); -} - -void BulletPhysicsServer3D::area_set_collision_layer(RID p_area, uint32_t p_layer) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - area->set_collision_layer(p_layer); -} - -void BulletPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_monitorable(p_monitorable); -} - -void BulletPhysicsServer3D::area_set_monitor_callback(RID p_area, const Callable &p_callback) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_callback.is_valid() ? p_callback : Callable()); -} - -void BulletPhysicsServer3D::area_set_area_monitor_callback(RID p_area, const Callable &p_callback) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - - area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_callback.is_valid() ? p_callback : Callable()); -} - -void BulletPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) { - AreaBullet *area = area_owner.get_or_null(p_area); - ERR_FAIL_COND(!area); - area->set_ray_pickable(p_enable); -} - -RID BulletPhysicsServer3D::body_create(BodyMode p_mode, bool p_init_sleeping) { - RigidBodyBullet *body = bulletnew(RigidBodyBullet); - body->set_mode(p_mode); - body->set_collision_layer(1); - body->set_collision_mask(1); - if (p_init_sleeping) { - body->set_state(BODY_STATE_SLEEPING, p_init_sleeping); - } - CreateThenReturnRID(rigid_body_owner, body); -} - -void BulletPhysicsServer3D::body_set_space(RID p_body, RID p_space) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - SpaceBullet *space = nullptr; - - if (p_space.is_valid()) { - space = space_owner.get_or_null(p_space); - ERR_FAIL_COND(!space); - } - - if (body->get_space() == space) { - return; //pointless - } - - body->set_space(space); -} - -RID BulletPhysicsServer3D::body_get_space(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, RID()); - - SpaceBullet *space = body->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -} - -void BulletPhysicsServer3D::body_set_mode(RID p_body, PhysicsServer3D::BodyMode p_mode) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_mode(p_mode); -} - -PhysicsServer3D::BodyMode BulletPhysicsServer3D::body_get_mode(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); - return body->get_mode(); -} - -void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND(!shape); - - body->add_shape(shape, p_transform, p_disabled); -} - -void BulletPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - ShapeBullet *shape = shape_owner.get_or_null(p_shape); - ERR_FAIL_COND(!shape); - - body->set_shape(p_shape_idx, shape); -} - -void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_shape_transform(p_shape_idx, p_transform); -} - -int BulletPhysicsServer3D::body_get_shape_count(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - return body->get_shape_count(); -} - -RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, RID()); - - ShapeBullet *shape = body->get_shape(p_shape_idx); - ERR_FAIL_COND_V(!shape, RID()); - - return shape->get_self(); -} - -Transform3D BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, Transform3D()); - return body->get_shape_transform(p_shape_idx); -} - -void BulletPhysicsServer3D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_shape_disabled(p_shape_idx, p_disabled); -} - -void BulletPhysicsServer3D::body_remove_shape(RID p_body, int p_shape_idx) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->remove_shape_full(p_shape_idx); -} - -void BulletPhysicsServer3D::body_clear_shapes(RID p_body) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->remove_all_shapes(); -} - -void BulletPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { - CollisionObjectBullet *body = get_collision_object(p_body); - ERR_FAIL_COND(!body); - - body->set_instance_id(p_id); -} - -ObjectID BulletPhysicsServer3D::body_get_object_instance_id(RID p_body) const { - CollisionObjectBullet *body = get_collision_object(p_body); - ERR_FAIL_COND_V(!body, ObjectID()); - - return body->get_instance_id(); -} - -void BulletPhysicsServer3D::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_continuous_collision_detection(p_enable); -} - -bool BulletPhysicsServer3D::body_is_continuous_collision_detection_enabled(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, false); - - return body->is_continuous_collision_detection_enabled(); -} - -void BulletPhysicsServer3D::body_set_collision_layer(RID p_body, uint32_t p_layer) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_collision_layer(p_layer); -} - -uint32_t BulletPhysicsServer3D::body_get_collision_layer(RID p_body) const { - const RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_layer(); -} - -void BulletPhysicsServer3D::body_set_collision_mask(RID p_body, uint32_t p_mask) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_collision_mask(p_mask); -} - -uint32_t BulletPhysicsServer3D::body_get_collision_mask(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_mask(); -} - -void BulletPhysicsServer3D::body_set_user_flags(RID p_body, uint32_t p_flags) { - // This function is not currently supported -} - -uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const { - // This function is not currently supported - return 0; -} - -void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_param(p_param, p_value); -} - -real_t BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_param(p_param); -} - -void BulletPhysicsServer3D::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - if (body->get_kinematic_utilities()) { - body->get_kinematic_utilities()->setSafeMargin(p_margin); - } -} - -real_t BulletPhysicsServer3D::body_get_kinematic_safe_margin(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - if (body->get_kinematic_utilities()) { - return body->get_kinematic_utilities()->safe_margin; - } - - return 0; -} - -void BulletPhysicsServer3D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_state(p_state, p_variant); -} - -Variant BulletPhysicsServer3D::body_get_state(RID p_body, BodyState p_state) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, Variant()); - - return body->get_state(p_state); -} - -void BulletPhysicsServer3D::body_set_applied_force(RID p_body, const Vector3 &p_force) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_applied_force(p_force); -} - -Vector3 BulletPhysicsServer3D::body_get_applied_force(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, Vector3()); - return body->get_applied_force(); -} - -void BulletPhysicsServer3D::body_set_applied_torque(RID p_body, const Vector3 &p_torque) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_applied_torque(p_torque); -} - -Vector3 BulletPhysicsServer3D::body_get_applied_torque(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, Vector3()); - - return body->get_applied_torque(); -} - -void BulletPhysicsServer3D::body_add_central_force(RID p_body, const Vector3 &p_force) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->apply_central_force(p_force); -} - -void BulletPhysicsServer3D::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->apply_force(p_force, p_position); -} - -void BulletPhysicsServer3D::body_add_torque(RID p_body, const Vector3 &p_torque) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->apply_torque(p_torque); -} - -void BulletPhysicsServer3D::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->apply_central_impulse(p_impulse); -} - -void BulletPhysicsServer3D::body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->apply_impulse(p_impulse, p_position); -} - -void BulletPhysicsServer3D::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->apply_torque_impulse(p_impulse); -} - -void BulletPhysicsServer3D::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - Vector3 v = body->get_linear_velocity(); - Vector3 axis = p_axis_velocity.normalized(); - v -= axis * axis.dot(v); - v += p_axis_velocity; - body->set_linear_velocity(v); -} - -void BulletPhysicsServer3D::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_axis_lock(p_axis, p_lock); -} - -bool BulletPhysicsServer3D::body_is_axis_locked(RID p_body, BodyAxis p_axis) const { - const RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - return body->is_axis_locked(p_axis); -} - -void BulletPhysicsServer3D::body_add_collision_exception(RID p_body, RID p_body_b) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - RigidBodyBullet *other_body = rigid_body_owner.get_or_null(p_body_b); - ERR_FAIL_COND(!other_body); - - body->add_collision_exception(other_body); -} - -void BulletPhysicsServer3D::body_remove_collision_exception(RID p_body, RID p_body_b) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - RigidBodyBullet *other_body = rigid_body_owner.get_or_null(p_body_b); - ERR_FAIL_COND(!other_body); - - body->remove_collision_exception(other_body); -} - -void BulletPhysicsServer3D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - for (int i = 0; i < body->get_exceptions().size(); i++) { - p_exceptions->push_back(body->get_exceptions()[i]); - } -} - -void BulletPhysicsServer3D::body_set_max_contacts_reported(RID p_body, int p_contacts) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_max_collisions_detection(p_contacts); -} - -int BulletPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_max_collisions_detection(); -} - -void BulletPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { - // Not supported by bullet and even Godot -} - -real_t BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const { - // Not supported by bullet and even Godot - return 0.; -} - -void BulletPhysicsServer3D::body_set_omit_force_integration(RID p_body, bool p_omit) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_omit_forces_integration(p_omit); -} - -bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, false); - - return body->get_omit_forces_integration(); -} - -void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_force_integration_callback(p_callable, p_udata); -} - -void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_ray_pickable(p_enable); -} - -PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_body) { - if (!rigid_body_owner.owns(p_body)) { - return nullptr; - } - - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, nullptr); - - if (!body->get_space()) { - return nullptr; - } - - return BulletPhysicsDirectBodyState3D::get_singleton(body); -} - -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, const Set<RID> &p_exclude) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, false); - ERR_FAIL_COND_V(!body->get_space(), false); - - return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes, p_exclude); -} - -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.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - ERR_FAIL_COND_V(!body->get_space(), 0); - - return body->get_space()->test_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); -} - -RID BulletPhysicsServer3D::soft_body_create(bool p_init_sleeping) { - SoftBodyBullet *body = bulletnew(SoftBodyBullet); - body->set_collision_layer(1); - body->set_collision_mask(1); - if (p_init_sleeping) { - body->set_activation_state(false); - } - CreateThenReturnRID(soft_body_owner, body); -} - -void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->update_rendering_server(p_rendering_server_handler); -} - -void BulletPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - SpaceBullet *space = nullptr; - - if (p_space.is_valid()) { - space = space_owner.get_or_null(p_space); - ERR_FAIL_COND(!space); - } - - if (body->get_space() == space) { - return; //pointless - } - - body->set_space(space); -} - -RID BulletPhysicsServer3D::soft_body_get_space(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, RID()); - - SpaceBullet *space = body->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -} - -void BulletPhysicsServer3D::soft_body_set_mesh(RID p_body, RID p_mesh) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_soft_mesh(p_mesh); -} - -AABB BulletPhysicsServer::soft_body_get_bounds(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get(p_body); - ERR_FAIL_COND_V(!body, AABB()); - - return body->get_bounds(); -} - -void BulletPhysicsServer3D::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_collision_layer(p_layer); -} - -uint32_t BulletPhysicsServer3D::soft_body_get_collision_layer(RID p_body) const { - const SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_layer(); -} - -void BulletPhysicsServer3D::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_collision_mask(p_mask); -} - -uint32_t BulletPhysicsServer3D::soft_body_get_collision_mask(RID p_body) const { - const SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_mask(); -} - -void BulletPhysicsServer3D::soft_body_add_collision_exception(RID p_body, RID p_body_b) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - CollisionObjectBullet *other_body = rigid_body_owner.get_or_null(p_body_b); - if (!other_body) { - other_body = soft_body_owner.get_or_null(p_body_b); - } - ERR_FAIL_COND(!other_body); - - body->add_collision_exception(other_body); -} - -void BulletPhysicsServer3D::soft_body_remove_collision_exception(RID p_body, RID p_body_b) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - CollisionObjectBullet *other_body = rigid_body_owner.get_or_null(p_body_b); - if (!other_body) { - other_body = soft_body_owner.get_or_null(p_body_b); - } - ERR_FAIL_COND(!other_body); - - body->remove_collision_exception(other_body); -} - -void BulletPhysicsServer3D::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - for (int i = 0; i < body->get_exceptions().size(); i++) { - p_exceptions->push_back(body->get_exceptions()[i]); - } -} - -void BulletPhysicsServer3D::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { - // FIXME: Must be implemented. - WARN_PRINT("soft_body_state is not implemented yet in Bullet backend."); -} - -Variant BulletPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state) const { - // FIXME: Must be implemented. - WARN_PRINT("soft_body_state is not implemented yet in Bullet backend."); - return Variant(); -} - -void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform3D &p_transform) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - - body->set_soft_transform(p_transform); -} - -void BulletPhysicsServer3D::soft_body_set_ray_pickable(RID p_body, bool p_enable) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_ray_pickable(p_enable); -} - -void BulletPhysicsServer3D::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_simulation_precision(p_simulation_precision); -} - -int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_simulation_precision(); -} - -void BulletPhysicsServer3D::soft_body_set_total_mass(RID p_body, real_t p_total_mass) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_total_mass(p_total_mass); -} - -real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_total_mass(); -} - -void BulletPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_linear_stiffness(p_stiffness); -} - -real_t BulletPhysicsServer3D::soft_body_get_linear_stiffness(RID p_body) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_linear_stiffness(); -} - -void BulletPhysicsServer3D::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_pressure_coefficient(p_pressure_coefficient); -} - -real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_pressure_coefficient(); -} - -void BulletPhysicsServer3D::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_damping_coefficient(p_damping_coefficient); -} - -real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_damping_coefficient(); -} - -void BulletPhysicsServer3D::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_drag_coefficient(p_drag_coefficient); -} - -real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_drag_coefficient(); -} - -void BulletPhysicsServer3D::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_node_position(p_point_index, p_global_position); -} - -Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.)); - Vector3 pos; - body->get_node_position(p_point_index, pos); - return pos; -} - -void BulletPhysicsServer3D::soft_body_remove_all_pinned_points(RID p_body) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->reset_all_node_mass(); -} - -void BulletPhysicsServer3D::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND(!body); - body->set_node_mass(p_point_index, p_pin ? 0 : 1); -} - -bool BulletPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) const { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_body); - ERR_FAIL_COND_V(!body, 0.f); - return body->get_node_mass(p_point_index); -} - -PhysicsServer3D::JointType BulletPhysicsServer3D::joint_get_type(RID p_joint) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, JOINT_PIN); - return joint->get_type(); -} - -void BulletPhysicsServer3D::joint_set_solver_priority(RID p_joint, int p_priority) { - // Joint priority not supported by bullet -} - -int BulletPhysicsServer3D::joint_get_solver_priority(RID p_joint) const { - // Joint priority not supported by bullet - return 0; -} - -void BulletPhysicsServer3D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - - joint->disable_collisions_between_bodies(p_disable); -} - -bool BulletPhysicsServer3D::joint_is_disabled_collisions_between_bodies(RID p_joint) const { - JointBullet *joint(joint_owner.get_or_null(p_joint)); - ERR_FAIL_COND_V(!joint, false); - - return joint->is_disabled_collisions_between_bodies(); -} - -RID BulletPhysicsServer3D::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { - RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); - - JointAssertSpace(body_A, "A", RID()); - - RigidBodyBullet *body_B = nullptr; - if (p_body_B.is_valid()) { - body_B = rigid_body_owner.get_or_null(p_body_B); - JointAssertSpace(body_B, "B", RID()); - JointAssertSameSpace(body_A, body_B, RID()); - } - - ERR_FAIL_COND_V(body_A == body_B, RID()); - - JointBullet *joint = bulletnew(PinJointBullet(body_A, p_local_A, body_B, p_local_B)); - AddJointToSpace(body_A, joint); - - CreateThenReturnRID(joint_owner, joint); -} - -void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_PIN); - PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); - pin_joint->set_param(p_param, p_value); -} - -real_t BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0); - PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); - return pin_joint->get_param(p_param); -} - -void BulletPhysicsServer3D::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_PIN); - PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); - pin_joint->setPivotInA(p_A); -} - -Vector3 BulletPhysicsServer3D::pin_joint_get_local_a(RID p_joint) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, Vector3()); - ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3()); - PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); - return pin_joint->getPivotInA(); -} - -void BulletPhysicsServer3D::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_PIN); - PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); - pin_joint->setPivotInB(p_B); -} - -Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, Vector3()); - ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3()); - PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint); - return pin_joint->getPivotInB(); -} - -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.get_or_null(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); - JointAssertSpace(body_A, "A", RID()); - - RigidBodyBullet *body_B = nullptr; - if (p_body_B.is_valid()) { - body_B = rigid_body_owner.get_or_null(p_body_B); - JointAssertSpace(body_B, "B", RID()); - JointAssertSameSpace(body_A, body_B, RID()); - } - - ERR_FAIL_COND_V(body_A == body_B, RID()); - - JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_hinge_A, p_hinge_B)); - AddJointToSpace(body_A, joint); - - CreateThenReturnRID(joint_owner, joint); -} - -RID BulletPhysicsServer3D::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) { - RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); - JointAssertSpace(body_A, "A", RID()); - - RigidBodyBullet *body_B = nullptr; - if (p_body_B.is_valid()) { - body_B = rigid_body_owner.get_or_null(p_body_B); - JointAssertSpace(body_B, "B", RID()); - JointAssertSameSpace(body_A, body_B, RID()); - } - - ERR_FAIL_COND_V(body_A == body_B, RID()); - - JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); - AddJointToSpace(body_A, joint); - - CreateThenReturnRID(joint_owner, joint); -} - -void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); - HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); - hinge_joint->set_param(p_param, p_value); -} - -real_t BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0); - HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); - return hinge_joint->get_param(p_param); -} - -void BulletPhysicsServer3D::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); - HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); - hinge_joint->set_flag(p_flag, p_value); -} - -bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, false); - ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false); - HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint); - return hinge_joint->get_flag(p_flag); -} - -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.get_or_null(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); - JointAssertSpace(body_A, "A", RID()); - - RigidBodyBullet *body_B = nullptr; - if (p_body_B.is_valid()) { - body_B = rigid_body_owner.get_or_null(p_body_B); - JointAssertSpace(body_B, "B", RID()); - JointAssertSameSpace(body_A, body_B, RID()); - } - - ERR_FAIL_COND_V(body_A == body_B, RID()); - - JointBullet *joint = bulletnew(SliderJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint); - - CreateThenReturnRID(joint_owner, joint); -} - -void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER); - SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint); - slider_joint->set_param(p_param, p_value); -} - -real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0); - SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint); - return slider_joint->get_param(p_param); -} - -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.get_or_null(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); - JointAssertSpace(body_A, "A", RID()); - - RigidBodyBullet *body_B = nullptr; - if (p_body_B.is_valid()) { - body_B = rigid_body_owner.get_or_null(p_body_B); - JointAssertSpace(body_B, "B", RID()); - JointAssertSameSpace(body_A, body_B, RID()); - } - - JointBullet *joint = bulletnew(ConeTwistJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint); - - CreateThenReturnRID(joint_owner, joint); -} - -void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST); - ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint); - coneTwist_joint->set_param(p_param, p_value); -} - -real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, 0.); - ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.); - ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint); - return coneTwist_joint->get_param(p_param); -} - -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.get_or_null(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); - JointAssertSpace(body_A, "A", RID()); - - RigidBodyBullet *body_B = nullptr; - if (p_body_B.is_valid()) { - body_B = rigid_body_owner.get_or_null(p_body_B); - JointAssertSpace(body_B, "B", RID()); - JointAssertSameSpace(body_A, body_B, RID()); - } - - ERR_FAIL_COND_V(body_A == body_B, RID()); - - JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint); - - CreateThenReturnRID(joint_owner, joint); -} - -void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); - Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); - generic_6dof_joint->set_param(p_axis, p_param, p_value); -} - -real_t BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0); - Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); - return generic_6dof_joint->get_param(p_axis, p_param); -} - -void BulletPhysicsServer3D::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); - Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); - generic_6dof_joint->set_flag(p_axis, p_flag, p_enable); -} - -bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) { - JointBullet *joint = joint_owner.get_or_null(p_joint); - ERR_FAIL_COND_V(!joint, false); - ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false); - Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); - return generic_6dof_joint->get_flag(p_axis, p_flag); -} - -void BulletPhysicsServer3D::free(RID p_rid) { - if (shape_owner.owns(p_rid)) { - ShapeBullet *shape = shape_owner.get_or_null(p_rid); - - // Notify the shape is configured - for (const KeyValue<ShapeOwnerBullet *, int> &element : shape->get_owners()) { - static_cast<ShapeOwnerBullet *>(element.key)->remove_shape_full(shape); - } - - shape_owner.free(p_rid); - bulletdelete(shape); - } else if (rigid_body_owner.owns(p_rid)) { - RigidBodyBullet *body = rigid_body_owner.get_or_null(p_rid); - - body->set_space(nullptr); - - body->remove_all_shapes(true, true); - - rigid_body_owner.free(p_rid); - bulletdelete(body); - - } else if (soft_body_owner.owns(p_rid)) { - SoftBodyBullet *body = soft_body_owner.get_or_null(p_rid); - - body->set_space(nullptr); - - soft_body_owner.free(p_rid); - bulletdelete(body); - - } else if (area_owner.owns(p_rid)) { - AreaBullet *area = area_owner.get_or_null(p_rid); - - area->set_space(nullptr); - - area->remove_all_shapes(true, true); - - area_owner.free(p_rid); - bulletdelete(area); - - } else if (joint_owner.owns(p_rid)) { - JointBullet *joint = joint_owner.get_or_null(p_rid); - joint->destroy_internal_constraint(); - joint_owner.free(p_rid); - bulletdelete(joint); - - } else if (space_owner.owns(p_rid)) { - SpaceBullet *space = space_owner.get_or_null(p_rid); - - space->remove_all_collision_objects(); - - space_set_active(p_rid, false); - space_owner.free(p_rid); - bulletdelete(space); - } else { - ERR_FAIL_MSG("Invalid ID."); - } -} - -void BulletPhysicsServer3D::init() { - BulletPhysicsDirectBodyState3D::initSingleton(); -} - -void BulletPhysicsServer3D::step(real_t p_deltaTime) { - if (!active) { - return; - } - - BulletPhysicsDirectBodyState3D::singleton_setDeltaTime(p_deltaTime); - - for (int i = 0; i < active_spaces_count; ++i) { - active_spaces[i]->step(p_deltaTime); - } -} - -void BulletPhysicsServer3D::flush_queries() { - if (!active) { - return; - } - - for (int i = 0; i < active_spaces_count; ++i) { - active_spaces[i]->flush_queries(); - } -} - -void BulletPhysicsServer3D::finish() { - BulletPhysicsDirectBodyState3D::destroySingleton(); -} - -int BulletPhysicsServer3D::get_process_info(ProcessInfo p_info) { - return 0; -} - -SpaceBullet *BulletPhysicsServer3D::get_space(RID p_rid) const { - ERR_FAIL_COND_V_MSG(space_owner.owns(p_rid) == false, nullptr, "The RID is not valid."); - return space_owner.get_or_null(p_rid); -} - -ShapeBullet *BulletPhysicsServer3D::get_shape(RID p_rid) const { - ERR_FAIL_COND_V_MSG(shape_owner.owns(p_rid) == false, nullptr, "The RID is not valid."); - return shape_owner.get_or_null(p_rid); -} - -CollisionObjectBullet *BulletPhysicsServer3D::get_collision_object(RID p_object) const { - if (rigid_body_owner.owns(p_object)) { - return rigid_body_owner.get_or_null(p_object); - } - if (area_owner.owns(p_object)) { - return area_owner.get_or_null(p_object); - } - if (soft_body_owner.owns(p_object)) { - return soft_body_owner.get_or_null(p_object); - } - ERR_FAIL_V_MSG(nullptr, "The RID is no valid."); -} - -RigidCollisionObjectBullet *BulletPhysicsServer3D::get_rigid_collision_object(RID p_object) const { - if (rigid_body_owner.owns(p_object)) { - return rigid_body_owner.get_or_null(p_object); - } - if (area_owner.owns(p_object)) { - return area_owner.get_or_null(p_object); - } - ERR_FAIL_V_MSG(nullptr, "The RID is no valid."); -} - -JointBullet *BulletPhysicsServer3D::get_joint(RID p_rid) const { - ERR_FAIL_COND_V_MSG(joint_owner.owns(p_rid) == false, nullptr, "The RID is not valid."); - return joint_owner.get_or_null(p_rid); -} diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h deleted file mode 100644 index 94635b5bfc..0000000000 --- a/modules/bullet/bullet_physics_server.h +++ /dev/null @@ -1,398 +0,0 @@ -/*************************************************************************/ -/* bullet_physics_server.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 BULLET_PHYSICS_SERVER_H -#define BULLET_PHYSICS_SERVER_H - -#include "area_bullet.h" -#include "core/templates/rid.h" -#include "core/templates/rid_owner.h" -#include "joint_bullet.h" -#include "rigid_body_bullet.h" -#include "servers/physics_server_3d.h" -#include "shape_bullet.h" -#include "soft_body_bullet.h" -#include "space_bullet.h" - -/** - @author AndreaCatania -*/ - -class BulletPhysicsServer3D : public PhysicsServer3D { - GDCLASS(BulletPhysicsServer3D, PhysicsServer3D); - - friend class BulletPhysicsDirectSpaceState; - - bool active = true; - char active_spaces_count = 0; - Vector<SpaceBullet *> active_spaces; - - mutable RID_PtrOwner<SpaceBullet> space_owner; - mutable RID_PtrOwner<ShapeBullet> shape_owner; - mutable RID_PtrOwner<AreaBullet> area_owner; - mutable RID_PtrOwner<RigidBodyBullet> rigid_body_owner; - mutable RID_PtrOwner<SoftBodyBullet> soft_body_owner; - mutable RID_PtrOwner<JointBullet> joint_owner; - -protected: - static void _bind_methods(); - -public: - BulletPhysicsServer3D(); - ~BulletPhysicsServer3D(); - - _FORCE_INLINE_ RID_PtrOwner<SpaceBullet> *get_space_owner() { - return &space_owner; - } - _FORCE_INLINE_ RID_PtrOwner<ShapeBullet> *get_shape_owner() { - return &shape_owner; - } - _FORCE_INLINE_ RID_PtrOwner<AreaBullet> *get_area_owner() { - return &area_owner; - } - _FORCE_INLINE_ RID_PtrOwner<RigidBodyBullet> *get_rigid_body_owner() { - return &rigid_body_owner; - } - _FORCE_INLINE_ RID_PtrOwner<SoftBodyBullet> *get_soft_body_owner() { - return &soft_body_owner; - } - _FORCE_INLINE_ RID_PtrOwner<JointBullet> *get_joint_owner() { - return &joint_owner; - } - - /* SHAPE API */ - virtual RID shape_create(ShapeType p_shape) override; - virtual void shape_set_data(RID p_shape, const Variant &p_data) override; - virtual ShapeType shape_get_type(RID p_shape) const override; - virtual Variant shape_get_data(RID p_shape) const override; - - virtual void shape_set_margin(RID p_shape, real_t p_margin) override; - virtual real_t shape_get_margin(RID p_shape) const override; - - /// Not supported - virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias) override; - /// Not supported - virtual real_t shape_get_custom_solver_bias(RID p_shape) const override; - - /* SPACE API */ - - virtual RID space_create() override; - virtual void space_set_active(RID p_space, bool p_active) override; - virtual bool space_is_active(RID p_space) const override; - - /// Not supported - virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) override; - /// Not supported - virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const override; - - virtual PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) override; - - virtual void space_set_debug_contacts(RID p_space, int p_max_contacts) override; - virtual Vector<Vector3> space_get_contacts(RID p_space) const override; - virtual int space_get_contact_count(RID p_space) const override; - - /* AREA API */ - - /// Bullet Physics Engine not support "Area", this must be handled by the game developer in another way. - /// Since godot Physics use the concept of area even to define the main world, the API area_set_param is used to set initial physics world information. - /// The API area_set_param is a bit hacky, and allow Godot to set some parameters on Bullet's world, a different use print a warning to console. - /// All other APIs returns a warning message if used - - virtual RID area_create() override; - - virtual void area_set_space(RID p_area, RID p_space) override; - - virtual RID area_get_space(RID p_area) const override; - - 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 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 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 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; - virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id) override; - virtual ObjectID area_get_object_instance_id(RID p_area) const override; - - /// If you pass as p_area the SpaceBullet you can set some parameters as specified below - /// AREA_PARAM_GRAVITY - /// AREA_PARAM_GRAVITY_VECTOR - /// Otherwise you can set area parameters - 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 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; - - virtual void area_set_monitorable(RID p_area, bool p_monitorable) override; - virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override; - virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override; - virtual void area_set_ray_pickable(RID p_area, bool p_enable) override; - - /* RIGID BODY API */ - - 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; - - 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 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 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 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; - - virtual void body_remove_shape(RID p_body, int p_shape_idx) override; - virtual void body_clear_shapes(RID p_body) override; - - // Used for Rigid and Soft Bodies - virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) override; - virtual ObjectID body_get_object_instance_id(RID p_body) const override; - - virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) override; - virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const override; - - virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) override; - virtual uint32_t body_get_collision_layer(RID p_body) const override; - - virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; - virtual uint32_t body_get_collision_mask(RID p_body) const override; - - /// This is not supported by physics server - virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override; - /// This is not supported by physics server - virtual uint32_t body_get_user_flags(RID p_body) const override; - - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; - - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) override; - virtual real_t body_get_kinematic_safe_margin(RID p_body) const override; - - virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; - virtual Variant body_get_state(RID p_body, BodyState p_state) const override; - - virtual void body_set_applied_force(RID p_body, const Vector3 &p_force) override; - virtual Vector3 body_get_applied_force(RID p_body) const override; - - virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque) override; - virtual Vector3 body_get_applied_torque(RID p_body) const override; - - virtual void body_add_central_force(RID p_body, const Vector3 &p_force) override; - virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position = Vector3()) override; - virtual void body_add_torque(RID p_body, const Vector3 &p_torque) override; - - virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) override; - virtual void body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override; - virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) override; - virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) override; - - virtual void body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) override; - virtual bool body_is_axis_locked(RID p_body, BodyAxis p_axis) const override; - - virtual void body_add_collision_exception(RID p_body, RID p_body_b) override; - virtual void body_remove_collision_exception(RID p_body, RID p_body_b) override; - virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override; - - virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override; - virtual int body_get_max_contacts_reported(RID p_body) const override; - - virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) override; - virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const override; - - 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, 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 Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) 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 */ - - virtual RID soft_body_create(bool p_init_sleeping = false) override; - - virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) override; - - virtual void soft_body_set_space(RID p_body, RID p_space) override; - virtual RID soft_body_get_space(RID p_body) const override; - - virtual void soft_body_set_mesh(RID p_body, RID p_mesh) override; - - virtual AABB soft_body_get_bounds(RID p_body) const override; - - virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override; - virtual uint32_t soft_body_get_collision_layer(RID p_body) const override; - - virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override; - virtual uint32_t soft_body_get_collision_mask(RID p_body) const override; - - virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override; - virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override; - virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override; - - virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; - 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 Transform3D &p_transform) override; - - virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override; - - virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override; - virtual int soft_body_get_simulation_precision(RID p_body) const override; - - virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override; - virtual real_t soft_body_get_total_mass(RID p_body) const override; - - virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override; - virtual real_t soft_body_get_linear_stiffness(RID p_body) const override; - - virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override; - virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override; - - virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override; - virtual real_t soft_body_get_damping_coefficient(RID p_body) const override; - - virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override; - virtual real_t soft_body_get_drag_coefficient(RID p_body) const override; - - virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override; - virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override; - - virtual void soft_body_remove_all_pinned_points(RID p_body) override; - virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override; - virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override; - - /* JOINT API */ - - virtual JointType joint_get_type(RID p_joint) const override; - - virtual void joint_set_solver_priority(RID p_joint, int p_priority) override; - virtual int joint_get_solver_priority(RID p_joint) const override; - - virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) override; - virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const override; - - virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override; - - virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override; - virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override; - - virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) override; - virtual Vector3 pin_joint_get_local_a(RID p_joint) const override; - - 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 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; - virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override; - - virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override; - 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 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 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 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; - - virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) override; - virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) override; - - /* MISC */ - - virtual void free(RID p_rid) override; - - virtual void set_active(bool p_active) override { - active = p_active; - } - - static bool singleton_isActive() { - return static_cast<BulletPhysicsServer3D *>(get_singleton())->active; - } - - bool isActive() { - return active; - } - - virtual void init() override; - virtual void step(real_t p_deltaTime) override; - virtual void flush_queries() override; - virtual void finish() override; - - virtual bool is_flushing_queries() const override { return false; } - - virtual int get_process_info(ProcessInfo p_info) override; - - SpaceBullet *get_space(RID p_rid) const; - ShapeBullet *get_shape(RID p_rid) const; - CollisionObjectBullet *get_collision_object(RID p_object) const; - RigidCollisionObjectBullet *get_rigid_collision_object(RID p_object) const; - JointBullet *get_joint(RID p_rid) const; -}; - -#endif diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp deleted file mode 100644 index 01461767bd..0000000000 --- a/modules/bullet/bullet_types_converter.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/*************************************************************************/ -/* bullet_types_converter.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 "bullet_types_converter.h" - -/** - @author AndreaCatania -*/ - -// ++ BULLET to GODOT ++++++++++ -void B_TO_G(btVector3 const &inVal, Vector3 &outVal) { - outVal[0] = inVal[0]; - outVal[1] = inVal[1]; - outVal[2] = inVal[2]; -} - -void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal) { - outVal[0] = inVal[0] != 0. ? 1. / inVal[0] : 0.; - outVal[1] = inVal[1] != 0. ? 1. / inVal[1] : 0.; - outVal[2] = inVal[2] != 0. ? 1. / inVal[2] : 0.; -} - -void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) { - B_TO_G(inVal[0], outVal[0]); - B_TO_G(inVal[1], outVal[1]); - B_TO_G(inVal[2], outVal[2]); -} - -void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) { - INVERT_B_TO_G(inVal[0], outVal[0]); - INVERT_B_TO_G(inVal[1], outVal[1]); - INVERT_B_TO_G(inVal[2], outVal[2]); -} - -void B_TO_G(btTransform const &inVal, Transform3D &outVal) { - B_TO_G(inVal.getBasis(), outVal.basis); - B_TO_G(inVal.getOrigin(), outVal.origin); -} - -// ++ GODOT to BULLET ++++++++++ -void G_TO_B(Vector3 const &inVal, btVector3 &outVal) { - outVal[0] = inVal[0]; - outVal[1] = inVal[1]; - outVal[2] = inVal[2]; -} - -void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal) { - outVal[0] = inVal[0] != 0. ? 1. / inVal[0] : 0.; - outVal[1] = inVal[1] != 0. ? 1. / inVal[1] : 0.; - outVal[2] = inVal[2] != 0. ? 1. / inVal[2] : 0.; -} - -void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) { - G_TO_B(inVal[0], outVal[0]); - G_TO_B(inVal[1], outVal[1]); - G_TO_B(inVal[2], outVal[2]); -} - -void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) { - INVERT_G_TO_B(inVal[0], outVal[0]); - INVERT_G_TO_B(inVal[1], outVal[1]); - INVERT_G_TO_B(inVal[2], outVal[2]); -} - -void G_TO_B(Transform3D const &inVal, btTransform &outVal) { - G_TO_B(inVal.basis, outVal.getBasis()); - G_TO_B(inVal.origin, outVal.getOrigin()); -} - -void UNSCALE_BT_BASIS(btTransform &scaledBasis) { - btMatrix3x3 &basis(scaledBasis.getBasis()); - btVector3 column0 = basis.getColumn(0); - btVector3 column1 = basis.getColumn(1); - btVector3 column2 = basis.getColumn(2); - - // Check for zero scaling. - if (column0.fuzzyZero()) { - if (column1.fuzzyZero()) { - if (column2.fuzzyZero()) { - // All dimensions are fuzzy zero. Create a default basis. - column0 = btVector3(1, 0, 0); - column1 = btVector3(0, 1, 0); - column2 = btVector3(0, 0, 1); - } else { // Column 2 scale not fuzzy zero. - // Create two vectors orthogonal to row 2. - // Ensure that a default basis is created if row 2 = <0, 0, 1> - column1 = btVector3(0, column2[2], -column2[1]); - column0 = column1.cross(column2); - } - } else { // Column 1 scale not fuzzy zero. - if (column2.fuzzyZero()) { - // Create two vectors orthogonal to column 1. - // Ensure that a default basis is created if column 1 = <0, 1, 0> - column0 = btVector3(column1[1], -column1[0], 0); - column2 = column0.cross(column1); - } else { // Column 1 and column 2 scales not fuzzy zero. - // Create column 0 orthogonal to column 1 and column 2. - column0 = column1.cross(column2); - } - } - } else { // Column 0 scale not fuzzy zero. - if (column1.fuzzyZero()) { - if (column2.fuzzyZero()) { - // Create two vectors orthogonal to column 0. - // Ensure that a default basis is created if column 0 = <1, 0, 0> - column2 = btVector3(-column0[2], 0, column0[0]); - column1 = column2.cross(column0); - } else { // Column 0 and column 2 scales not fuzzy zero. - // Create column 1 orthogonal to column 0 and column 2. - column1 = column2.cross(column0); - } - } else { // Column 0 and column 1 scales not fuzzy zero. - if (column2.fuzzyZero()) { - // Create column 2 orthogonal to column 0 and column 1. - column2 = column0.cross(column1); - } - } - } - - // Normalize - column0.normalize(); - column1.normalize(); - column2.normalize(); - - basis.setValue(column0[0], column1[0], column2[0], - column0[1], column1[1], column2[1], - column0[2], column1[2], column2[2]); -} diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h deleted file mode 100644 index e184fe1769..0000000000 --- a/modules/bullet/bullet_types_converter.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* bullet_types_converter.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 BULLET_TYPES_CONVERTER_H -#define BULLET_TYPES_CONVERTER_H - -#include "core/math/basis.h" -#include "core/math/transform_3d.h" -#include "core/math/vector3.h" -#include "core/typedefs.h" - -#include <LinearMath/btMatrix3x3.h> -#include <LinearMath/btTransform.h> -#include <LinearMath/btVector3.h> - -/** - @author AndreaCatania -*/ - -// Bullet to Godot -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, 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(Transform3D const &inVal, btTransform &outVal); - -extern void UNSCALE_BT_BASIS(btTransform &scaledBasis); -#endif diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h deleted file mode 100644 index a7c0fafbea..0000000000 --- a/modules/bullet/bullet_utilities.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************/ -/* bullet_utilities.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 BULLET_UTILITIES_H -#define BULLET_UTILITIES_H - -/** - @author AndreaCatania -*/ - -#define bulletnew(cl) \ - new cl - -#define bulletdelete(cl) \ - { \ - delete cl; \ - cl = nullptr; \ - } -#endif diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp deleted file mode 100644 index cbb746800d..0000000000 --- a/modules/bullet/collision_object_bullet.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/*************************************************************************/ -/* collision_object_bullet.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 "collision_object_bullet.h" - -#include "area_bullet.h" -#include "bullet_physics_server.h" -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "shape_bullet.h" -#include "space_bullet.h" - -#include <btBulletCollisionCommon.h> - -/** - @author AndreaCatania -*/ - -// We enable dynamic AABB tree so that we can actually perform a broadphase on bodies with compound collision shapes. -// This is crucial for the performance of kinematic bodies and for bodies with transforming shapes. -#define enableDynamicAabbTree true - -CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} - -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); -} - -void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_transform) { - transform = p_transform; -} - -btTransform CollisionObjectBullet::ShapeWrapper::get_adjusted_transform() const { - if (shape->get_type() == PhysicsServer3D::SHAPE_HEIGHTMAP) { - const HeightMapShapeBullet *hm_shape = (const HeightMapShapeBullet *)shape; // should be safe to cast now - btTransform adjusted_transform; - - // Bullet centers our heightmap: - // https://github.com/bulletphysics/bullet3/blob/master/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h#L33 - // This is really counter intuitive so we're adjusting for it - - adjusted_transform.setIdentity(); - adjusted_transform.setOrigin(btVector3(0.0, hm_shape->min_height + ((hm_shape->max_height - hm_shape->min_height) * 0.5), 0.0)); - adjusted_transform *= transform; - - return adjusted_transform; - } else { - return transform; - } -} - -void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_scale) { - if (!bt_shape) { - if (active) { - bt_shape = shape->create_bt_shape(scale * body_scale); - } else { - bt_shape = ShapeBullet::create_shape_empty(); - } - } -} - -CollisionObjectBullet::CollisionObjectBullet(Type p_type) : - RIDBullet(), - type(p_type) {} - -CollisionObjectBullet::~CollisionObjectBullet() { - for (int i = 0; i < areasOverlapped.size(); i++) { - areasOverlapped[i]->remove_object_overlaps(this); - } - destroyBulletCollisionObject(); -} - -bool equal(real_t first, real_t second) { - return Math::abs(first - second) <= 0.001f; -} - -void CollisionObjectBullet::set_body_scale(const Vector3 &p_new_scale) { - if (!equal(p_new_scale[0], body_scale[0]) || !equal(p_new_scale[1], body_scale[1]) || !equal(p_new_scale[2], body_scale[2])) { - body_scale = p_new_scale; - body_scale_changed(); - } -} - -btVector3 CollisionObjectBullet::get_bt_body_scale() const { - btVector3 s; - G_TO_B(body_scale, s); - return s; -} - -void CollisionObjectBullet::body_scale_changed() { - force_shape_reset = true; -} - -void CollisionObjectBullet::destroyBulletCollisionObject() { - bulletdelete(bt_collision_object); -} - -void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_collisionObject) { - bt_collision_object = p_collisionObject; - bt_collision_object->setUserPointer(this); - bt_collision_object->setUserIndex(type); - // Force the enabling of collision and avoid problems - set_collision_enabled(collisionsEnabled); - p_collisionObject->setCollisionFlags(p_collisionObject->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); -} - -void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { - exceptions.insert(p_ignoreCollisionObject->get_self()); - if (!bt_collision_object) { - return; - } - bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true); - if (space) { - space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher()); - } -} - -void CollisionObjectBullet::remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { - exceptions.erase(p_ignoreCollisionObject->get_self()); - if (!bt_collision_object) { - return; - } - bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, false); - if (space) { - space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher()); - } -} - -bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const { - return exceptions.has(p_otherCollisionObject->get_self()); -} - -void CollisionObjectBullet::set_collision_enabled(bool p_enabled) { - collisionsEnabled = p_enabled; - if (!bt_collision_object) { - return; - } - if (collisionsEnabled) { - bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() & (~btCollisionObject::CF_NO_CONTACT_RESPONSE)); - } else { - bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); - } -} - -bool CollisionObjectBullet::is_collisions_response_enabled() { - return collisionsEnabled; -} - -void CollisionObjectBullet::notify_new_overlap(AreaBullet *p_area) { - if (areasOverlapped.find(p_area) == -1) { - areasOverlapped.push_back(p_area); - } -} - -void CollisionObjectBullet::on_exit_area(AreaBullet *p_area) { - areasOverlapped.erase(p_area); -} - -void CollisionObjectBullet::set_godot_object_flags(int flags) { - bt_collision_object->setUserIndex2(flags); - updated = true; -} - -int CollisionObjectBullet::get_godot_object_flags() const { - return bt_collision_object->getUserIndex2(); -} - -void CollisionObjectBullet::set_transform(const Transform3D &p_global_transform) { - set_body_scale(p_global_transform.basis.get_scale_abs()); - - btTransform bt_transform; - G_TO_B(p_global_transform, bt_transform); - UNSCALE_BT_BASIS(bt_transform); - - set_transform__bullet(bt_transform); -} - -Transform3D CollisionObjectBullet::get_transform() const { - Transform3D t; - B_TO_G(get_transform__bullet(), t); - t.basis.scale(body_scale); - return t; -} - -void CollisionObjectBullet::set_transform__bullet(const btTransform &p_global_transform) { - bt_collision_object->setWorldTransform(p_global_transform); - notify_transform_changed(); -} - -const btTransform &CollisionObjectBullet::get_transform__bullet() const { - return bt_collision_object->getWorldTransform(); -} - -void CollisionObjectBullet::notify_transform_changed() { - updated = true; -} - -RigidCollisionObjectBullet::~RigidCollisionObjectBullet() { - remove_all_shapes(true, true); - if (mainShape && mainShape->isCompound()) { - bulletdelete(mainShape); - } -} - -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(); -} - -void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { - ShapeWrapper &shp = shapes.write[p_index]; - shp.shape->remove_owner(this); - p_shape->add_owner(this); - shp.shape = p_shape; - reload_shapes(); -} - -int RigidCollisionObjectBullet::get_shape_count() const { - return shapes.size(); -} - -ShapeBullet *RigidCollisionObjectBullet::get_shape(int p_index) const { - return shapes[p_index].shape; -} - -btCollisionShape *RigidCollisionObjectBullet::get_bt_shape(int p_index) const { - return shapes[p_index].bt_shape; -} - -int RigidCollisionObjectBullet::find_shape(ShapeBullet *p_shape) const { - const int size = shapes.size(); - for (int i = 0; i < size; ++i) { - if (shapes[i].shape == p_shape) { - return i; - } - } - return -1; -} - -void RigidCollisionObjectBullet::remove_shape_full(ShapeBullet *p_shape) { - // Remove the shape, all the times it appears - // Reverse order required for delete. - for (int i = shapes.size() - 1; 0 <= i; --i) { - if (p_shape == shapes[i].shape) { - internal_shape_destroy(i); - shapes.remove_at(i); - } - } - reload_shapes(); -} - -void RigidCollisionObjectBullet::remove_shape_full(int p_index) { - ERR_FAIL_INDEX(p_index, get_shape_count()); - internal_shape_destroy(p_index); - shapes.remove_at(p_index); - reload_shapes(); -} - -void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBody, bool p_force_not_reload) { - // Reverse order required for delete. - for (int i = shapes.size() - 1; 0 <= i; --i) { - internal_shape_destroy(i, p_permanentlyFromThisBody); - } - shapes.clear(); - if (!p_force_not_reload) { - reload_shapes(); - } -} - -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); - shape_changed(p_index); -} - -const btTransform &RigidCollisionObjectBullet::get_bt_shape_transform(int p_index) const { - return shapes[p_index].transform; -} - -Transform3D RigidCollisionObjectBullet::get_shape_transform(int p_index) const { - Transform3D trs; - B_TO_G(shapes[p_index].transform, trs); - return trs; -} - -void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) { - if (shapes[p_index].active != p_disabled) { - return; - } - shapes.write[p_index].active = !p_disabled; - shape_changed(p_index); -} - -bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) { - return !shapes[p_index].active; -} - -void RigidCollisionObjectBullet::shape_changed(int p_shape_index) { - ShapeWrapper &shp = shapes.write[p_shape_index]; - if (shp.bt_shape == mainShape) { - mainShape = nullptr; - } - bulletdelete(shp.bt_shape); - reload_shapes(); -} - -void RigidCollisionObjectBullet::reload_shapes() { - if (mainShape && mainShape->isCompound()) { - // Destroy compound - bulletdelete(mainShape); - } - - mainShape = nullptr; - - ShapeWrapper *shpWrapper; - const int shape_count = shapes.size(); - - // Reset shape if required - if (force_shape_reset) { - for (int i(0); i < shape_count; ++i) { - shpWrapper = &shapes.write[i]; - bulletdelete(shpWrapper->bt_shape); - } - force_shape_reset = false; - } - - const btVector3 body_scale(get_bt_body_scale()); - - // Try to optimize by not using compound - if (1 == shape_count) { - shpWrapper = &shapes.write[0]; - btTransform transform = shpWrapper->get_adjusted_transform(); - if (transform.getOrigin().isZero() && transform.getBasis() == transform.getBasis().getIdentity()) { - shpWrapper->claim_bt_shape(body_scale); - mainShape = shpWrapper->bt_shape; - main_shape_changed(); - return; - } - } - - // Optimization not possible use a compound shape - btCompoundShape *compoundShape = bulletnew(btCompoundShape(enableDynamicAabbTree, shape_count)); - - for (int i(0); i < shape_count; ++i) { - shpWrapper = &shapes.write[i]; - shpWrapper->claim_bt_shape(body_scale); - btTransform scaled_shape_transform(shpWrapper->get_adjusted_transform()); - scaled_shape_transform.getOrigin() *= body_scale; - compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape); - } - - compoundShape->recalculateLocalAabb(); - mainShape = compoundShape; - main_shape_changed(); -} - -void RigidCollisionObjectBullet::body_scale_changed() { - CollisionObjectBullet::body_scale_changed(); - reload_shapes(); -} - -void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) { - ShapeWrapper &shp = shapes.write[p_index]; - shp.shape->remove_owner(this, p_permanentlyFromThisBody); - if (shp.bt_shape == mainShape) { - mainShape = nullptr; - } - bulletdelete(shp.bt_shape); -} diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h deleted file mode 100644 index 6d2c564e44..0000000000 --- a/modules/bullet/collision_object_bullet.h +++ /dev/null @@ -1,259 +0,0 @@ -/*************************************************************************/ -/* collision_object_bullet.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 COLLISION_OBJECT_BULLET_H -#define COLLISION_OBJECT_BULLET_H - -#include "core/math/transform_3d.h" -#include "core/math/vector3.h" -#include "core/object/class_db.h" -#include "core/templates/vset.h" -#include "shape_owner_bullet.h" - -#include <LinearMath/btTransform.h> - -/** - @author AndreaCatania -*/ - -class AreaBullet; -class ShapeBullet; -class btCollisionObject; -class btCompoundShape; -class btCollisionShape; -class SpaceBullet; - -class CollisionObjectBullet : public RIDBullet { -public: - enum GodotObjectFlags { - GOF_IS_MONITORING_AREA = 1 << 0 - // FLAG2 = 1 << 1, - // FLAG3 = 1 << 2, - // FLAG4 = 1 << 3, - // FLAG5 = 1 << 4, - // FLAG6 = 1 << 5 - // etc.. - }; - enum Type { - TYPE_AREA = 0, - TYPE_RIGID_BODY, - TYPE_SOFT_BODY, - TYPE_KINEMATIC_GHOST_BODY - }; - - struct ShapeWrapper { - ShapeBullet *shape = nullptr; - btCollisionShape *bt_shape = nullptr; - btTransform transform; - btVector3 scale; - bool active = true; - - ShapeWrapper() {} - - ShapeWrapper(ShapeBullet *p_shape, const btTransform &p_transform, bool p_active) : - shape(p_shape), - active(p_active) { - set_transform(p_transform); - } - - ShapeWrapper(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_active) : - shape(p_shape), - active(p_active) { - set_transform(p_transform); - } - ~ShapeWrapper(); - - ShapeWrapper(const ShapeWrapper &otherShape) { - operator=(otherShape); - } - - void operator=(const ShapeWrapper &otherShape) { - shape = otherShape.shape; - bt_shape = otherShape.bt_shape; - transform = otherShape.transform; - scale = otherShape.scale; - active = otherShape.active; - } - - void set_transform(const Transform3D &p_transform); - void set_transform(const btTransform &p_transform); - btTransform get_adjusted_transform() const; - - void claim_bt_shape(const btVector3 &body_scale); - }; - -protected: - Type type = TYPE_AREA; - ObjectID instance_id; - uint32_t collisionLayer = 0; - uint32_t collisionMask = 0; - bool collisionsEnabled = true; - bool m_isStatic = false; - bool ray_pickable = false; - btCollisionObject *bt_collision_object = nullptr; - Vector3 body_scale = Vector3(1, 1, 1); - bool force_shape_reset = false; - SpaceBullet *space = nullptr; - - VSet<RID> exceptions; - - /// This array is used to know all areas where this Object is overlapped in - /// New area is added when overlap with new area (AreaBullet::addOverlap), then is removed when it exit (CollisionObjectBullet::onExitArea) - /// This array is used mainly to know which area hold the pointer of this object - Vector<AreaBullet *> areasOverlapped; - bool updated = false; - -public: - CollisionObjectBullet(Type p_type); - virtual ~CollisionObjectBullet(); - - Type getType() { return type; } - -protected: - void destroyBulletCollisionObject(); - void setupBulletCollisionObject(btCollisionObject *p_collisionObject); - -public: - _FORCE_INLINE_ btCollisionObject *get_bt_collision_object() { return bt_collision_object; } - - _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; } - _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; } - - _FORCE_INLINE_ bool is_static() const { return m_isStatic; } - - _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } - _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } - - void set_body_scale(const Vector3 &p_new_scale); - const Vector3 &get_body_scale() const { return body_scale; } - btVector3 get_bt_body_scale() const; - virtual void body_scale_changed(); - - void add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject); - void remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject); - bool has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const; - _FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; } - - _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { - if (collisionLayer != p_layer) { - collisionLayer = p_layer; - on_collision_filters_change(); - } - } - _FORCE_INLINE_ uint32_t get_collision_layer() const { return collisionLayer; } - - _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { - if (collisionMask != p_mask) { - collisionMask = p_mask; - on_collision_filters_change(); - } - } - _FORCE_INLINE_ uint32_t get_collision_mask() const { return collisionMask; } - - virtual void on_collision_filters_change() = 0; - - _FORCE_INLINE_ bool test_collision_mask(CollisionObjectBullet *p_other) const { - return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask; - } - - virtual void reload_body() = 0; - virtual void set_space(SpaceBullet *p_space) = 0; - _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } - - virtual void on_collision_checker_start() = 0; - virtual void on_collision_checker_end() = 0; - - virtual void dispatch_callbacks() = 0; - - void set_collision_enabled(bool p_enabled); - bool is_collisions_response_enabled(); - - void notify_new_overlap(AreaBullet *p_area); - virtual void on_enter_area(AreaBullet *p_area) = 0; - virtual void on_exit_area(AreaBullet *p_area); - - void set_godot_object_flags(int flags); - int get_godot_object_flags() 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; - virtual void notify_transform_changed(); - - bool is_updated() const { return updated; } -}; - -class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwnerBullet { -protected: - btCollisionShape *mainShape = nullptr; - Vector<ShapeWrapper> shapes; - -public: - RigidCollisionObjectBullet(Type p_type) : - CollisionObjectBullet(p_type) {} - ~RigidCollisionObjectBullet(); - - _FORCE_INLINE_ const Vector<ShapeWrapper> &get_shapes_wrappers() const { return shapes; } - - _FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; } - - 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; - ShapeBullet *get_shape(int p_index) const; - btCollisionShape *get_bt_shape(int p_index) const; - - int find_shape(ShapeBullet *p_shape) const; - - virtual void remove_shape_full(ShapeBullet *p_shape); - 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 Transform3D &p_transform); - - const btTransform &get_bt_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); - - virtual void shape_changed(int p_shape_index); - virtual void reload_shapes(); - - virtual void main_shape_changed() = 0; - virtual void body_scale_changed(); - -private: - void internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody = false); -}; - -#endif diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp deleted file mode 100644 index 34516d8b3b..0000000000 --- a/modules/bullet/cone_twist_joint_bullet.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/*************************************************************************/ -/* cone_twist_joint_bullet.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 "cone_twist_joint_bullet.h" - -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "rigid_body_bullet.h" - -#include <BulletDynamics/ConstraintSolver/btConeTwistConstraint.h> - -/** - @author AndreaCatania -*/ - -ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : - JointBullet() { - 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) { - Transform3D scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale())); - scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); - - btTransform btFrameB; - G_TO_B(scaled_BFrame, btFrameB); - - coneConstraint = bulletnew(btConeTwistConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB)); - } else { - coneConstraint = bulletnew(btConeTwistConstraint(*rbA->get_bt_rigid_body(), btFrameA)); - } - setup(coneConstraint); -} - -void ConeTwistJointBullet::set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value) { - switch (p_param) { - case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: - coneConstraint->setLimit(5, p_value); - coneConstraint->setLimit(4, p_value); - break; - case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: - coneConstraint->setLimit(3, p_value); - break; - case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: - coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), p_value, coneConstraint->getRelaxationFactor()); - break; - case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: - coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), p_value, coneConstraint->getBiasFactor(), coneConstraint->getRelaxationFactor()); - break; - case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: - coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), coneConstraint->getBiasFactor(), p_value); - break; - case PhysicsServer3D::CONE_TWIST_MAX: - // Internal size value, nothing to do. - break; - } -} - -real_t ConeTwistJointBullet::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const { - switch (p_param) { - case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: - return coneConstraint->getSwingSpan1(); - case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: - return coneConstraint->getTwistSpan(); - case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: - return coneConstraint->getBiasFactor(); - case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: - return coneConstraint->getLimitSoftness(); - case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: - return coneConstraint->getRelaxationFactor(); - case PhysicsServer3D::CONE_TWIST_MAX: - // Internal size value, nothing to do. - return 0; - } - // Compiler doesn't seem to notice that all code paths are fulfilled... - return 0; -} diff --git a/modules/bullet/config.py b/modules/bullet/config.py deleted file mode 100644 index 83605f1f9b..0000000000 --- a/modules/bullet/config.py +++ /dev/null @@ -1,8 +0,0 @@ -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): - pass diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp deleted file mode 100644 index 7e04d57b9d..0000000000 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/*************************************************************************/ -/* generic_6dof_joint_bullet.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 "generic_6dof_joint_bullet.h" - -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "rigid_body_bullet.h" - -#include <BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h> - -/** - @author AndreaCatania -*/ - -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++) { - flags[i][j] = false; - } - } - - 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) { - Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); - - scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); - - btTransform btFrameB; - G_TO_B(scaled_BFrame, btFrameB); - - sixDOFConstraint = bulletnew(btGeneric6DofSpring2Constraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB)); - } else { - sixDOFConstraint = bulletnew(btGeneric6DofSpring2Constraint(*rbA->get_bt_rigid_body(), btFrameA)); - } - - setup(sixDOFConstraint); -} - -Transform3D Generic6DOFJointBullet::getFrameOffsetA() const { - btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); - Transform3D gTrs; - B_TO_G(btTrs, gTrs); - return gTrs; -} - -Transform3D Generic6DOFJointBullet::getFrameOffsetB() const { - btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); - Transform3D gTrs; - B_TO_G(btTrs, gTrs); - return gTrs; -} - -Transform3D Generic6DOFJointBullet::getFrameOffsetA() { - btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); - Transform3D gTrs; - B_TO_G(btTrs, gTrs); - return gTrs; -} - -Transform3D Generic6DOFJointBullet::getFrameOffsetB() { - btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); - Transform3D gTrs; - B_TO_G(btTrs, gTrs); - return gTrs; -} - -void Generic6DOFJointBullet::set_linear_lower_limit(const Vector3 &linearLower) { - btVector3 btVec; - G_TO_B(linearLower, btVec); - sixDOFConstraint->setLinearLowerLimit(btVec); -} - -void Generic6DOFJointBullet::set_linear_upper_limit(const Vector3 &linearUpper) { - btVector3 btVec; - G_TO_B(linearUpper, btVec); - sixDOFConstraint->setLinearUpperLimit(btVec); -} - -void Generic6DOFJointBullet::set_angular_lower_limit(const Vector3 &angularLower) { - btVector3 btVec; - G_TO_B(angularLower, btVec); - sixDOFConstraint->setAngularLowerLimit(btVec); -} - -void Generic6DOFJointBullet::set_angular_upper_limit(const Vector3 &angularUpper) { - btVector3 btVec; - G_TO_B(angularUpper, btVec); - sixDOFConstraint->setAngularUpperLimit(btVec); -} - -void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value) { - ERR_FAIL_INDEX(p_axis, 3); - switch (p_param) { - case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: - limits_lower[0][p_axis] = p_value; - set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter - break; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT: - limits_upper[0][p_axis] = p_value; - set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter - break; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: - sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis] = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: - sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis] = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: - sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis] = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: - sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis] = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: - sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis] = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: - limits_lower[1][p_axis] = p_value; - set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: - limits_upper[1][p_axis] = p_value; - set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_MAX: - // Internal size value, nothing to do. - break; - default: - WARN_DEPRECATED_MSG("The parameter " + itos(p_param) + " is deprecated."); - break; - } -} - -real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const { - ERR_FAIL_INDEX_V(p_axis, 3, 0.); - switch (p_param) { - case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: - return limits_lower[0][p_axis]; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT: - return limits_upper[0][p_axis]; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: - return sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis]; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: - return sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis]; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: - return sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis]; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: - return sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis]; - case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: - return sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis]; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: - return limits_lower[1][p_axis]; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: - return limits_upper[1][p_axis]; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping; - case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint; - case PhysicsServer3D::G6DOF_JOINT_MAX: - // Internal size value, nothing to do. - return 0; - default: - WARN_DEPRECATED_MSG("The parameter " + itos(p_param) + " is deprecated."); - return 0; - } -} - -void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value) { - ERR_FAIL_INDEX(p_axis, 3); - - flags[p_axis][p_flag] = p_value; - - switch (p_flag) { - case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: - if (flags[p_axis][p_flag]) { - sixDOFConstraint->setLimit(p_axis, limits_lower[0][p_axis], limits_upper[0][p_axis]); - } else { - sixDOFConstraint->setLimit(p_axis, 0, -1); // Free - } - break; - case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: - if (flags[p_axis][p_flag]) { - sixDOFConstraint->setLimit(p_axis + 3, limits_lower[1][p_axis], limits_upper[1][p_axis]); - } else { - sixDOFConstraint->setLimit(p_axis + 3, 0, -1); // Free - } - break; - case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableSpring = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: - sixDOFConstraint->getTranslationalLimitMotor()->m_enableSpring[p_axis] = p_value; - break; - case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor = flags[p_axis][p_flag]; - break; - case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: - sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = flags[p_axis][p_flag]; - break; - case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: - // Internal size value, nothing to do. - break; - } -} - -bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const { - ERR_FAIL_INDEX_V(p_axis, 3, false); - return flags[p_axis][p_flag]; -} diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h deleted file mode 100644 index 00567e3085..0000000000 --- a/modules/bullet/generic_6dof_joint_bullet.h +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************/ -/* generic_6dof_joint_bullet.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 GENERIC_6DOF_JOINT_BULLET_H -#define GENERIC_6DOF_JOINT_BULLET_H - -#include "joint_bullet.h" - -/** - @author AndreaCatania -*/ - -class RigidBodyBullet; - -class Generic6DOFJointBullet : public JointBullet { - class btGeneric6DofSpring2Constraint *sixDOFConstraint; - - // First is linear second is angular - Vector3 limits_lower[2]; - Vector3 limits_upper[2]; - bool flags[3][PhysicsServer3D::G6DOF_JOINT_FLAG_MAX]; - -public: - Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB); - - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; } - - 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); - - void set_angular_lower_limit(const Vector3 &angularLower); - void set_angular_upper_limit(const Vector3 &angularUpper); - - void set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value); - real_t get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const; - - void set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value); - bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const; -}; - -#endif diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp deleted file mode 100644 index 94f150b712..0000000000 --- a/modules/bullet/godot_collision_configuration.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************/ -/* godot_collision_configuration.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 "godot_collision_configuration.h" - -#include "godot_ray_world_algorithm.h" - -#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h> -#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h> - -/** - @author AndreaCatania -*/ - -GodotCollisionConfiguration::GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) : - btDefaultCollisionConfiguration(constructionInfo) { - void *mem = nullptr; - - mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16); - m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world); - - mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::SwappedCreateFunc), 16); - m_swappedRayWorldCF = new (mem) GodotRayWorldAlgorithm::SwappedCreateFunc(world); -} - -GodotCollisionConfiguration::~GodotCollisionConfiguration() { - m_rayWorldCF->~btCollisionAlgorithmCreateFunc(); - btAlignedFree(m_rayWorldCF); - - m_swappedRayWorldCF->~btCollisionAlgorithmCreateFunc(); - btAlignedFree(m_swappedRayWorldCF); -} - -btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1) { - if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - // This collision is not supported - return m_emptyCreateFunc; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { - return m_rayWorldCF; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - return m_swappedRayWorldCF; - } else { - return btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(proxyType0, proxyType1); - } -} - -btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) { - if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - // This collision is not supported - return m_emptyCreateFunc; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { - return m_rayWorldCF; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - return m_swappedRayWorldCF; - } else { - return btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(proxyType0, proxyType1); - } -} - -GodotSoftCollisionConfiguration::GodotSoftCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) : - btSoftBodyRigidBodyCollisionConfiguration(constructionInfo) { - void *mem = nullptr; - - mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16); - m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world); - - mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::SwappedCreateFunc), 16); - m_swappedRayWorldCF = new (mem) GodotRayWorldAlgorithm::SwappedCreateFunc(world); -} - -GodotSoftCollisionConfiguration::~GodotSoftCollisionConfiguration() { - m_rayWorldCF->~btCollisionAlgorithmCreateFunc(); - btAlignedFree(m_rayWorldCF); - - m_swappedRayWorldCF->~btCollisionAlgorithmCreateFunc(); - btAlignedFree(m_swappedRayWorldCF); -} - -btCollisionAlgorithmCreateFunc *GodotSoftCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1) { - if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - // This collision is not supported - return m_emptyCreateFunc; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { - return m_rayWorldCF; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - return m_swappedRayWorldCF; - } else { - return btSoftBodyRigidBodyCollisionConfiguration::getCollisionAlgorithmCreateFunc(proxyType0, proxyType1); - } -} - -btCollisionAlgorithmCreateFunc *GodotSoftCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) { - if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - // This collision is not supported - return m_emptyCreateFunc; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { - return m_rayWorldCF; - } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { - return m_swappedRayWorldCF; - } else { - return btSoftBodyRigidBodyCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(proxyType0, proxyType1); - } -} diff --git a/modules/bullet/godot_collision_configuration.h b/modules/bullet/godot_collision_configuration.h deleted file mode 100644 index 8ed55cb1da..0000000000 --- a/modules/bullet/godot_collision_configuration.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************/ -/* godot_collision_configuration.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 GODOT_COLLISION_CONFIGURATION_H -#define GODOT_COLLISION_CONFIGURATION_H - -#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h> -#include <BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h> - -/** - @author AndreaCatania -*/ - -class btDiscreteDynamicsWorld; - -class GodotCollisionConfiguration : public btDefaultCollisionConfiguration { - btCollisionAlgorithmCreateFunc *m_rayWorldCF; - btCollisionAlgorithmCreateFunc *m_swappedRayWorldCF; - -public: - GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo = btDefaultCollisionConstructionInfo()); - virtual ~GodotCollisionConfiguration(); - - virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1); - virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); -}; - -class GodotSoftCollisionConfiguration : public btSoftBodyRigidBodyCollisionConfiguration { - btCollisionAlgorithmCreateFunc *m_rayWorldCF; - btCollisionAlgorithmCreateFunc *m_swappedRayWorldCF; - -public: - GodotSoftCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo = btDefaultCollisionConstructionInfo()); - virtual ~GodotSoftCollisionConfiguration(); - - virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1); - virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); -}; -#endif diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp deleted file mode 100644 index 423166c408..0000000000 --- a/modules/bullet/godot_collision_dispatcher.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* godot_collision_dispatcher.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 "godot_collision_dispatcher.h" - -#include "collision_object_bullet.h" - -/** - @author AndreaCatania -*/ - -const int GodotCollisionDispatcher::CASTED_TYPE_AREA = static_cast<int>(CollisionObjectBullet::TYPE_AREA); - -GodotCollisionDispatcher::GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration) : - btCollisionDispatcher(collisionConfiguration) {} - -bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, const btCollisionObject *body1) { - if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) { - // Avoid area narrow phase - return false; - } - return btCollisionDispatcher::needsCollision(body0, body1); -} - -bool GodotCollisionDispatcher::needsResponse(const btCollisionObject *body0, const btCollisionObject *body1) { - if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) { - // Avoid area narrow phase - return false; - } - return btCollisionDispatcher::needsResponse(body0, body1); -} diff --git a/modules/bullet/godot_collision_dispatcher.h b/modules/bullet/godot_collision_dispatcher.h deleted file mode 100644 index 77472a9432..0000000000 --- a/modules/bullet/godot_collision_dispatcher.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* godot_collision_dispatcher.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 GODOT_COLLISION_DISPATCHER_H -#define GODOT_COLLISION_DISPATCHER_H - -#include <cstdint> - -#include <btBulletDynamicsCommon.h> - -/** - @author AndreaCatania -*/ - -/// This class is required to implement custom collision behaviour in the narrowphase -class GodotCollisionDispatcher : public btCollisionDispatcher { -private: - static const int CASTED_TYPE_AREA; - -public: - GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration); - virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1); - virtual bool needsResponse(const btCollisionObject *body0, const btCollisionObject *body1); -}; -#endif diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h deleted file mode 100644 index ca17349130..0000000000 --- a/modules/bullet/godot_motion_state.h +++ /dev/null @@ -1,99 +0,0 @@ -/*************************************************************************/ -/* godot_motion_state.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 GODOT_MOTION_STATE_H -#define GODOT_MOTION_STATE_H - -#include "rigid_body_bullet.h" - -#include <LinearMath/btMotionState.h> - -/** - @author AndreaCatania -*/ - -class RigidBodyBullet; - -// This class is responsible to move kinematic actor -// and sincronize rendering engine with Bullet -/// DOC: -/// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/MotionStates#What.27s_a_MotionState.3F -class GodotMotionState : public btMotionState { - /// This data is used to store the new world position for kinematic body - btTransform bodyKinematicWorldTransf; - /// This data is used to store last world position - btTransform bodyCurrentWorldTransform; - - RigidBodyBullet *owner = nullptr; - -public: - GodotMotionState(RigidBodyBullet *p_owner) : - bodyKinematicWorldTransf(btMatrix3x3(1., 0., 0., 0., 1., 0., 0., 0., 1.), btVector3(0., 0., 0.)), - bodyCurrentWorldTransform(btMatrix3x3(1., 0., 0., 0., 1., 0., 0., 0., 1.), btVector3(0., 0., 0.)), - owner(p_owner) {} - - /// IMPORTANT DON'T USE THIS FUNCTION TO KNOW THE CURRENT BODY TRANSFORM - /// This class is used internally by Bullet - /// Use GodotMotionState::getCurrentWorldTransform to know current position - /// - /// This function is used by Bullet to get the position of object in the world - /// if the body is kinematic Bullet will move the object to this location - /// if the body is static Bullet doesn't move at all - virtual void getWorldTransform(btTransform &worldTrans) const { - worldTrans = bodyKinematicWorldTransf; - } - - /// IMPORTANT: to move the body use: moveBody - /// IMPORTANT: DON'T CALL THIS FUNCTION, IT IS CALLED BY BULLET TO UPDATE RENDERING ENGINE - /// - /// This function is called each time by Bullet and set the current position of body - /// inside the physics world. - /// Don't allow Godot rendering scene takes world transform from this object because - /// the correct transform is set by Bullet only after the last step when there are sub steps - /// This function must update Godot transform rendering scene for this object. - virtual void setWorldTransform(const btTransform &worldTrans) { - bodyCurrentWorldTransform = worldTrans; - - owner->notify_transform_changed(); - } - -public: - /// Use this function to move kinematic body - /// -- or set initial transform before body creation. - void moveBody(const btTransform &newWorldTransform) { - bodyKinematicWorldTransf = newWorldTransform; - } - - /// It returns the current body transform from last Bullet update - const btTransform &getCurrentWorldTransform() const { - return bodyCurrentWorldTransform; - } -}; -#endif diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp deleted file mode 100644 index a8291d4ab4..0000000000 --- a/modules/bullet/godot_ray_world_algorithm.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************/ -/* godot_ray_world_algorithm.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 "godot_ray_world_algorithm.h" - -#include "btRayShape.h" -#include "collision_object_bullet.h" - -#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h> - -/** - @author AndreaCatania -*/ - -// Epsilon to account for floating point inaccuracies -#define RAY_PENETRATION_DEPTH_EPSILON 0.01 - -GodotRayWorldAlgorithm::CreateFunc::CreateFunc(const btDiscreteDynamicsWorld *world) : - m_world(world) {} - -GodotRayWorldAlgorithm::SwappedCreateFunc::SwappedCreateFunc(const btDiscreteDynamicsWorld *world) : - m_world(world) {} - -GodotRayWorldAlgorithm::GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped) : - btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap), - m_world(world), - m_manifoldPtr(mf), - m_isSwapped(isSwapped) {} - -GodotRayWorldAlgorithm::~GodotRayWorldAlgorithm() { - if (m_ownManifold && m_manifoldPtr) { - m_dispatcher->releaseManifold(m_manifoldPtr); - } -} - -void GodotRayWorldAlgorithm::processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut) { - if (!m_manifoldPtr) { - if (m_isSwapped) { - m_manifoldPtr = m_dispatcher->getNewManifold(body1Wrap->getCollisionObject(), body0Wrap->getCollisionObject()); - } else { - m_manifoldPtr = m_dispatcher->getNewManifold(body0Wrap->getCollisionObject(), body1Wrap->getCollisionObject()); - } - m_ownManifold = true; - } - m_manifoldPtr->clearManifold(); - resultOut->setPersistentManifold(m_manifoldPtr); - - const btRayShape *ray_shape; - btTransform ray_transform; - - const btCollisionObjectWrapper *other_co_wrapper; - - if (m_isSwapped) { - ray_shape = static_cast<const btRayShape *>(body1Wrap->getCollisionShape()); - ray_transform = body1Wrap->getWorldTransform(); - - other_co_wrapper = body0Wrap; - } else { - ray_shape = static_cast<const btRayShape *>(body0Wrap->getCollisionShape()); - ray_transform = body0Wrap->getWorldTransform(); - - other_co_wrapper = body1Wrap; - } - - btTransform to(ray_transform * ray_shape->getSupportPoint()); - - btCollisionWorld::ClosestRayResultCallback btResult(ray_transform.getOrigin(), to.getOrigin()); - - m_world->rayTestSingleInternal(ray_transform, to, other_co_wrapper, btResult); - - if (btResult.hasHit()) { - btScalar depth(ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1)); - - if (depth > -RAY_PENETRATION_DEPTH_EPSILON) { - depth = 0.0; - } - - if (ray_shape->getSlipsOnSlope()) { - resultOut->addContactPoint(btResult.m_hitNormalWorld, btResult.m_hitPointWorld, depth); - } else { - resultOut->addContactPoint((ray_transform.getOrigin() - to.getOrigin()).normalize(), btResult.m_hitPointWorld, depth); - } - } -} - -btScalar GodotRayWorldAlgorithm::calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut) { - return 1; -} diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h deleted file mode 100644 index 25798aecb4..0000000000 --- a/modules/bullet/godot_ray_world_algorithm.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************/ -/* godot_ray_world_algorithm.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 GODOT_RAY_WORLD_ALGORITHM_H -#define GODOT_RAY_WORLD_ALGORITHM_H - -#include <BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h> -#include <BulletCollision/CollisionDispatch/btCollisionCreateFunc.h> -#include <BulletCollision/CollisionDispatch/btCollisionDispatcher.h> - -/** - @author AndreaCatania -*/ - -class btDiscreteDynamicsWorld; - -class GodotRayWorldAlgorithm : public btActivatingCollisionAlgorithm { - const btDiscreteDynamicsWorld *m_world; - btPersistentManifold *m_manifoldPtr; - bool m_ownManifold = false; - bool m_isSwapped = false; - -public: - GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped); - virtual ~GodotRayWorldAlgorithm(); - - virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut); - virtual btScalar calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut); - - virtual void getAllContactManifolds(btManifoldArray &manifoldArray) { - ///should we use m_ownManifold to avoid adding duplicates? - if (m_manifoldPtr && m_ownManifold) { - manifoldArray.push_back(m_manifoldPtr); - } - } - struct CreateFunc : public btCollisionAlgorithmCreateFunc { - const btDiscreteDynamicsWorld *m_world; - CreateFunc(const btDiscreteDynamicsWorld *world); - - virtual btCollisionAlgorithm *CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) { - void *mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(GodotRayWorldAlgorithm)); - return new (mem) GodotRayWorldAlgorithm(m_world, ci.m_manifold, ci, body0Wrap, body1Wrap, false); - } - }; - - struct SwappedCreateFunc : public btCollisionAlgorithmCreateFunc { - const btDiscreteDynamicsWorld *m_world; - SwappedCreateFunc(const btDiscreteDynamicsWorld *world); - - virtual btCollisionAlgorithm *CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) { - void *mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(GodotRayWorldAlgorithm)); - return new (mem) GodotRayWorldAlgorithm(m_world, ci.m_manifold, ci, body0Wrap, body1Wrap, true); - } - }; -}; - -#endif // GODOT_RAY_WORLD_ALGORITHM_H diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp deleted file mode 100644 index edb2bcb4c7..0000000000 --- a/modules/bullet/godot_result_callbacks.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/*************************************************************************/ -/* godot_result_callbacks.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 "godot_result_callbacks.h" - -#include "area_bullet.h" -#include "bullet_types_converter.h" -#include "collision_object_bullet.h" -#include "rigid_body_bullet.h" -#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h> - -/** - @author AndreaCatania -*/ - -bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { - if (!colObj1Wrap->getCollisionObject()->getCollisionShape()->isCompound()) { - btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1); - } - return true; -} - -bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const { - return (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) || (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); -} - -bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - - if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { - if (!collide_with_areas) { - return false; - } - } else { - if (!collide_with_bodies) { - return false; - } - } - - if (m_pickRay && !gObj->is_ray_pickable()) { - return false; - } - - if (m_exclude->has(gObj->get_self())) { - return false; - } - - return true; - } else { - return false; - } -} - -bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (count >= m_resultMax) { - return false; - } - - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - if (m_exclude->has(gObj->get_self())) { - return false; - } - - return true; - } else { - return false; - } -} - -btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { - if (count >= m_resultMax) { - return 1; // not used by bullet - } - - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer()); - - PhysicsDirectSpaceState3D::ShapeResult &result = m_results[count]; - - // Triangle index is an odd name but contains the compound shape ID. - // A shape part of -1 indicates the index is a shape index and not a triangle index. - if (convexResult.m_localShapeInfo && convexResult.m_localShapeInfo->m_shapePart == -1) { - result.shape = convexResult.m_localShapeInfo->m_triangleIndex; - } else { - result.shape = 0; - } - - result.rid = gObj->get_self(); - result.collider_id = gObj->get_instance_id(); - result.collider = result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(result.collider_id); - - ++count; - return 1; // not used by bullet -} - -bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - if (gObj == m_self_object) { - return false; - } else { - // A kinematic body can't be stopped by a rigid body since the mass of kinematic body is infinite - if (m_infinite_inertia && !btObj->isStaticOrKinematicObject()) { - return false; - } - - if (gObj->getType() == CollisionObjectBullet::TYPE_AREA) { - return false; - } - - if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) { - return false; - } - - if (m_exclude->has(gObj->get_self())) { - return false; - } - } - return true; - } else { - return false; - } -} - -bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - - if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { - if (!collide_with_areas) { - return false; - } - } else { - if (!collide_with_bodies) { - return false; - } - } - - if (m_exclude->has(gObj->get_self())) { - return false; - } - return true; - } else { - return false; - } -} - -btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { - // Triangle index is an odd name but contains the compound shape ID. - // A shape part of -1 indicates the index is a shape index and not a triangle index. - if (convexResult.m_localShapeInfo && convexResult.m_localShapeInfo->m_shapePart == -1) { - m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; - } else { - m_shapeId = 0; - } - - return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); -} - -bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (m_count >= m_resultMax) { - return false; - } - - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - - if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { - if (!collide_with_areas) { - return false; - } - } else { - if (!collide_with_bodies) { - return false; - } - } - - if (m_exclude->has(gObj->get_self())) { - return false; - } - return true; - } else { - return false; - } -} - -btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { - if (m_count >= m_resultMax) { - return cp.getDistance(); - } - - if (cp.getDistance() <= 0) { - PhysicsDirectSpaceState3D::ShapeResult &result = m_results[m_count]; - // Penetrated - - CollisionObjectBullet *colObj; - if (m_self_object == colObj0Wrap->getCollisionObject()) { - colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer()); - // Checking for compound shape because the index might be uninitialized otherwise. - // A partId of -1 indicates the index is a shape index and not a triangle index. - if (colObj1Wrap->getCollisionObject()->getCollisionShape()->isCompound() && cp.m_partId1 == -1) { - result.shape = cp.m_index1; - } else { - result.shape = 0; - } - } else { - colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer()); - // Checking for compound shape because the index might be uninitialized otherwise. - // A partId of -1 indicates the index is a shape index and not a triangle index. - if (colObj0Wrap->getCollisionObject()->getCollisionShape()->isCompound() && cp.m_partId0 == -1) { - result.shape = cp.m_index0; - } else { - result.shape = 0; - } - } - - result.collider_id = colObj->get_instance_id(); - result.collider = result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(result.collider_id); - result.rid = colObj->get_self(); - ++m_count; - } - - return cp.getDistance(); -} - -bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (m_count >= m_resultMax) { - return false; - } - - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - - if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { - if (!collide_with_areas) { - return false; - } - } else { - if (!collide_with_bodies) { - return false; - } - } - - if (m_exclude->has(gObj->get_self())) { - return false; - } - return true; - } else { - return false; - } -} - -btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { - if (m_count >= m_resultMax) { - return 1; // not used by bullet - } - - if (m_self_object == colObj0Wrap->getCollisionObject()) { - B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 0]); // Local contact - B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 1]); - } else { - B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 0]); // Local contact - B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 1]); - } - - ++m_count; - - return 1; // Not used by bullet -} - -bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { - btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - - if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { - if (!collide_with_areas) { - return false; - } - } else { - if (!collide_with_bodies) { - return false; - } - } - - if (m_exclude->has(gObj->get_self())) { - return false; - } - return true; - } else { - return false; - } -} - -btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { - if (cp.getDistance() <= m_min_distance) { - m_min_distance = cp.getDistance(); - - CollisionObjectBullet *colObj; - if (m_self_object == colObj0Wrap->getCollisionObject()) { - colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer()); - // Checking for compound shape because the index might be uninitialized otherwise. - // A partId of -1 indicates the index is a shape index and not a triangle index. - if (colObj1Wrap->getCollisionObject()->getCollisionShape()->isCompound() && cp.m_partId1 == -1) { - m_result->shape = cp.m_index1; - } else { - m_result->shape = 0; - } - B_TO_G(cp.getPositionWorldOnB(), m_result->point); - B_TO_G(cp.m_normalWorldOnB, m_result->normal); - m_rest_info_bt_point = cp.getPositionWorldOnB(); - m_rest_info_collision_object = colObj1Wrap->getCollisionObject(); - } else { - colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer()); - // Checking for compound shape because the index might be uninitialized otherwise. - // A partId of -1 indicates the index is a shape index and not a triangle index. - if (colObj0Wrap->getCollisionObject()->getCollisionShape()->isCompound() && cp.m_partId0 == -1) { - m_result->shape = cp.m_index0; - } else { - m_result->shape = 0; - } - B_TO_G(cp.m_normalWorldOnB * -1, m_result->normal); - m_rest_info_bt_point = cp.getPositionWorldOnA(); - m_rest_info_collision_object = colObj0Wrap->getCollisionObject(); - } - - m_result->collider_id = colObj->get_instance_id(); - m_result->rid = colObj->get_self(); - - m_collided = true; - } - - return 1; // Not used by bullet -} - -void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth) { - if (m_penetration_distance > depth) { // Has penetration? - - const bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); - m_penetration_distance = depth; - m_other_compound_shape_index = isSwapped ? m_index0 : m_index1; - m_pointWorld = isSwapped ? (pointInWorldOnB + (normalOnBInWorld * depth)) : pointInWorldOnB; - - m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; - } -} diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h deleted file mode 100644 index 3dfa21aec8..0000000000 --- a/modules/bullet/godot_result_callbacks.h +++ /dev/null @@ -1,228 +0,0 @@ -/*************************************************************************/ -/* godot_result_callbacks.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 GODOT_RESULT_CALLBACKS_H -#define GODOT_RESULT_CALLBACKS_H - -#include "servers/physics_server_3d.h" - -#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h> -#include <btBulletDynamicsCommon.h> - -/** - @author AndreaCatania -*/ - -class RigidBodyBullet; - -/// This callback is injected inside bullet server and allow me to smooth contacts against trimesh -bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); - -/// This class is required to implement custom collision behaviour in the broadphase -struct GodotFilterCallback : public btOverlapFilterCallback { - // return true when pairs need collision - virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const; -}; - -/// It performs an additional check allow exclusions. -struct GodotClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { - const Set<RID> *m_exclude; - bool m_pickRay = false; - int m_shapeId = 0; - - bool collide_with_bodies = false; - bool collide_with_areas = false; - -public: - GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : - btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), - m_exclude(p_exclude), - collide_with_bodies(p_collide_with_bodies), - collide_with_areas(p_collide_with_areas) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; - - virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace) { - // Triangle index is an odd name but contains the compound shape ID. - // A shape part of -1 indicates the index is a shape index and not a triangle index. - if (rayResult.m_localShapeInfo && rayResult.m_localShapeInfo->m_shapePart == -1) { - m_shapeId = rayResult.m_localShapeInfo->m_triangleIndex; - } else { - m_shapeId = 0; - } - return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); - } -}; - -// store all colliding object -struct GodotAllConvexResultCallback : public btCollisionWorld::ConvexResultCallback { -public: - PhysicsDirectSpaceState3D::ShapeResult *m_results = nullptr; - int m_resultMax = 0; - const Set<RID> *m_exclude; - int count = 0; - - GodotAllConvexResultCallback(PhysicsDirectSpaceState3D::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) : - m_results(p_results), - m_resultMax(p_resultMax), - m_exclude(p_exclude) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace); -}; - -struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { -public: - const RigidBodyBullet *m_self_object; - const Set<RID> *m_exclude; - const bool m_infinite_inertia; - - GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia, const Set<RID> *p_exclude) : - btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), - m_self_object(p_self_object), - m_exclude(p_exclude), - m_infinite_inertia(p_infinite_inertia) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; -}; - -struct GodotClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { -public: - const Set<RID> *m_exclude; - int m_shapeId = 0; - - bool collide_with_bodies = false; - bool collide_with_areas = false; - - GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : - btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), - m_exclude(p_exclude), - collide_with_bodies(p_collide_with_bodies), - collide_with_areas(p_collide_with_areas) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace); -}; - -struct GodotAllContactResultCallback : public btCollisionWorld::ContactResultCallback { -public: - const btCollisionObject *m_self_object; - PhysicsDirectSpaceState3D::ShapeResult *m_results = nullptr; - int m_resultMax = 0; - const Set<RID> *m_exclude; - int m_count = 0; - - bool collide_with_bodies = false; - bool collide_with_areas = false; - - GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState3D::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : - m_self_object(p_self_object), - m_results(p_results), - m_resultMax(p_resultMax), - m_exclude(p_exclude), - collide_with_bodies(p_collide_with_bodies), - collide_with_areas(p_collide_with_areas) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; - - virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); -}; - -/// Returns the list of contacts pairs in this order: Local contact, other body contact -struct GodotContactPairContactResultCallback : public btCollisionWorld::ContactResultCallback { -public: - const btCollisionObject *m_self_object; - Vector3 *m_results = nullptr; - int m_resultMax = 0; - const Set<RID> *m_exclude; - int m_count = 0; - - bool collide_with_bodies = false; - bool collide_with_areas = false; - - GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : - m_self_object(p_self_object), - m_results(p_results), - m_resultMax(p_resultMax), - m_exclude(p_exclude), - collide_with_bodies(p_collide_with_bodies), - collide_with_areas(p_collide_with_areas) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; - - virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); -}; - -struct GodotRestInfoContactResultCallback : public btCollisionWorld::ContactResultCallback { -public: - const btCollisionObject *m_self_object; - PhysicsDirectSpaceState3D::ShapeRestInfo *m_result = nullptr; - const Set<RID> *m_exclude; - bool m_collided = false; - real_t m_min_distance = 0.0; - const btCollisionObject *m_rest_info_collision_object = nullptr; - btVector3 m_rest_info_bt_point; - bool collide_with_bodies = false; - bool collide_with_areas = false; - - GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState3D::ShapeRestInfo *p_result, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : - m_self_object(p_self_object), - m_result(p_result), - m_exclude(p_exclude), - collide_with_bodies(p_collide_with_bodies), - collide_with_areas(p_collide_with_areas) {} - - virtual bool needsCollision(btBroadphaseProxy *proxy0) const; - - virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); -}; - -struct GodotDeepPenetrationContactResultCallback : public btManifoldResult { - btVector3 m_pointNormalWorld; - btVector3 m_pointWorld; - btScalar m_penetration_distance = 0; - int m_other_compound_shape_index = 0; - - GodotDeepPenetrationContactResultCallback(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) : - btManifoldResult(body0Wrap, body1Wrap) {} - - void reset() { - m_penetration_distance = 0; - } - - bool hasHit() { - return m_penetration_distance < 0; - } - - virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth); -}; -#endif // GODOT_RESULT_CALLBACKS_H diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp deleted file mode 100644 index b5fe50cf5f..0000000000 --- a/modules/bullet/hinge_joint_bullet.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************/ -/* hinge_joint_bullet.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 "hinge_joint_bullet.h" - -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "rigid_body_bullet.h" - -#include <BulletDynamics/ConstraintSolver/btHingeConstraint.h> - -/** - @author AndreaCatania -*/ - -HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB) : - JointBullet() { - 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) { - Transform3D scaled_BFrame(frameB.scaled(rbB->get_body_scale())); - scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); - - btTransform btFrameB; - G_TO_B(scaled_BFrame, btFrameB); - - hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB)); - } else { - hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), btFrameA)); - } - - setup(hingeConstraint); -} - -HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB) : - JointBullet() { - btVector3 btPivotA; - btVector3 btAxisA; - G_TO_B(pivotInA * rbA->get_body_scale(), btPivotA); - G_TO_B(axisInA * rbA->get_body_scale(), btAxisA); - - if (rbB) { - btVector3 btPivotB; - btVector3 btAxisB; - G_TO_B(pivotInB * rbB->get_body_scale(), btPivotB); - G_TO_B(axisInB * rbB->get_body_scale(), btAxisB); - - hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btPivotA, btPivotB, btAxisA, btAxisB)); - } else { - hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), btPivotA, btAxisA)); - } - - setup(hingeConstraint); -} - -real_t HingeJointBullet::get_hinge_angle() { - return hingeConstraint->getHingeAngle(); -} - -void HingeJointBullet::set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value) { - switch (p_param) { - case PhysicsServer3D::HINGE_JOINT_BIAS: - WARN_DEPRECATED_MSG("The HingeJoint3D parameter \"bias\" is deprecated."); - break; - case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER: - hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), p_value, hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); - break; - case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER: - hingeConstraint->setLimit(p_value, hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); - break; - case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS: - hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), p_value, hingeConstraint->getLimitRelaxationFactor()); - break; - case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS: - hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), p_value, hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); - break; - case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION: - hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), p_value); - break; - case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY: - hingeConstraint->setMotorTargetVelocity(p_value); - break; - case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE: - hingeConstraint->setMaxMotorImpulse(p_value); - break; - case PhysicsServer3D::HINGE_JOINT_MAX: - // Internal size value, nothing to do. - break; - } -} - -real_t HingeJointBullet::get_param(PhysicsServer3D::HingeJointParam p_param) const { - switch (p_param) { - case PhysicsServer3D::HINGE_JOINT_BIAS: - WARN_DEPRECATED_MSG("The HingeJoint3D parameter \"bias\" is deprecated."); - return 0; - case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER: - return hingeConstraint->getUpperLimit(); - case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER: - return hingeConstraint->getLowerLimit(); - case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS: - return hingeConstraint->getLimitBiasFactor(); - case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS: - return hingeConstraint->getLimitSoftness(); - case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION: - return hingeConstraint->getLimitRelaxationFactor(); - case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY: - return hingeConstraint->getMotorTargetVelocity(); - case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE: - return hingeConstraint->getMaxMotorImpulse(); - case PhysicsServer3D::HINGE_JOINT_MAX: - // Internal size value, nothing to do. - return 0; - } - // Compiler doesn't seem to notice that all code paths are fulfilled... - return 0; -} - -void HingeJointBullet::set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value) { - switch (p_flag) { - case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: - if (!p_value) { - hingeConstraint->setLimit(-Math_PI, Math_PI); - } - break; - case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR: - hingeConstraint->enableMotor(p_value); - break; - case PhysicsServer3D::HINGE_JOINT_FLAG_MAX: - break; // Can't happen, but silences warning - } -} - -bool HingeJointBullet::get_flag(PhysicsServer3D::HingeJointFlag p_flag) const { - switch (p_flag) { - case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: - return true; - case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR: - return hingeConstraint->getEnableAngularMotor(); - default: - return false; - } -} diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h deleted file mode 100644 index dd0f69ba68..0000000000 --- a/modules/bullet/hinge_joint_bullet.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************/ -/* hinge_joint_bullet.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 HINGE_JOINT_BULLET_H -#define HINGE_JOINT_BULLET_H - -#include "joint_bullet.h" - -/** - @author AndreaCatania -*/ - -class HingeJointBullet : public JointBullet { - class btHingeConstraint *hingeConstraint; - -public: - 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; } - - real_t get_hinge_angle(); - - void set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value); - real_t get_param(PhysicsServer3D::HingeJointParam p_param) const; - - void set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value); - bool get_flag(PhysicsServer3D::HingeJointFlag p_flag) const; -}; -#endif diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp deleted file mode 100644 index 8e8ff57f11..0000000000 --- a/modules/bullet/pin_joint_bullet.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************/ -/* pin_joint_bullet.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 "pin_joint_bullet.h" - -#include "bullet_types_converter.h" -#include "rigid_body_bullet.h" - -#include <BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h> - -/** - @author AndreaCatania -*/ - -PinJointBullet::PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b) : - JointBullet() { - if (p_body_b) { - btVector3 btPivotA; - btVector3 btPivotB; - G_TO_B(p_pos_a * p_body_a->get_body_scale(), btPivotA); - G_TO_B(p_pos_b * p_body_b->get_body_scale(), btPivotB); - p2pConstraint = bulletnew(btPoint2PointConstraint(*p_body_a->get_bt_rigid_body(), - *p_body_b->get_bt_rigid_body(), - btPivotA, - btPivotB)); - } else { - btVector3 btPivotA; - G_TO_B(p_pos_a, btPivotA); - p2pConstraint = bulletnew(btPoint2PointConstraint(*p_body_a->get_bt_rigid_body(), btPivotA)); - } - - setup(p2pConstraint); -} - -PinJointBullet::~PinJointBullet() {} - -void PinJointBullet::set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value) { - switch (p_param) { - case PhysicsServer3D::PIN_JOINT_BIAS: - p2pConstraint->m_setting.m_tau = p_value; - break; - case PhysicsServer3D::PIN_JOINT_DAMPING: - p2pConstraint->m_setting.m_damping = p_value; - break; - case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP: - p2pConstraint->m_setting.m_impulseClamp = p_value; - break; - } -} - -real_t PinJointBullet::get_param(PhysicsServer3D::PinJointParam p_param) const { - switch (p_param) { - case PhysicsServer3D::PIN_JOINT_BIAS: - return p2pConstraint->m_setting.m_tau; - case PhysicsServer3D::PIN_JOINT_DAMPING: - return p2pConstraint->m_setting.m_damping; - case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP: - return p2pConstraint->m_setting.m_impulseClamp; - } - // Compiler doesn't seem to notice that all code paths are fulfilled... - return 0; -} - -void PinJointBullet::setPivotInA(const Vector3 &p_pos) { - btVector3 btVec; - G_TO_B(p_pos, btVec); - p2pConstraint->setPivotA(btVec); -} - -void PinJointBullet::setPivotInB(const Vector3 &p_pos) { - btVector3 btVec; - G_TO_B(p_pos, btVec); - p2pConstraint->setPivotB(btVec); -} - -Vector3 PinJointBullet::getPivotInA() { - btVector3 vec = p2pConstraint->getPivotInA(); - Vector3 gVec; - B_TO_G(vec, gVec); - return gVec; -} - -Vector3 PinJointBullet::getPivotInB() { - btVector3 vec = p2pConstraint->getPivotInB(); - Vector3 gVec; - B_TO_G(vec, gVec); - return gVec; -} diff --git a/modules/bullet/pin_joint_bullet.h b/modules/bullet/pin_joint_bullet.h deleted file mode 100644 index 6fbb6f7e02..0000000000 --- a/modules/bullet/pin_joint_bullet.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* pin_joint_bullet.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 PIN_JOINT_BULLET_H -#define PIN_JOINT_BULLET_H - -#include "joint_bullet.h" - -/** - @author AndreaCatania -*/ - -class RigidBodyBullet; - -class PinJointBullet : public JointBullet { - class btPoint2PointConstraint *p2pConstraint; - -public: - PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b); - ~PinJointBullet(); - - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_PIN; } - - void set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value); - real_t get_param(PhysicsServer3D::PinJointParam p_param) const; - - void setPivotInA(const Vector3 &p_pos); - void setPivotInB(const Vector3 &p_pos); - - Vector3 getPivotInA(); - Vector3 getPivotInB(); -}; -#endif diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp deleted file mode 100644 index b5ad5749a6..0000000000 --- a/modules/bullet/register_types.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "bullet_physics_server.h" -#include "core/config/project_settings.h" -#include "core/object/class_db.h" - -/** - @author AndreaCatania -*/ - -#ifndef _3D_DISABLED -PhysicsServer3D *_createBulletPhysicsCallback() { - return memnew(BulletPhysicsServer3D); -} -#endif - -void register_bullet_types() { -#ifndef _3D_DISABLED - PhysicsServer3DManager::register_server("Bullet", &_createBulletPhysicsCallback); - PhysicsServer3DManager::set_default_server("Bullet", 1); - - GLOBAL_DEF("physics/3d/active_soft_world", true); - ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/active_soft_world", PropertyInfo(Variant::BOOL, "physics/3d/active_soft_world")); -#endif -} - -void unregister_bullet_types() { -} diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp deleted file mode 100644 index 4faab19539..0000000000 --- a/modules/bullet/rigid_body_bullet.cpp +++ /dev/null @@ -1,1056 +0,0 @@ -/*************************************************************************/ -/* rigid_body_bullet.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 "rigid_body_bullet.h" - -#include "btRayShape.h" -#include "bullet_physics_server.h" -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "godot_motion_state.h" -#include "joint_bullet.h" - -#include <BulletCollision/CollisionDispatch/btGhostObject.h> -#include <BulletCollision/CollisionShapes/btConvexPointCloudShape.h> -#include <BulletDynamics/Dynamics/btRigidBody.h> -#include <btBulletCollisionCommon.h> - -#include <assert.h> - -/** - @author AndreaCatania -*/ - -BulletPhysicsDirectBodyState3D *BulletPhysicsDirectBodyState3D::singleton = nullptr; - -Vector3 BulletPhysicsDirectBodyState3D::get_total_gravity() const { - Vector3 gVec; - B_TO_G(body->btBody->getGravity(), gVec); - return gVec; -} - -real_t BulletPhysicsDirectBodyState3D::get_total_angular_damp() const { - return body->btBody->getAngularDamping(); -} - -real_t BulletPhysicsDirectBodyState3D::get_total_linear_damp() const { - return body->btBody->getLinearDamping(); -} - -Vector3 BulletPhysicsDirectBodyState3D::get_center_of_mass() const { - Vector3 gVec; - B_TO_G(body->btBody->getCenterOfMassPosition(), gVec); - return gVec; -} - -Basis BulletPhysicsDirectBodyState3D::get_principal_inertia_axes() const { - return Basis(); -} - -real_t BulletPhysicsDirectBodyState3D::get_inverse_mass() const { - return body->btBody->getInvMass(); -} - -Vector3 BulletPhysicsDirectBodyState3D::get_inverse_inertia() const { - Vector3 gVec; - B_TO_G(body->btBody->getInvInertiaDiagLocal(), gVec); - return gVec; -} - -Basis BulletPhysicsDirectBodyState3D::get_inverse_inertia_tensor() const { - Basis gInertia; - B_TO_G(body->btBody->getInvInertiaTensorWorld(), gInertia); - return gInertia; -} - -void BulletPhysicsDirectBodyState3D::set_linear_velocity(const Vector3 &p_velocity) { - body->set_linear_velocity(p_velocity); -} - -Vector3 BulletPhysicsDirectBodyState3D::get_linear_velocity() const { - return body->get_linear_velocity(); -} - -void BulletPhysicsDirectBodyState3D::set_angular_velocity(const Vector3 &p_velocity) { - body->set_angular_velocity(p_velocity); -} - -Vector3 BulletPhysicsDirectBodyState3D::get_angular_velocity() const { - return body->get_angular_velocity(); -} - -void BulletPhysicsDirectBodyState3D::set_transform(const Transform3D &p_transform) { - body->set_transform(p_transform); -} - -Transform3D BulletPhysicsDirectBodyState3D::get_transform() const { - return body->get_transform(); -} - -Vector3 BulletPhysicsDirectBodyState3D::get_velocity_at_local_position(const Vector3 &p_position) const { - btVector3 local_position; - G_TO_B(p_position, local_position); - - Vector3 velocity; - B_TO_G(body->btBody->getVelocityInLocalPoint(local_position), velocity); - - return velocity; -} - -void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) { - body->apply_central_force(p_force); -} - -void BulletPhysicsDirectBodyState3D::add_force(const Vector3 &p_force, const Vector3 &p_position) { - body->apply_force(p_force, p_position); -} - -void BulletPhysicsDirectBodyState3D::add_torque(const Vector3 &p_torque) { - body->apply_torque(p_torque); -} - -void BulletPhysicsDirectBodyState3D::apply_central_impulse(const Vector3 &p_impulse) { - body->apply_central_impulse(p_impulse); -} - -void BulletPhysicsDirectBodyState3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { - body->apply_impulse(p_impulse, p_position); -} - -void BulletPhysicsDirectBodyState3D::apply_torque_impulse(const Vector3 &p_impulse) { - body->apply_torque_impulse(p_impulse); -} - -void BulletPhysicsDirectBodyState3D::set_sleep_state(bool p_sleep) { - body->set_activation_state(!p_sleep); -} - -bool BulletPhysicsDirectBodyState3D::is_sleeping() const { - return !body->is_active(); -} - -int BulletPhysicsDirectBodyState3D::get_contact_count() const { - return body->collisionsCount; -} - -Vector3 BulletPhysicsDirectBodyState3D::get_contact_local_position(int p_contact_idx) const { - return body->collisions[p_contact_idx].hitLocalLocation; -} - -Vector3 BulletPhysicsDirectBodyState3D::get_contact_local_normal(int p_contact_idx) const { - return body->collisions[p_contact_idx].hitNormal; -} - -real_t BulletPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const { - return body->collisions[p_contact_idx].appliedImpulse; -} - -int BulletPhysicsDirectBodyState3D::get_contact_local_shape(int p_contact_idx) const { - return body->collisions[p_contact_idx].local_shape; -} - -RID BulletPhysicsDirectBodyState3D::get_contact_collider(int p_contact_idx) const { - return body->collisions[p_contact_idx].otherObject->get_self(); -} - -Vector3 BulletPhysicsDirectBodyState3D::get_contact_collider_position(int p_contact_idx) const { - return body->collisions[p_contact_idx].hitWorldLocation; -} - -ObjectID BulletPhysicsDirectBodyState3D::get_contact_collider_id(int p_contact_idx) const { - return body->collisions[p_contact_idx].otherObject->get_instance_id(); -} - -int BulletPhysicsDirectBodyState3D::get_contact_collider_shape(int p_contact_idx) const { - return body->collisions[p_contact_idx].other_object_shape; -} - -Vector3 BulletPhysicsDirectBodyState3D::get_contact_collider_velocity_at_position(int p_contact_idx) const { - RigidBodyBullet::CollisionData &colDat = body->collisions.write[p_contact_idx]; - - btVector3 hitLocation; - G_TO_B(colDat.hitLocalLocation, hitLocation); - - Vector3 velocityAtPoint; - B_TO_G(colDat.otherObject->get_bt_rigid_body()->getVelocityInLocalPoint(hitLocation), velocityAtPoint); - - return velocityAtPoint; -} - -PhysicsDirectSpaceState3D *BulletPhysicsDirectBodyState3D::get_space_state() { - return body->get_space()->get_direct_state(); -} - -RigidBodyBullet::KinematicUtilities::KinematicUtilities(RigidBodyBullet *p_owner) : - owner(p_owner), - safe_margin(0.001) { -} - -RigidBodyBullet::KinematicUtilities::~KinematicUtilities() { - just_delete_shapes(shapes.size()); // don't need to resize -} - -void RigidBodyBullet::KinematicUtilities::setSafeMargin(btScalar p_margin) { - safe_margin = p_margin; - copyAllOwnerShapes(); -} - -void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { - const Vector<CollisionObjectBullet::ShapeWrapper> &shapes_wrappers(owner->get_shapes_wrappers()); - const int shapes_count = shapes_wrappers.size(); - - just_delete_shapes(shapes_count); - - const CollisionObjectBullet::ShapeWrapper *shape_wrapper; - - btVector3 owner_scale(owner->get_bt_body_scale()); - - for (int i = shapes_count - 1; 0 <= i; --i) { - shape_wrapper = &shapes_wrappers[i]; - if (!shape_wrapper->active) { - continue; - } - - shapes.write[i].transform = shape_wrapper->transform; - shapes.write[i].transform.getOrigin() *= owner_scale; - switch (shape_wrapper->shape->get_type()) { - case PhysicsServer3D::SHAPE_SPHERE: - case PhysicsServer3D::SHAPE_BOX: - case PhysicsServer3D::SHAPE_CAPSULE: - case PhysicsServer3D::SHAPE_CYLINDER: - case PhysicsServer3D::SHAPE_CONVEX_POLYGON: - case PhysicsServer3D::SHAPE_RAY: { - shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); - } break; - default: - WARN_PRINT("This shape is not supported for kinematic collision."); - shapes.write[i].shape = nullptr; - } - } -} - -void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) { - for (int i = shapes.size() - 1; 0 <= i; --i) { - if (shapes[i].shape) { - bulletdelete(shapes.write[i].shape); - } - } - shapes.resize(new_size); -} - -RigidBodyBullet::RigidBodyBullet() : - RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_RIGID_BODY) { - godotMotionState = bulletnew(GodotMotionState(this)); - - // Initial properties - const btVector3 localInertia(0, 0, 0); - btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, nullptr, localInertia); - - btBody = bulletnew(btRigidBody(cInfo)); - btBody->setFriction(1.0); - reload_shapes(); - setupBulletCollisionObject(btBody); - - set_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); - reload_axis_lock(); - - areasWhereIam.resize(maxAreasWhereIam); - for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { - areasWhereIam.write[i] = nullptr; - } - btBody->setSleepingThresholds(0.2, 0.2); - - prev_collision_traces = &collision_traces_1; - curr_collision_traces = &collision_traces_2; -} - -RigidBodyBullet::~RigidBodyBullet() { - bulletdelete(godotMotionState); - - if (force_integration_callback) { - memdelete(force_integration_callback); - } - - destroy_kinematic_utilities(); -} - -void RigidBodyBullet::init_kinematic_utilities() { - kinematic_utilities = memnew(KinematicUtilities(this)); - reload_kinematic_shapes(); -} - -void RigidBodyBullet::destroy_kinematic_utilities() { - if (kinematic_utilities) { - memdelete(kinematic_utilities); - kinematic_utilities = nullptr; - } -} - -void RigidBodyBullet::main_shape_changed() { - CRASH_COND(!get_main_shape()); - btBody->setCollisionShape(get_main_shape()); - set_continuous_collision_detection(is_continuous_collision_detection_enabled()); // Reset -} - -void RigidBodyBullet::reload_body() { - if (space) { - space->remove_rigid_body(this); - if (get_main_shape()) { - space->add_rigid_body(this); - } - } -} - -void RigidBodyBullet::set_space(SpaceBullet *p_space) { - // Clear the old space if there is one - if (space) { - can_integrate_forces = false; - isScratchedSpaceOverrideModificator = false; - // Remove any constraints - space->remove_rigid_body_constraints(this); - // Remove this object form the physics world - space->remove_rigid_body(this); - } - - space = p_space; - - if (space) { - space->add_rigid_body(this); - } -} - -void RigidBodyBullet::dispatch_callbacks() { - /// The check isFirstTransformChanged is necessary in order to call integrated forces only when the first transform is sent - if ((btBody->isKinematicObject() || btBody->isActive() || previousActiveState != btBody->isActive()) && force_integration_callback && can_integrate_forces) { - if (omit_forces_integration) { - btBody->clearForces(); - } - - BulletPhysicsDirectBodyState3D *bodyDirect = BulletPhysicsDirectBodyState3D::get_singleton(this); - - Variant variantBodyDirect = bodyDirect; - - Object *obj = force_integration_callback->callable.get_object(); - if (!obj) { - // Remove integration callback - 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; - Variant rv; - force_integration_callback->callable.call(vp, argc, rv, responseCallError); - } - } - - if (isScratchedSpaceOverrideModificator || 0 < countGravityPointSpaces) { - isScratchedSpaceOverrideModificator = false; - reload_space_override_modificator(); - } - - /// Lock axis - btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor()); - btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor()); - - previousActiveState = btBody->isActive(); -} - -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_callable.get_object()) { - force_integration_callback = memnew(ForceIntegrationCallback); - force_integration_callback->callable = p_callable; - force_integration_callback->udata = p_udata; - } -} - -void RigidBodyBullet::scratch_space_override_modificator() { - isScratchedSpaceOverrideModificator = true; -} - -void RigidBodyBullet::on_collision_filters_change() { - if (space) { - space->reload_collision_filters(this); - } - - set_activation_state(true); -} - -void RigidBodyBullet::on_collision_checker_start() { - prev_collision_count = collisionsCount; - collisionsCount = 0; - - // Swap array - Vector<RigidBodyBullet *> *s = prev_collision_traces; - prev_collision_traces = curr_collision_traces; - curr_collision_traces = s; -} - -void RigidBodyBullet::on_collision_checker_end() { - // Always true if active and not a static or kinematic body - updated = btBody->isActive() && !btBody->isStaticOrKinematicObject(); -} - -bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const real_t &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) { - if (collisionsCount >= maxCollisionsDetection) { - return false; - } - - CollisionData &cd = collisions.write[collisionsCount]; - cd.hitLocalLocation = p_hitLocalLocation; - cd.otherObject = p_otherObject; - cd.hitWorldLocation = p_hitWorldLocation; - cd.hitNormal = p_hitNormal; - cd.appliedImpulse = p_appliedImpulse; - cd.other_object_shape = p_other_shape_index; - cd.local_shape = p_local_shape_index; - - curr_collision_traces->write[collisionsCount] = p_otherObject; - - ++collisionsCount; - return true; -} - -bool RigidBodyBullet::was_colliding(RigidBodyBullet *p_other_object) { - for (int i = prev_collision_count - 1; 0 <= i; --i) { - if ((*prev_collision_traces)[i] == p_other_object) { - return true; - } - } - return false; -} - -void RigidBodyBullet::set_activation_state(bool p_active) { - if (p_active) { - btBody->activate(); - } else { - btBody->setActivationState(WANTS_DEACTIVATION); - } -} - -bool RigidBodyBullet::is_active() const { - return btBody->isActive(); -} - -void RigidBodyBullet::set_omit_forces_integration(bool p_omit) { - omit_forces_integration = p_omit; -} - -void RigidBodyBullet::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) { - switch (p_param) { - case PhysicsServer3D::BODY_PARAM_BOUNCE: - btBody->setRestitution(p_value); - break; - case PhysicsServer3D::BODY_PARAM_FRICTION: - btBody->setFriction(p_value); - break; - case PhysicsServer3D::BODY_PARAM_MASS: { - ERR_FAIL_COND(p_value < 0); - mass = p_value; - _internal_set_mass(p_value); - break; - } - case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: - linearDamp = p_value; - // Mark for updating total linear damping. - scratch_space_override_modificator(); - break; - case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: - angularDamp = p_value; - // Mark for updating total angular damping. - scratch_space_override_modificator(); - break; - case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: - gravity_scale = p_value; - // The Bullet gravity will be is set by reload_space_override_modificator. - // Mark for updating total gravity scale. - scratch_space_override_modificator(); - break; - default: - WARN_PRINT("Parameter " + itos(p_param) + " not supported by bullet. Value: " + itos(p_value)); - } -} - -real_t RigidBodyBullet::get_param(PhysicsServer3D::BodyParameter p_param) const { - switch (p_param) { - case PhysicsServer3D::BODY_PARAM_BOUNCE: - return btBody->getRestitution(); - case PhysicsServer3D::BODY_PARAM_FRICTION: - return btBody->getFriction(); - case PhysicsServer3D::BODY_PARAM_MASS: { - const btScalar invMass = btBody->getInvMass(); - return 0 == invMass ? 0 : 1 / invMass; - } - case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: - return linearDamp; - case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: - return angularDamp; - case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: - return gravity_scale; - default: - WARN_PRINT("Parameter " + itos(p_param) + " not supported by bullet"); - return 0; - } -} - -void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) { - // This is necessary to block force_integration until next move - can_integrate_forces = false; - destroy_kinematic_utilities(); - // The mode change is relevant to its mass - mode = p_mode; - switch (p_mode) { - case PhysicsServer3D::BODY_MODE_KINEMATIC: - reload_axis_lock(); - _internal_set_mass(0); - init_kinematic_utilities(); - break; - case PhysicsServer3D::BODY_MODE_STATIC: - reload_axis_lock(); - _internal_set_mass(0); - break; - case PhysicsServer3D::BODY_MODE_DYNAMIC: - reload_axis_lock(); - _internal_set_mass(0 == mass ? 1 : mass); - scratch_space_override_modificator(); - break; - case PhysicsServer3D::MODE_DYNAMIC_LINEAR: - reload_axis_lock(); - _internal_set_mass(0 == mass ? 1 : mass); - scratch_space_override_modificator(); - break; - } - - btBody->setAngularVelocity(btVector3(0, 0, 0)); - btBody->setLinearVelocity(btVector3(0, 0, 0)); -} - -PhysicsServer3D::BodyMode RigidBodyBullet::get_mode() const { - return mode; -} - -void RigidBodyBullet::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) { - switch (p_state) { - case PhysicsServer3D::BODY_STATE_TRANSFORM: - set_transform(p_variant); - break; - case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: - set_linear_velocity(p_variant); - break; - case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: - set_angular_velocity(p_variant); - break; - case PhysicsServer3D::BODY_STATE_SLEEPING: - set_activation_state(!bool(p_variant)); - break; - case PhysicsServer3D::BODY_STATE_CAN_SLEEP: - can_sleep = bool(p_variant); - if (!can_sleep) { - // Can't sleep - btBody->forceActivationState(DISABLE_DEACTIVATION); - } else { - btBody->forceActivationState(ACTIVE_TAG); - } - break; - } -} - -Variant RigidBodyBullet::get_state(PhysicsServer3D::BodyState p_state) const { - switch (p_state) { - case PhysicsServer3D::BODY_STATE_TRANSFORM: - return get_transform(); - case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: - return get_linear_velocity(); - case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: - return get_angular_velocity(); - case PhysicsServer3D::BODY_STATE_SLEEPING: - return !is_active(); - case PhysicsServer3D::BODY_STATE_CAN_SLEEP: - return can_sleep; - default: - WARN_PRINT("This state " + itos(p_state) + " is not supported by Bullet"); - return Variant(); - } -} - -void RigidBodyBullet::apply_central_impulse(const Vector3 &p_impulse) { - btVector3 btImpulse; - G_TO_B(p_impulse, btImpulse); - if (Vector3() != p_impulse) { - btBody->activate(); - } - btBody->applyCentralImpulse(btImpulse); -} - -void RigidBodyBullet::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { - btVector3 btImpulse; - btVector3 btPosition; - G_TO_B(p_impulse, btImpulse); - G_TO_B(p_position, btPosition); - if (Vector3() != p_impulse) { - btBody->activate(); - } - btBody->applyImpulse(btImpulse, btPosition); -} - -void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) { - btVector3 btImp; - G_TO_B(p_impulse, btImp); - if (Vector3() != p_impulse) { - btBody->activate(); - } - btBody->applyTorqueImpulse(btImp); -} - -void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_position) { - btVector3 btForce; - btVector3 btPosition; - G_TO_B(p_force, btForce); - G_TO_B(p_position, btPosition); - if (Vector3() != p_force) { - btBody->activate(); - } - btBody->applyForce(btForce, btPosition); -} - -void RigidBodyBullet::apply_central_force(const Vector3 &p_force) { - btVector3 btForce; - G_TO_B(p_force, btForce); - if (Vector3() != p_force) { - btBody->activate(); - } - btBody->applyCentralForce(btForce); -} - -void RigidBodyBullet::apply_torque(const Vector3 &p_torque) { - btVector3 btTorq; - G_TO_B(p_torque, btTorq); - if (Vector3() != p_torque) { - btBody->activate(); - } - btBody->applyTorque(btTorq); -} - -void RigidBodyBullet::set_applied_force(const Vector3 &p_force) { - btVector3 btVec = btBody->getTotalTorque(); - - if (Vector3() != p_force) { - btBody->activate(); - } - - btBody->clearForces(); - btBody->applyTorque(btVec); - - G_TO_B(p_force, btVec); - btBody->applyCentralForce(btVec); -} - -Vector3 RigidBodyBullet::get_applied_force() const { - Vector3 gTotForc; - B_TO_G(btBody->getTotalForce(), gTotForc); - return gTotForc; -} - -void RigidBodyBullet::set_applied_torque(const Vector3 &p_torque) { - btVector3 btVec = btBody->getTotalForce(); - - if (Vector3() != p_torque) { - btBody->activate(); - } - - btBody->clearForces(); - btBody->applyCentralForce(btVec); - - G_TO_B(p_torque, btVec); - btBody->applyTorque(btVec); -} - -Vector3 RigidBodyBullet::get_applied_torque() const { - Vector3 gTotTorq; - B_TO_G(btBody->getTotalTorque(), gTotTorq); - return gTotTorq; -} - -void RigidBodyBullet::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) { - if (lock) { - locked_axis |= p_axis; - } else { - locked_axis &= ~p_axis; - } - - reload_axis_lock(); -} - -bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { - return locked_axis & p_axis; -} - -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::MODE_DYNAMIC_LINEAR == mode) { - /// When character angular is always locked - btBody->setAngularFactor(btVector3(0., 0., 0.)); - } else { - btBody->setAngularFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z)))); - } -} - -void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { - if (p_enable) { - // This threshold enable CCD if the object moves more than - // 1 meter in one simulation frame - btBody->setCcdMotionThreshold(1e-7); - - /// Calculate using the rule write below the CCD swept sphere radius - /// CCD works on an embedded sphere of radius, make sure this radius - /// is embedded inside the convex objects, preferably smaller: - /// for an object of dimensions 1 meter, try 0.2 - btScalar radius(1.0); - if (btBody->getCollisionShape()) { - btVector3 center; - btBody->getCollisionShape()->getBoundingSphere(center, radius); - } - btBody->setCcdSweptSphereRadius(radius * 0.2); - } else { - btBody->setCcdMotionThreshold(0.); - btBody->setCcdSweptSphereRadius(0.); - } -} - -bool RigidBodyBullet::is_continuous_collision_detection_enabled() const { - return 0. < btBody->getCcdMotionThreshold(); -} - -void RigidBodyBullet::set_linear_velocity(const Vector3 &p_velocity) { - btVector3 btVec; - G_TO_B(p_velocity, btVec); - if (Vector3() != p_velocity) { - btBody->activate(); - } - btBody->setLinearVelocity(btVec); -} - -Vector3 RigidBodyBullet::get_linear_velocity() const { - Vector3 gVec; - B_TO_G(btBody->getLinearVelocity(), gVec); - return gVec; -} - -void RigidBodyBullet::set_angular_velocity(const Vector3 &p_velocity) { - btVector3 btVec; - G_TO_B(p_velocity, btVec); - if (Vector3() != p_velocity) { - btBody->activate(); - } - btBody->setAngularVelocity(btVec); -} - -Vector3 RigidBodyBullet::get_angular_velocity() const { - Vector3 gVec; - B_TO_G(btBody->getAngularVelocity(), gVec); - return gVec; -} - -void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) { - if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) { - if (space && space->get_delta_time() != 0) { - btBody->setLinearVelocity((p_global_transform.getOrigin() - btBody->getWorldTransform().getOrigin()) / space->get_delta_time()); - } - // The kinematic use MotionState class - godotMotionState->moveBody(p_global_transform); - } else { - // Is necessary to avoid wrong location on the rendering side on the next frame - godotMotionState->setWorldTransform(p_global_transform); - } - CollisionObjectBullet::set_transform__bullet(p_global_transform); -} - -const btTransform &RigidBodyBullet::get_transform__bullet() const { - if (is_static()) { - return RigidCollisionObjectBullet::get_transform__bullet(); - } else { - return godotMotionState->getCurrentWorldTransform(); - } -} - -void RigidBodyBullet::reload_shapes() { - RigidCollisionObjectBullet::reload_shapes(); - - const btScalar invMass = btBody->getInvMass(); - const btScalar mass = invMass == 0 ? 0 : 1 / invMass; - - if (mainShape) { - // inertia initialised zero here because some of bullet's collision - // shapes incorrectly do not set the vector in calculateLocalIntertia. - // Arbitrary zero is preferable to undefined behaviour. - btVector3 inertia(0, 0, 0); - if (EMPTY_SHAPE_PROXYTYPE != mainShape->getShapeType()) { // Necessary to avoid assertion of the empty shape - mainShape->calculateLocalInertia(mass, inertia); - } - btBody->setMassProps(mass, inertia); - } - btBody->updateInertiaTensor(); - - reload_kinematic_shapes(); - set_continuous_collision_detection(is_continuous_collision_detection_enabled()); - reload_body(); -} - -void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { - /// Add this area to the array in an ordered way - ++areaWhereIamCount; - if (areaWhereIamCount >= maxAreasWhereIam) { - --areaWhereIamCount; - return; - } - for (int i = 0; i < areaWhereIamCount; ++i) { - if (nullptr == areasWhereIam[i]) { - // This area has the highest priority - areasWhereIam.write[i] = p_area; - break; - } else { - if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) { - // The position was found, just shift all elements - for (int j = areaWhereIamCount; j > i; j--) { - areasWhereIam.write[j] = areasWhereIam[j - 1]; - } - areasWhereIam.write[i] = p_area; - break; - } - } - } - if (PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { - scratch_space_override_modificator(); - } - - if (p_area->is_spOv_gravityPoint()) { - ++countGravityPointSpaces; - ERR_FAIL_COND(countGravityPointSpaces <= 0); - } -} - -void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { - RigidCollisionObjectBullet::on_exit_area(p_area); - /// Remove this area and keep the order - /// N.B. Since I don't want resize the array I can't use the "erase" function - bool wasTheAreaFound = false; - for (int i = 0; i < areaWhereIamCount; ++i) { - if (p_area == areasWhereIam[i]) { - // The area was found, just shift down all elements - for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam.write[j] = areasWhereIam[j + 1]; - } - wasTheAreaFound = true; - break; - } - } - if (wasTheAreaFound) { - if (p_area->is_spOv_gravityPoint()) { - --countGravityPointSpaces; - ERR_FAIL_COND(countGravityPointSpaces < 0); - } - - --areaWhereIamCount; - areasWhereIam.write[areaWhereIamCount] = nullptr; // Even if this is not required, I clear the last element to be safe - if (PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { - scratch_space_override_modificator(); - } - } -} - -void RigidBodyBullet::reload_space_override_modificator() { - if (mode == PhysicsServer3D::BODY_MODE_STATIC) { - return; - } - - Vector3 newGravity(0.0, 0.0, 0.0); - real_t newLinearDamp = MAX(0.0, linearDamp); - real_t newAngularDamp = MAX(0.0, angularDamp); - - AreaBullet *currentArea; - // Variable used to calculate new gravity for gravity point areas, it is pointed by currentGravity pointer - Vector3 support_gravity(0, 0, 0); - - bool stopped = false; - for (int i = areaWhereIamCount - 1; (0 <= i) && !stopped; --i) { - currentArea = areasWhereIam[i]; - - if (!currentArea || PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) { - continue; - } - - /// Here is calculated the gravity - if (currentArea->is_spOv_gravityPoint()) { - /// It calculates the direction of new gravity - support_gravity = currentArea->get_transform().xform(currentArea->get_spOv_gravityVec()) - get_transform().get_origin(); - real_t distanceMag = support_gravity.length(); - // Normalized in this way to avoid the double call of function "length()" - if (distanceMag == 0) { - support_gravity.x = 0; - support_gravity.y = 0; - support_gravity.z = 0; - } else { - support_gravity.x /= distanceMag; - support_gravity.y /= distanceMag; - support_gravity.z /= distanceMag; - } - - /// Here is calculated the final gravity - if (currentArea->get_spOv_gravityPointDistanceScale() > 0) { - // Scaled gravity by distance - support_gravity *= currentArea->get_spOv_gravityMag() / Math::pow(distanceMag * currentArea->get_spOv_gravityPointDistanceScale() + 1, 2); - } else { - // Unscaled gravity - support_gravity *= currentArea->get_spOv_gravityMag(); - } - } else { - support_gravity = currentArea->get_spOv_gravityVec() * currentArea->get_spOv_gravityMag(); - } - - switch (currentArea->get_spOv_mode()) { - case PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED: - /// This area does not affect gravity/damp. These are generally areas - /// that exist only to detect collisions, and objects entering or exiting them. - break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: - /// This area adds its gravity/damp values to whatever has been - /// calculated so far. This way, many overlapping areas can combine - /// their physics to make interesting - newGravity += support_gravity; - newLinearDamp += currentArea->get_spOv_linearDamp(); - newAngularDamp += currentArea->get_spOv_angularDamp(); - break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: - /// This area adds its gravity/damp values to whatever has been calculated - /// so far. Then stops taking into account the rest of the areas, even the - /// default one. - newGravity += support_gravity; - newLinearDamp += currentArea->get_spOv_linearDamp(); - newAngularDamp += currentArea->get_spOv_angularDamp(); - stopped = true; - break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: - /// This area replaces any gravity/damp, even the default one, and - /// stops taking into account the rest of the areas. - newGravity = support_gravity; - newLinearDamp = currentArea->get_spOv_linearDamp(); - newAngularDamp = currentArea->get_spOv_angularDamp(); - stopped = true; - break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: - /// This area replaces any gravity/damp calculated so far, but keeps - /// calculating the rest of the areas, down to the default one. - newGravity = support_gravity; - newLinearDamp = currentArea->get_spOv_linearDamp(); - newAngularDamp = currentArea->get_spOv_angularDamp(); - break; - } - } - - // Add default gravity and damping from space. - if (!stopped) { - newGravity += space->get_gravity_direction() * space->get_gravity_magnitude(); - newLinearDamp += space->get_linear_damp(); - newAngularDamp += space->get_angular_damp(); - } - - btVector3 newBtGravity; - G_TO_B(newGravity * gravity_scale, newBtGravity); - - btBody->setGravity(newBtGravity); - btBody->setDamping(newLinearDamp, newAngularDamp); -} - -void RigidBodyBullet::reload_kinematic_shapes() { - if (!kinematic_utilities) { - return; - } - kinematic_utilities->copyAllOwnerShapes(); -} - -void RigidBodyBullet::notify_transform_changed() { - RigidCollisionObjectBullet::notify_transform_changed(); - can_integrate_forces = true; -} - -void RigidBodyBullet::_internal_set_mass(real_t p_mass) { - btVector3 localInertia(0, 0, 0); - - int clearedCurrentFlags = btBody->getCollisionFlags(); - clearedCurrentFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_CHARACTER_OBJECT); - - // 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_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LINEAR != mode) { - return; - } - - m_isStatic = false; - if (mainShape) { - mainShape->calculateLocalInertia(p_mass, localInertia); - } - - 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); - } - - if (can_sleep) { - btBody->forceActivationState(ACTIVE_TAG); // ACTIVE_TAG 1 - } else { - btBody->forceActivationState(DISABLE_DEACTIVATION); // DISABLE_DEACTIVATION 4 - } - } else { - if (PhysicsServer3D::BODY_MODE_STATIC != mode && PhysicsServer3D::BODY_MODE_KINEMATIC != mode) { - return; - } - - m_isStatic = true; - if (PhysicsServer3D::BODY_MODE_STATIC == mode) { - btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_STATIC_OBJECT); - } else { - btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_KINEMATIC_OBJECT); - set_transform__bullet(btBody->getWorldTransform()); // Set current Transform using kinematic method - } - btBody->forceActivationState(DISABLE_SIMULATION); // DISABLE_SIMULATION 5 - } - - btBody->setMassProps(p_mass, localInertia); - btBody->updateInertiaTensor(); - - reload_body(); -} diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h deleted file mode 100644 index 01ac1e4836..0000000000 --- a/modules/bullet/rigid_body_bullet.h +++ /dev/null @@ -1,332 +0,0 @@ -/*************************************************************************/ -/* rigid_body_bullet.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 BODYBULLET_H -#define BODYBULLET_H - -#include "collision_object_bullet.h" -#include "space_bullet.h" - -#include <BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h> -#include <LinearMath/btTransform.h> - -/** - @author AndreaCatania -*/ - -class AreaBullet; -class SpaceBullet; -class btRigidBody; -class GodotMotionState; -class BulletPhysicsDirectBodyState3D; - -/// This class could be used in multi thread with few changes but currently -/// is set to be only in one single thread. -/// -/// In the system there is only one object at a time that manage all bodies and is -/// created by BulletPhysicsServer3D and is held by the "singleton" variable of this class -/// Each time something require it, the body must be set again. -class BulletPhysicsDirectBodyState3D : public PhysicsDirectBodyState3D { - GDCLASS(BulletPhysicsDirectBodyState3D, PhysicsDirectBodyState3D); - - static BulletPhysicsDirectBodyState3D *singleton; - -public: - /// This class avoid the creation of more object of this class - static void initSingleton() { - if (!singleton) { - singleton = memnew(BulletPhysicsDirectBodyState3D); - } - } - - static void destroySingleton() { - memdelete(singleton); - singleton = nullptr; - } - - static void singleton_setDeltaTime(real_t p_deltaTime) { - singleton->deltaTime = p_deltaTime; - } - - static BulletPhysicsDirectBodyState3D *get_singleton(RigidBodyBullet *p_body) { - singleton->body = p_body; - return singleton; - } - -public: - RigidBodyBullet *body = nullptr; - real_t deltaTime = 0.0; - -private: - BulletPhysicsDirectBodyState3D() {} - -public: - virtual Vector3 get_total_gravity() const override; - virtual real_t get_total_angular_damp() const override; - virtual real_t get_total_linear_damp() const override; - - virtual Vector3 get_center_of_mass() const override; - virtual Basis get_principal_inertia_axes() const override; - // get the mass - virtual real_t get_inverse_mass() const override; - // get density of this body space - virtual Vector3 get_inverse_inertia() const override; - // get density of this body space - virtual Basis get_inverse_inertia_tensor() const override; - - virtual void set_linear_velocity(const Vector3 &p_velocity) override; - virtual Vector3 get_linear_velocity() const override; - - virtual void set_angular_velocity(const Vector3 &p_velocity) override; - virtual Vector3 get_angular_velocity() const override; - - virtual void set_transform(const Transform3D &p_transform) override; - virtual Transform3D get_transform() const override; - - virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) 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; - virtual void add_torque(const Vector3 &p_torque) override; - virtual void apply_central_impulse(const Vector3 &p_impulse) override; - virtual void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override; - virtual void apply_torque_impulse(const Vector3 &p_impulse) override; - - virtual void set_sleep_state(bool p_sleep) override; - virtual bool is_sleeping() const override; - - virtual int get_contact_count() const override; - - virtual Vector3 get_contact_local_position(int p_contact_idx) const override; - virtual Vector3 get_contact_local_normal(int p_contact_idx) const override; - virtual real_t get_contact_impulse(int p_contact_idx) const override; - virtual int get_contact_local_shape(int p_contact_idx) const override; - - virtual RID get_contact_collider(int p_contact_idx) const override; - virtual Vector3 get_contact_collider_position(int p_contact_idx) const override; - virtual ObjectID get_contact_collider_id(int p_contact_idx) const override; - virtual int get_contact_collider_shape(int p_contact_idx) const override; - virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const override; - - virtual real_t get_step() const override { return deltaTime; } - virtual void integrate_forces() override { - // Skip the execution of this function - } - - virtual PhysicsDirectSpaceState3D *get_space_state() override; -}; - -class RigidBodyBullet : public RigidCollisionObjectBullet { -public: - struct CollisionData { - RigidBodyBullet *otherObject = nullptr; - int other_object_shape = 0; - int local_shape = 0; - Vector3 hitLocalLocation; - Vector3 hitWorldLocation; - Vector3 hitNormal; - real_t appliedImpulse = 0.0; - }; - - struct ForceIntegrationCallback { - Callable callable; - Variant udata; - }; - - /// Used to hold shapes - struct KinematicShape { - class btConvexShape *shape = nullptr; - btTransform transform; - - KinematicShape() {} - bool is_active() const { return shape; } - }; - - struct KinematicUtilities { - RigidBodyBullet *owner = nullptr; - btScalar safe_margin; - Vector<KinematicShape> shapes; - - KinematicUtilities(RigidBodyBullet *p_owner); - ~KinematicUtilities(); - - void setSafeMargin(btScalar p_margin); - /// Used to set the default shape to ghost - void copyAllOwnerShapes(); - - private: - void just_delete_shapes(int new_size); - }; - -private: - friend class BulletPhysicsDirectBodyState3D; - - // This is required only for Kinematic movement - KinematicUtilities *kinematic_utilities = nullptr; - - PhysicsServer3D::BodyMode mode; - GodotMotionState *godotMotionState; - btRigidBody *btBody; - uint16_t locked_axis = 0; - real_t mass = 1.0; - real_t gravity_scale = 1.0; - real_t linearDamp = 0.0; - real_t angularDamp = 0.0; - bool can_sleep = true; - bool omit_forces_integration = false; - bool can_integrate_forces = false; - - Vector<CollisionData> collisions; - Vector<RigidBodyBullet *> collision_traces_1; - Vector<RigidBodyBullet *> collision_traces_2; - Vector<RigidBodyBullet *> *prev_collision_traces; - Vector<RigidBodyBullet *> *curr_collision_traces; - - // these parameters are used to avoid vector resize - int maxCollisionsDetection = 0; - int collisionsCount = 0; - int prev_collision_count = 0; - - Vector<AreaBullet *> areasWhereIam; - // these parameters are used to avoid vector resize - int maxAreasWhereIam = 10; - int areaWhereIamCount = 0; - // Used to know if the area is used as gravity point - int countGravityPointSpaces = 0; - bool isScratchedSpaceOverrideModificator = false; - - bool previousActiveState = true; // Last check state - - ForceIntegrationCallback *force_integration_callback = nullptr; - -public: - RigidBodyBullet(); - ~RigidBodyBullet(); - - void init_kinematic_utilities(); - void destroy_kinematic_utilities(); - _FORCE_INLINE_ KinematicUtilities *get_kinematic_utilities() const { return kinematic_utilities; } - - _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; } - - virtual void main_shape_changed(); - virtual void reload_body(); - virtual void set_space(SpaceBullet *p_space); - - virtual void dispatch_callbacks(); - 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(); - virtual void on_collision_checker_start(); - virtual void on_collision_checker_end(); - - void set_max_collisions_detection(int p_maxCollisionsDetection) { - ERR_FAIL_COND(0 > p_maxCollisionsDetection); - - maxCollisionsDetection = p_maxCollisionsDetection; - - collisions.resize(p_maxCollisionsDetection); - collision_traces_1.resize(p_maxCollisionsDetection); - collision_traces_2.resize(p_maxCollisionsDetection); - - collisionsCount = 0; - prev_collision_count = MIN(prev_collision_count, p_maxCollisionsDetection); - } - int get_max_collisions_detection() { - return maxCollisionsDetection; - } - - bool can_add_collision() { return collisionsCount < maxCollisionsDetection; } - bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const real_t &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index); - bool was_colliding(RigidBodyBullet *p_other_object); - - void set_activation_state(bool p_active); - bool is_active() const; - - void set_omit_forces_integration(bool p_omit); - _FORCE_INLINE_ bool get_omit_forces_integration() const { return omit_forces_integration; } - - void set_param(PhysicsServer3D::BodyParameter p_param, real_t); - real_t get_param(PhysicsServer3D::BodyParameter p_param) const; - - void set_mode(PhysicsServer3D::BodyMode p_mode); - PhysicsServer3D::BodyMode get_mode() const; - - void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant); - Variant get_state(PhysicsServer3D::BodyState p_state) const; - - void apply_central_impulse(const Vector3 &p_impulse); - void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); - void apply_torque_impulse(const Vector3 &p_impulse); - - void apply_central_force(const Vector3 &p_force); - void apply_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()); - void apply_torque(const Vector3 &p_torque); - - void set_applied_force(const Vector3 &p_force); - Vector3 get_applied_force() const; - void set_applied_torque(const Vector3 &p_torque); - Vector3 get_applied_torque() const; - - void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock); - bool is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const; - void reload_axis_lock(); - - /// Doc: - /// https://web.archive.org/web/20180404091446/https://www.bulletphysics.org/mediawiki-1.5.8/index.php/Anti_tunneling_by_Motion_Clamping - void set_continuous_collision_detection(bool p_enable); - bool is_continuous_collision_detection_enabled() const; - - void set_linear_velocity(const Vector3 &p_velocity); - Vector3 get_linear_velocity() const; - - void set_angular_velocity(const Vector3 &p_velocity); - Vector3 get_angular_velocity() const; - - virtual void set_transform__bullet(const btTransform &p_global_transform); - virtual const btTransform &get_transform__bullet() const; - - virtual void reload_shapes(); - - virtual void on_enter_area(AreaBullet *p_area); - virtual void on_exit_area(AreaBullet *p_area); - void reload_space_override_modificator(); - - /// Kinematic - void reload_kinematic_shapes(); - - virtual void notify_transform_changed(); - -private: - void _internal_set_mass(real_t p_mass); -}; - -#endif diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp deleted file mode 100644 index ec039ba842..0000000000 --- a/modules/bullet/shape_bullet.cpp +++ /dev/null @@ -1,599 +0,0 @@ -/*************************************************************************/ -/* shape_bullet.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 "shape_bullet.h" - -#include "btRayShape.h" -#include "bullet_physics_server.h" -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "core/config/project_settings.h" -#include "shape_owner_bullet.h" - -#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h> -#include <BulletCollision/CollisionShapes/btConvexPointCloudShape.h> -#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> -#include <btBulletCollisionCommon.h> - -/** - @author AndreaCatania -*/ - -ShapeBullet::ShapeBullet() {} - -ShapeBullet::~ShapeBullet() {} - -btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge) { - btVector3 s; - G_TO_B(p_implicit_scale, s); - return create_bt_shape(s, p_extra_edge); -} - -btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const { - p_btShape->setUserPointer(const_cast<ShapeBullet *>(this)); - p_btShape->setMargin(margin); - return p_btShape; -} - -void ShapeBullet::notifyShapeChanged() { - for (const KeyValue<ShapeOwnerBullet *, int> &E : owners) { - ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E.key); - owner->shape_changed(owner->find_shape(this)); - } -} - -void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) { - Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner); - if (E) { - E->get()++; - } else { - owners[p_owner] = 1; // add new owner - } -} - -void ShapeBullet::remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody) { - Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner); - if (!E) { - return; - } - E->get()--; - if (p_permanentlyFromThisBody || 0 >= E->get()) { - owners.erase(E); - } -} - -bool ShapeBullet::is_owner(ShapeOwnerBullet *p_owner) const { - return owners.has(p_owner); -} - -const Map<ShapeOwnerBullet *, int> &ShapeBullet::get_owners() const { - return owners; -} - -void ShapeBullet::set_margin(real_t p_margin) { - margin = p_margin; - notifyShapeChanged(); -} - -real_t ShapeBullet::get_margin() const { - return margin; -} - -btEmptyShape *ShapeBullet::create_shape_empty() { - return bulletnew(btEmptyShape); -} - -btStaticPlaneShape *ShapeBullet::create_shape_world_boundary(const btVector3 &planeNormal, btScalar planeConstant) { - return bulletnew(btStaticPlaneShape(planeNormal, planeConstant)); -} - -btSphereShape *ShapeBullet::create_shape_sphere(btScalar radius) { - return bulletnew(btSphereShape(radius)); -} - -btBoxShape *ShapeBullet::create_shape_box(const btVector3 &boxHalfExtents) { - return bulletnew(btBoxShape(boxHalfExtents)); -} - -btCapsuleShape *ShapeBullet::create_shape_capsule(btScalar radius, btScalar height) { - return bulletnew(btCapsuleShape(radius, height)); -} - -btCylinderShape *ShapeBullet::create_shape_cylinder(btScalar radius, btScalar height) { - return bulletnew(btCylinderShape(btVector3(radius, height / 2.0, radius))); -} - -btConvexPointCloudShape *ShapeBullet::create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling) { - return bulletnew(btConvexPointCloudShape(&p_vertices[0], p_vertices.size(), p_local_scaling)); -} - -btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling) { - if (p_mesh_shape) { - return bulletnew(btScaledBvhTriangleMeshShape(p_mesh_shape, p_local_scaling)); - } else { - return nullptr; - } -} - -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; - const void *heightsPtr = p_heights.ptr(); - - btHeightfieldTerrainShape *heightfield = bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, p_min_height, p_max_height, YAxis, PHY_FLOAT, flipQuadEdges)); - - // The shape can be created without params when you do PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_HEIGHTMAP) - if (heightsPtr) { - heightfield->buildAccelerator(16); - } - - return heightfield; -} - -btRayShape *ShapeBullet::create_shape_ray(real_t p_length, bool p_slips_on_slope) { - btRayShape *r(bulletnew(btRayShape(p_length))); - r->setSlipsOnSlope(p_slips_on_slope); - return r; -} - -/* World boundary */ - -WorldBoundaryShapeBullet::WorldBoundaryShapeBullet() : - ShapeBullet() {} - -void WorldBoundaryShapeBullet::set_data(const Variant &p_data) { - setup(p_data); -} - -Variant WorldBoundaryShapeBullet::get_data() const { - return plane; -} - -PhysicsServer3D::ShapeType WorldBoundaryShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_WORLD_BOUNDARY; -} - -void WorldBoundaryShapeBullet::setup(const Plane &p_plane) { - plane = p_plane; - notifyShapeChanged(); -} - -btCollisionShape *WorldBoundaryShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - btVector3 btPlaneNormal; - G_TO_B(plane.normal, btPlaneNormal); - return prepare(WorldBoundaryShapeBullet::create_shape_world_boundary(btPlaneNormal, plane.d)); -} - -/* Sphere */ - -SphereShapeBullet::SphereShapeBullet() : - ShapeBullet() {} - -void SphereShapeBullet::set_data(const Variant &p_data) { - setup(p_data); -} - -Variant SphereShapeBullet::get_data() const { - return radius; -} - -PhysicsServer3D::ShapeType SphereShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_SPHERE; -} - -void SphereShapeBullet::setup(real_t p_radius) { - radius = p_radius; - notifyShapeChanged(); -} - -btCollisionShape *SphereShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - return prepare(ShapeBullet::create_shape_sphere(radius * p_implicit_scale[0] + p_extra_edge)); -} - -/* Box */ -BoxShapeBullet::BoxShapeBullet() : - ShapeBullet() {} - -void BoxShapeBullet::set_data(const Variant &p_data) { - setup(p_data); -} - -Variant BoxShapeBullet::get_data() const { - Vector3 g_half_extents; - B_TO_G(half_extents, g_half_extents); - return g_half_extents; -} - -PhysicsServer3D::ShapeType BoxShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_BOX; -} - -void BoxShapeBullet::setup(const Vector3 &p_half_extents) { - G_TO_B(p_half_extents, half_extents); - notifyShapeChanged(); -} - -btCollisionShape *BoxShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - return prepare(ShapeBullet::create_shape_box((half_extents * p_implicit_scale) + btVector3(p_extra_edge, p_extra_edge, p_extra_edge))); -} - -/* Capsule */ - -CapsuleShapeBullet::CapsuleShapeBullet() : - ShapeBullet() {} - -void CapsuleShapeBullet::set_data(const Variant &p_data) { - Dictionary d = p_data; - ERR_FAIL_COND(!d.has("radius")); - ERR_FAIL_COND(!d.has("height")); - setup(d["height"], d["radius"]); -} - -Variant CapsuleShapeBullet::get_data() const { - Dictionary d; - d["radius"] = radius; - d["height"] = height; - return d; -} - -PhysicsServer3D::ShapeType CapsuleShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_CAPSULE; -} - -void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) { - radius = p_radius; - height = p_height; - notifyShapeChanged(); -} - -btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_extra_edge, height * p_implicit_scale[1])); -} - -/* Cylinder */ - -CylinderShapeBullet::CylinderShapeBullet() : - ShapeBullet() {} - -void CylinderShapeBullet::set_data(const Variant &p_data) { - Dictionary d = p_data; - ERR_FAIL_COND(!d.has("radius")); - ERR_FAIL_COND(!d.has("height")); - setup(d["height"], d["radius"]); -} - -Variant CylinderShapeBullet::get_data() const { - Dictionary d; - d["radius"] = radius; - d["height"] = height; - return d; -} - -PhysicsServer3D::ShapeType CylinderShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_CYLINDER; -} - -void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) { - radius = p_radius; - height = p_height; - notifyShapeChanged(); -} - -btCollisionShape *CylinderShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { - return prepare(ShapeBullet::create_shape_cylinder(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); -} - -/* Convex polygon */ - -ConvexPolygonShapeBullet::ConvexPolygonShapeBullet() : - ShapeBullet() {} - -void ConvexPolygonShapeBullet::set_data(const Variant &p_data) { - setup(p_data); -} - -void ConvexPolygonShapeBullet::get_vertices(Vector<Vector3> &out_vertices) { - const int n_of_vertices = vertices.size(); - out_vertices.resize(n_of_vertices); - for (int i = n_of_vertices - 1; 0 <= i; --i) { - B_TO_G(vertices[i], out_vertices.write[i]); - } -} - -Variant ConvexPolygonShapeBullet::get_data() const { - ConvexPolygonShapeBullet *variable_self = const_cast<ConvexPolygonShapeBullet *>(this); - Vector<Vector3> out_vertices; - variable_self->get_vertices(out_vertices); - return out_vertices; -} - -PhysicsServer3D::ShapeType ConvexPolygonShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_CONVEX_POLYGON; -} - -void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) { - // Make a copy of vertices - const int n_of_vertices = p_vertices.size(); - vertices.resize(n_of_vertices); - for (int i = n_of_vertices - 1; 0 <= i; --i) { - G_TO_B(p_vertices[i], vertices[i]); - } - notifyShapeChanged(); -} - -btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - if (!vertices.size()) { - // This is necessary since 0 vertices - return prepare(ShapeBullet::create_shape_empty()); - } - btCollisionShape *cs(ShapeBullet::create_shape_convex(vertices)); - cs->setLocalScaling(p_implicit_scale); - prepare(cs); - return cs; -} - -/* Concave polygon */ - -ConcavePolygonShapeBullet::ConcavePolygonShapeBullet() : - ShapeBullet() {} - -ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() { - if (meshShape) { - delete meshShape->getMeshInterface(); - delete meshShape->getTriangleInfoMap(); - bulletdelete(meshShape); - } - faces = Vector<Vector3>(); -} - -void ConcavePolygonShapeBullet::set_data(const Variant &p_data) { - Dictionary d = p_data; - ERR_FAIL_COND(!d.has("faces")); - - setup(d["faces"]); -} - -Variant ConcavePolygonShapeBullet::get_data() const { - Dictionary d; - d["faces"] = faces; - - return d; -} - -PhysicsServer3D::ShapeType ConcavePolygonShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; -} - -void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) { - faces = p_faces; - if (meshShape) { - /// Clear previous created shape - delete meshShape->getMeshInterface(); - delete meshShape->getTriangleInfoMap(); - bulletdelete(meshShape); - } - int src_face_count = faces.size(); - if (0 < src_face_count) { - // It counts the faces and assert the array contains the correct number of vertices. - ERR_FAIL_COND(src_face_count % 3); - - btTriangleMesh *shapeInterface = bulletnew(btTriangleMesh); - src_face_count /= 3; - const Vector3 *r = p_faces.ptr(); - const Vector3 *facesr = r; - - btVector3 supVec_0; - btVector3 supVec_1; - btVector3 supVec_2; - for (int i = 0; i < src_face_count; ++i) { - G_TO_B(facesr[i * 3 + 0], supVec_0); - G_TO_B(facesr[i * 3 + 1], supVec_1); - G_TO_B(facesr[i * 3 + 2], supVec_2); - - // Inverted from standard godot otherwise btGenerateInternalEdgeInfo generates wrong edge info - shapeInterface->addTriangle(supVec_2, supVec_1, supVec_0); - } - - const bool useQuantizedAabbCompression = true; - - meshShape = bulletnew(btBvhTriangleMeshShape(shapeInterface, useQuantizedAabbCompression)); - - if (GLOBAL_DEF("physics/3d/smooth_trimesh_collision", false)) { - btTriangleInfoMap *triangleInfoMap = new btTriangleInfoMap(); - btGenerateInternalEdgeInfo(meshShape, triangleInfoMap); - } - } else { - meshShape = nullptr; - ERR_PRINT("The faces count are 0, the mesh shape cannot be created"); - } - notifyShapeChanged(); -} - -btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape); - if (!cs) { - // This is necessary since if 0 faces the creation of concave return null - cs = ShapeBullet::create_shape_empty(); - } - cs->setLocalScaling(p_implicit_scale); - prepare(cs); - cs->setMargin(0); - return cs; -} - -/* Height map shape */ - -HeightMapShapeBullet::HeightMapShapeBullet() : - ShapeBullet() {} - -void HeightMapShapeBullet::set_data(const Variant &p_data) { - ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY); - Dictionary d = p_data; - ERR_FAIL_COND(!d.has("width")); - ERR_FAIL_COND(!d.has("depth")); - ERR_FAIL_COND(!d.has("heights")); - - real_t l_min_height = 0.0; - real_t l_max_height = 0.0; - - // If specified, min and max height will be used as precomputed values - if (d.has("min_height")) { - l_min_height = d["min_height"]; - } - if (d.has("max_height")) { - l_max_height = d["max_height"]; - } - - ERR_FAIL_COND(l_min_height > l_max_height); - - int l_width = d["width"]; - int l_depth = d["depth"]; - - 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."); - - Vector<float> l_heights; - Variant l_heights_v = d["heights"]; - - if (l_heights_v.get_type() == Variant::PACKED_FLOAT32_ARRAY) { - // Ready-to-use heights can be passed - - l_heights = l_heights_v; - - } else if (l_heights_v.get_type() == Variant::OBJECT) { - // If an image is passed, we have to convert it to a format Bullet supports. - // this would be expensive to do with a script, so it's nice to have it here. - - Ref<Image> l_image = l_heights_v; - ERR_FAIL_COND(l_image.is_null()); - - // Float is the only common format between Godot and Bullet that can be used for decent collision. - // (Int16 would be nice too but we still don't have it) - // We could convert here automatically but it's better to not be intrusive and let the caller do it if necessary. - ERR_FAIL_COND(l_image->get_format() != Image::FORMAT_RF); - - PackedByteArray im_data = l_image->get_data(); - - l_heights.resize(l_image->get_width() * l_image->get_height()); - - float *w = l_heights.ptrw(); - const uint8_t *r = im_data.ptr(); - 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) { - w[i] = rp[i]; - } - - } else { - ERR_FAIL_MSG("Expected PackedFloat32Array or float Image."); - } - - ERR_FAIL_COND(l_width <= 0); - ERR_FAIL_COND(l_depth <= 0); - ERR_FAIL_COND(l_heights.size() != (l_width * l_depth)); - - // Compute min and max heights if not specified. - if (!d.has("min_height") && !d.has("max_height")) { - const float *r = l_heights.ptr(); - int heights_size = l_heights.size(); - - for (int i = 0; i < heights_size; ++i) { - float h = r[i]; - - if (h < l_min_height) { - l_min_height = h; - } else if (h > l_max_height) { - l_max_height = h; - } - } - } - - setup(l_heights, l_width, l_depth, l_min_height, l_max_height); -} - -Variant HeightMapShapeBullet::get_data() const { - ERR_FAIL_V(Variant()); -} - -PhysicsServer3D::ShapeType HeightMapShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_HEIGHTMAP; -} - -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 - heights = p_heights; - - width = p_width; - depth = p_depth; - min_height = p_min_height; - max_height = p_max_height; - notifyShapeChanged(); -} - -btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, min_height, max_height)); - cs->setLocalScaling(p_implicit_scale); - prepare(cs); - return cs; -} - -/* Ray shape */ -RayShapeBullet::RayShapeBullet() : - ShapeBullet() {} - -void RayShapeBullet::set_data(const Variant &p_data) { - Dictionary d = p_data; - setup(d["length"], d["slips_on_slope"]); -} - -Variant RayShapeBullet::get_data() const { - Dictionary d; - d["length"] = length; - d["slips_on_slope"] = slips_on_slope; - return d; -} - -PhysicsServer3D::ShapeType RayShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_RAY; -} - -void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) { - length = p_length; - slips_on_slope = p_slips_on_slope; - notifyShapeChanged(); -} - -btCollisionShape *RayShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { - return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_extra_edge, slips_on_slope)); -} diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h deleted file mode 100644 index 0822399b5e..0000000000 --- a/modules/bullet/shape_bullet.h +++ /dev/null @@ -1,247 +0,0 @@ -/*************************************************************************/ -/* shape_bullet.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 SHAPE_BULLET_H -#define SHAPE_BULLET_H - -#include "core/math/geometry_3d.h" -#include "core/variant/variant.h" -#include "rid_bullet.h" -#include "servers/physics_server_3d.h" - -#include <LinearMath/btAlignedObjectArray.h> -#include <LinearMath/btScalar.h> -#include <LinearMath/btVector3.h> - -/** - @author AndreaCatania -*/ - -class ShapeBullet; -class btCollisionShape; -class ShapeOwnerBullet; -class btBvhTriangleMeshShape; - -class ShapeBullet : public RIDBullet { - Map<ShapeOwnerBullet *, int> owners; - real_t margin = 0.04; - -protected: - /// return self - btCollisionShape *prepare(btCollisionShape *p_btShape) const; - void notifyShapeChanged(); - -public: - ShapeBullet(); - virtual ~ShapeBullet(); - - btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge = 0); - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0) = 0; - - void add_owner(ShapeOwnerBullet *p_owner); - void remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody = false); - bool is_owner(ShapeOwnerBullet *p_owner) const; - const Map<ShapeOwnerBullet *, int> &get_owners() const; - - void set_margin(real_t p_margin); - real_t get_margin() const; - - /// Setup the shape - virtual void set_data(const Variant &p_data) = 0; - virtual Variant get_data() const = 0; - - virtual PhysicsServer3D::ShapeType get_type() const = 0; - -public: - static class btEmptyShape *create_shape_empty(); - static class btStaticPlaneShape *create_shape_world_boundary(const btVector3 &planeNormal, btScalar planeConstant); - static class btSphereShape *create_shape_sphere(btScalar radius); - static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents); - static class btCapsuleShape *create_shape_capsule(btScalar radius, btScalar height); - static class btCylinderShape *create_shape_cylinder(btScalar radius, btScalar height); - /// 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<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); -}; - -class WorldBoundaryShapeBullet : public ShapeBullet { - Plane plane; - -public: - WorldBoundaryShapeBullet(); - - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(const Plane &p_plane); -}; - -class SphereShapeBullet : public ShapeBullet { - real_t radius; - -public: - SphereShapeBullet(); - - _FORCE_INLINE_ real_t get_radius() { return radius; } - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(real_t p_radius); -}; - -class BoxShapeBullet : public ShapeBullet { - btVector3 half_extents; - -public: - BoxShapeBullet(); - - _FORCE_INLINE_ const btVector3 &get_half_extents() { return half_extents; } - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(const Vector3 &p_half_extents); -}; - -class CapsuleShapeBullet : public ShapeBullet { - real_t height; - real_t radius; - -public: - CapsuleShapeBullet(); - - _FORCE_INLINE_ real_t get_height() { return height; } - _FORCE_INLINE_ real_t get_radius() { return radius; } - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(real_t p_height, real_t p_radius); -}; - -class CylinderShapeBullet : public ShapeBullet { - real_t height; - real_t radius; - -public: - CylinderShapeBullet(); - - _FORCE_INLINE_ real_t get_height() { return height; } - _FORCE_INLINE_ real_t get_radius() { return radius; } - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); - -private: - void setup(real_t p_height, real_t p_radius); -}; - -class ConvexPolygonShapeBullet : public ShapeBullet { -public: - btAlignedObjectArray<btVector3> vertices; - - ConvexPolygonShapeBullet(); - - virtual void set_data(const Variant &p_data); - void get_vertices(Vector<Vector3> &out_vertices); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(const Vector<Vector3> &p_vertices); -}; - -class ConcavePolygonShapeBullet : public ShapeBullet { - class btBvhTriangleMeshShape *meshShape = nullptr; - -public: - Vector<Vector3> faces; - - ConcavePolygonShapeBullet(); - virtual ~ConcavePolygonShapeBullet(); - - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(Vector<Vector3> p_faces); -}; - -class HeightMapShapeBullet : public ShapeBullet { -public: - Vector<float> heights; - int width = 0; - int depth = 0; - real_t min_height = 0.0; - real_t max_height = 0.0; - - HeightMapShapeBullet(); - - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - 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 { -public: - real_t length = 1.0; - bool slips_on_slope = false; - - RayShapeBullet(); - - virtual void set_data(const Variant &p_data); - virtual Variant get_data() const; - virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); - -private: - void setup(real_t p_length, bool p_slips_on_slope); -}; -#endif diff --git a/modules/bullet/shape_owner_bullet.cpp b/modules/bullet/shape_owner_bullet.cpp deleted file mode 100644 index ea8821eaec..0000000000 --- a/modules/bullet/shape_owner_bullet.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************/ -/* shape_owner_bullet.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 "shape_owner_bullet.h" - -/** - @author AndreaCatania -*/ diff --git a/modules/bullet/shape_owner_bullet.h b/modules/bullet/shape_owner_bullet.h deleted file mode 100644 index 4bd583e096..0000000000 --- a/modules/bullet/shape_owner_bullet.h +++ /dev/null @@ -1,54 +0,0 @@ -/*************************************************************************/ -/* shape_owner_bullet.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 SHAPE_OWNER_BULLET_H -#define SHAPE_OWNER_BULLET_H - -#include "rid_bullet.h" - -/** - @author AndreaCatania -*/ - -class ShapeBullet; -class btCollisionShape; -class CollisionObjectBullet; - -/// Each class that want to use Shapes must inherit this class -/// E.G. BodyShape is a child of this -class ShapeOwnerBullet { -public: - virtual int find_shape(ShapeBullet *p_shape) const = 0; - virtual void shape_changed(int p_shape_index) = 0; - virtual void reload_shapes() = 0; - virtual void remove_shape_full(class ShapeBullet *p_shape) = 0; - virtual ~ShapeOwnerBullet() {} -}; -#endif diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp deleted file mode 100644 index 1d83118468..0000000000 --- a/modules/bullet/slider_joint_bullet.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/*************************************************************************/ -/* slider_joint_bullet.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 "slider_joint_bullet.h" - -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "rigid_body_bullet.h" - -#include <BulletDynamics/ConstraintSolver/btSliderConstraint.h> - -/** - @author AndreaCatania -*/ - -SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : - JointBullet() { - 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) { - Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); - scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); - - btTransform btFrameB; - G_TO_B(scaled_BFrame, btFrameB); - sliderConstraint = bulletnew(btSliderConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, true)); - - } else { - sliderConstraint = bulletnew(btSliderConstraint(*rbA->get_bt_rigid_body(), btFrameA, true)); - } - setup(sliderConstraint); -} - -const RigidBodyBullet *SliderJointBullet::getRigidBodyA() const { - return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyA().getUserPointer()); -} - -const RigidBodyBullet *SliderJointBullet::getRigidBodyB() const { - return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyB().getUserPointer()); -} - -const Transform3D SliderJointBullet::getCalculatedTransformA() const { - btTransform btTransform = sliderConstraint->getCalculatedTransformA(); - Transform3D gTrans; - B_TO_G(btTransform, gTrans); - return gTrans; -} - -const Transform3D SliderJointBullet::getCalculatedTransformB() const { - btTransform btTransform = sliderConstraint->getCalculatedTransformB(); - Transform3D gTrans; - B_TO_G(btTransform, gTrans); - return gTrans; -} - -const Transform3D SliderJointBullet::getFrameOffsetA() const { - btTransform btTransform = sliderConstraint->getFrameOffsetA(); - Transform3D gTrans; - B_TO_G(btTransform, gTrans); - return gTrans; -} - -const Transform3D SliderJointBullet::getFrameOffsetB() const { - btTransform btTransform = sliderConstraint->getFrameOffsetB(); - Transform3D gTrans; - B_TO_G(btTransform, gTrans); - return gTrans; -} - -Transform3D SliderJointBullet::getFrameOffsetA() { - btTransform btTransform = sliderConstraint->getFrameOffsetA(); - Transform3D gTrans; - B_TO_G(btTransform, gTrans); - return gTrans; -} - -Transform3D SliderJointBullet::getFrameOffsetB() { - btTransform btTransform = sliderConstraint->getFrameOffsetB(); - Transform3D gTrans; - B_TO_G(btTransform, gTrans); - return gTrans; -} - -real_t SliderJointBullet::getLowerLinLimit() const { - return sliderConstraint->getLowerLinLimit(); -} - -void SliderJointBullet::setLowerLinLimit(real_t lowerLimit) { - sliderConstraint->setLowerLinLimit(lowerLimit); -} - -real_t SliderJointBullet::getUpperLinLimit() const { - return sliderConstraint->getUpperLinLimit(); -} - -void SliderJointBullet::setUpperLinLimit(real_t upperLimit) { - sliderConstraint->setUpperLinLimit(upperLimit); -} - -real_t SliderJointBullet::getLowerAngLimit() const { - return sliderConstraint->getLowerAngLimit(); -} - -void SliderJointBullet::setLowerAngLimit(real_t lowerLimit) { - sliderConstraint->setLowerAngLimit(lowerLimit); -} - -real_t SliderJointBullet::getUpperAngLimit() const { - return sliderConstraint->getUpperAngLimit(); -} - -void SliderJointBullet::setUpperAngLimit(real_t upperLimit) { - sliderConstraint->setUpperAngLimit(upperLimit); -} - -real_t SliderJointBullet::getSoftnessDirLin() const { - return sliderConstraint->getSoftnessDirLin(); -} - -real_t SliderJointBullet::getRestitutionDirLin() const { - return sliderConstraint->getRestitutionDirLin(); -} - -real_t SliderJointBullet::getDampingDirLin() const { - return sliderConstraint->getDampingDirLin(); -} - -real_t SliderJointBullet::getSoftnessDirAng() const { - return sliderConstraint->getSoftnessDirAng(); -} - -real_t SliderJointBullet::getRestitutionDirAng() const { - return sliderConstraint->getRestitutionDirAng(); -} - -real_t SliderJointBullet::getDampingDirAng() const { - return sliderConstraint->getDampingDirAng(); -} - -real_t SliderJointBullet::getSoftnessLimLin() const { - return sliderConstraint->getSoftnessLimLin(); -} - -real_t SliderJointBullet::getRestitutionLimLin() const { - return sliderConstraint->getRestitutionLimLin(); -} - -real_t SliderJointBullet::getDampingLimLin() const { - return sliderConstraint->getDampingLimLin(); -} - -real_t SliderJointBullet::getSoftnessLimAng() const { - return sliderConstraint->getSoftnessLimAng(); -} - -real_t SliderJointBullet::getRestitutionLimAng() const { - return sliderConstraint->getRestitutionLimAng(); -} - -real_t SliderJointBullet::getDampingLimAng() const { - return sliderConstraint->getDampingLimAng(); -} - -real_t SliderJointBullet::getSoftnessOrthoLin() const { - return sliderConstraint->getSoftnessOrthoLin(); -} - -real_t SliderJointBullet::getRestitutionOrthoLin() const { - return sliderConstraint->getRestitutionOrthoLin(); -} - -real_t SliderJointBullet::getDampingOrthoLin() const { - return sliderConstraint->getDampingOrthoLin(); -} - -real_t SliderJointBullet::getSoftnessOrthoAng() const { - return sliderConstraint->getSoftnessOrthoAng(); -} - -real_t SliderJointBullet::getRestitutionOrthoAng() const { - return sliderConstraint->getRestitutionOrthoAng(); -} - -real_t SliderJointBullet::getDampingOrthoAng() const { - return sliderConstraint->getDampingOrthoAng(); -} - -void SliderJointBullet::setSoftnessDirLin(real_t softnessDirLin) { - sliderConstraint->setSoftnessDirLin(softnessDirLin); -} - -void SliderJointBullet::setRestitutionDirLin(real_t restitutionDirLin) { - sliderConstraint->setRestitutionDirLin(restitutionDirLin); -} - -void SliderJointBullet::setDampingDirLin(real_t dampingDirLin) { - sliderConstraint->setDampingDirLin(dampingDirLin); -} - -void SliderJointBullet::setSoftnessDirAng(real_t softnessDirAng) { - sliderConstraint->setSoftnessDirAng(softnessDirAng); -} - -void SliderJointBullet::setRestitutionDirAng(real_t restitutionDirAng) { - sliderConstraint->setRestitutionDirAng(restitutionDirAng); -} - -void SliderJointBullet::setDampingDirAng(real_t dampingDirAng) { - sliderConstraint->setDampingDirAng(dampingDirAng); -} - -void SliderJointBullet::setSoftnessLimLin(real_t softnessLimLin) { - sliderConstraint->setSoftnessLimLin(softnessLimLin); -} - -void SliderJointBullet::setRestitutionLimLin(real_t restitutionLimLin) { - sliderConstraint->setRestitutionLimLin(restitutionLimLin); -} - -void SliderJointBullet::setDampingLimLin(real_t dampingLimLin) { - sliderConstraint->setDampingLimLin(dampingLimLin); -} - -void SliderJointBullet::setSoftnessLimAng(real_t softnessLimAng) { - sliderConstraint->setSoftnessLimAng(softnessLimAng); -} - -void SliderJointBullet::setRestitutionLimAng(real_t restitutionLimAng) { - sliderConstraint->setRestitutionLimAng(restitutionLimAng); -} - -void SliderJointBullet::setDampingLimAng(real_t dampingLimAng) { - sliderConstraint->setDampingLimAng(dampingLimAng); -} - -void SliderJointBullet::setSoftnessOrthoLin(real_t softnessOrthoLin) { - sliderConstraint->setSoftnessOrthoLin(softnessOrthoLin); -} - -void SliderJointBullet::setRestitutionOrthoLin(real_t restitutionOrthoLin) { - sliderConstraint->setRestitutionOrthoLin(restitutionOrthoLin); -} - -void SliderJointBullet::setDampingOrthoLin(real_t dampingOrthoLin) { - sliderConstraint->setDampingOrthoLin(dampingOrthoLin); -} - -void SliderJointBullet::setSoftnessOrthoAng(real_t softnessOrthoAng) { - sliderConstraint->setSoftnessOrthoAng(softnessOrthoAng); -} - -void SliderJointBullet::setRestitutionOrthoAng(real_t restitutionOrthoAng) { - sliderConstraint->setRestitutionOrthoAng(restitutionOrthoAng); -} - -void SliderJointBullet::setDampingOrthoAng(real_t dampingOrthoAng) { - sliderConstraint->setDampingOrthoAng(dampingOrthoAng); -} - -void SliderJointBullet::setPoweredLinMotor(bool onOff) { - sliderConstraint->setPoweredLinMotor(onOff); -} - -bool SliderJointBullet::getPoweredLinMotor() { - return sliderConstraint->getPoweredLinMotor(); -} - -void SliderJointBullet::setTargetLinMotorVelocity(real_t targetLinMotorVelocity) { - sliderConstraint->setTargetLinMotorVelocity(targetLinMotorVelocity); -} - -real_t SliderJointBullet::getTargetLinMotorVelocity() { - return sliderConstraint->getTargetLinMotorVelocity(); -} - -void SliderJointBullet::setMaxLinMotorForce(real_t maxLinMotorForce) { - sliderConstraint->setMaxLinMotorForce(maxLinMotorForce); -} - -real_t SliderJointBullet::getMaxLinMotorForce() { - return sliderConstraint->getMaxLinMotorForce(); -} - -void SliderJointBullet::setPoweredAngMotor(bool onOff) { - sliderConstraint->setPoweredAngMotor(onOff); -} - -bool SliderJointBullet::getPoweredAngMotor() { - return sliderConstraint->getPoweredAngMotor(); -} - -void SliderJointBullet::setTargetAngMotorVelocity(real_t targetAngMotorVelocity) { - sliderConstraint->setTargetAngMotorVelocity(targetAngMotorVelocity); -} - -real_t SliderJointBullet::getTargetAngMotorVelocity() { - return sliderConstraint->getTargetAngMotorVelocity(); -} - -void SliderJointBullet::setMaxAngMotorForce(real_t maxAngMotorForce) { - sliderConstraint->setMaxAngMotorForce(maxAngMotorForce); -} - -real_t SliderJointBullet::getMaxAngMotorForce() { - return sliderConstraint->getMaxAngMotorForce(); -} - -real_t SliderJointBullet::getLinearPos() { - return sliderConstraint->getLinearPos(); - ; -} - -void SliderJointBullet::set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value) { - switch (p_param) { - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: - setUpperLinLimit(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: - setLowerLinLimit(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: - setSoftnessLimLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: - setRestitutionLimLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: - setDampingLimLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: - setSoftnessDirLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: - setRestitutionDirLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: - setDampingDirLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: - setSoftnessOrthoLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: - setRestitutionOrthoLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: - setDampingOrthoLin(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: - setUpperAngLimit(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: - setLowerAngLimit(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: - setSoftnessLimAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: - setRestitutionLimAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: - setDampingLimAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: - setSoftnessDirAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: - setRestitutionDirAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: - setDampingDirAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: - setSoftnessOrthoAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: - setRestitutionOrthoAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: - setDampingOrthoAng(p_value); - break; - case PhysicsServer3D::SLIDER_JOINT_MAX: - break; // Can't happen, but silences warning - } -} - -real_t SliderJointBullet::get_param(PhysicsServer3D::SliderJointParam p_param) const { - switch (p_param) { - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: - return getUpperLinLimit(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: - return getLowerLinLimit(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: - return getSoftnessLimLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: - return getRestitutionLimLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: - return getDampingLimLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: - return getSoftnessDirLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: - return getRestitutionDirLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: - return getDampingDirLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: - return getSoftnessOrthoLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: - return getRestitutionOrthoLin(); - case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: - return getDampingOrthoLin(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: - return getUpperAngLimit(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: - return getLowerAngLimit(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: - return getSoftnessLimAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: - return getRestitutionLimAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: - return getDampingLimAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: - return getSoftnessDirAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: - return getRestitutionDirAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: - return getDampingDirAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: - return getSoftnessOrthoAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: - return getRestitutionOrthoAng(); - case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: - return getDampingOrthoAng(); - default: - return 0; - } -} diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h deleted file mode 100644 index 0c93558449..0000000000 --- a/modules/bullet/slider_joint_bullet.h +++ /dev/null @@ -1,121 +0,0 @@ -/*************************************************************************/ -/* slider_joint_bullet.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 SLIDER_JOINT_BULLET_H -#define SLIDER_JOINT_BULLET_H - -#include "joint_bullet.h" - -/** - @author AndreaCatania -*/ - -class RigidBodyBullet; - -class SliderJointBullet : public JointBullet { - class btSliderConstraint *sliderConstraint; - -public: - /// Reference frame is A - 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 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; - void setUpperLinLimit(real_t upperLimit); - real_t getLowerAngLimit() const; - void setLowerAngLimit(real_t lowerLimit); - real_t getUpperAngLimit() const; - void setUpperAngLimit(real_t upperLimit); - - real_t getSoftnessDirLin() const; - real_t getRestitutionDirLin() const; - real_t getDampingDirLin() const; - real_t getSoftnessDirAng() const; - real_t getRestitutionDirAng() const; - real_t getDampingDirAng() const; - real_t getSoftnessLimLin() const; - real_t getRestitutionLimLin() const; - real_t getDampingLimLin() const; - real_t getSoftnessLimAng() const; - real_t getRestitutionLimAng() const; - real_t getDampingLimAng() const; - real_t getSoftnessOrthoLin() const; - real_t getRestitutionOrthoLin() const; - real_t getDampingOrthoLin() const; - real_t getSoftnessOrthoAng() const; - real_t getRestitutionOrthoAng() const; - real_t getDampingOrthoAng() const; - void setSoftnessDirLin(real_t softnessDirLin); - void setRestitutionDirLin(real_t restitutionDirLin); - void setDampingDirLin(real_t dampingDirLin); - void setSoftnessDirAng(real_t softnessDirAng); - void setRestitutionDirAng(real_t restitutionDirAng); - void setDampingDirAng(real_t dampingDirAng); - void setSoftnessLimLin(real_t softnessLimLin); - void setRestitutionLimLin(real_t restitutionLimLin); - void setDampingLimLin(real_t dampingLimLin); - void setSoftnessLimAng(real_t softnessLimAng); - void setRestitutionLimAng(real_t restitutionLimAng); - void setDampingLimAng(real_t dampingLimAng); - void setSoftnessOrthoLin(real_t softnessOrthoLin); - void setRestitutionOrthoLin(real_t restitutionOrthoLin); - void setDampingOrthoLin(real_t dampingOrthoLin); - void setSoftnessOrthoAng(real_t softnessOrthoAng); - void setRestitutionOrthoAng(real_t restitutionOrthoAng); - void setDampingOrthoAng(real_t dampingOrthoAng); - void setPoweredLinMotor(bool onOff); - bool getPoweredLinMotor(); - void setTargetLinMotorVelocity(real_t targetLinMotorVelocity); - real_t getTargetLinMotorVelocity(); - void setMaxLinMotorForce(real_t maxLinMotorForce); - real_t getMaxLinMotorForce(); - void setPoweredAngMotor(bool onOff); - bool getPoweredAngMotor(); - void setTargetAngMotorVelocity(real_t targetAngMotorVelocity); - real_t getTargetAngMotorVelocity(); - void setMaxAngMotorForce(real_t maxAngMotorForce); - real_t getMaxAngMotorForce(); - real_t getLinearPos(); - - void set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value); - real_t get_param(PhysicsServer3D::SliderJointParam p_param) const; -}; -#endif diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp deleted file mode 100644 index c0ffffa364..0000000000 --- a/modules/bullet/soft_body_bullet.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/*************************************************************************/ -/* soft_body_bullet.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 "soft_body_bullet.h" - -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "space_bullet.h" - -#include "servers/rendering_server.h" - -SoftBodyBullet::SoftBodyBullet() : - CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY) {} - -SoftBodyBullet::~SoftBodyBullet() { -} - -void SoftBodyBullet::reload_body() { - if (space) { - space->remove_soft_body(this); - space->add_soft_body(this); - } -} - -void SoftBodyBullet::set_space(SpaceBullet *p_space) { - if (space) { - isScratched = false; - space->remove_soft_body(this); - } - - space = p_space; - - if (space) { - space->add_soft_body(this); - } -} - -void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {} - -void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {} - -void SoftBodyBullet::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) { - if (!bt_soft_body) { - return; - } - - /// Update rendering server vertices - const btSoftBody::tNodeArray &nodes(bt_soft_body->m_nodes); - const int nodes_count = nodes.size(); - - const Vector<int> *vs_indices; - const void *vertex_position; - const void *vertex_normal; - - for (int vertex_index = 0; vertex_index < nodes_count; ++vertex_index) { - vertex_position = reinterpret_cast<const void *>(&nodes[vertex_index].m_x); - vertex_normal = reinterpret_cast<const void *>(&nodes[vertex_index].m_n); - - vs_indices = &indices_table[vertex_index]; - - const int vs_indices_size(vs_indices->size()); - for (int x = 0; x < vs_indices_size; ++x) { - p_rendering_server_handler->set_vertex((*vs_indices)[x], vertex_position); - p_rendering_server_handler->set_normal((*vs_indices)[x], vertex_normal); - } - } - - /// Generate AABB - btVector3 aabb_min; - btVector3 aabb_max; - bt_soft_body->getAabb(aabb_min, aabb_max); - - btVector3 size(aabb_max - aabb_min); - - AABB aabb; - B_TO_G(aabb_min, aabb.position); - B_TO_G(size, aabb.size); - - p_rendering_server_handler->set_aabb(aabb); -} - -void SoftBodyBullet::set_soft_mesh(RID p_mesh) { - destroy_soft_body(); - - soft_mesh = p_mesh; - - if (soft_mesh.is_null()) { - return; - } - - Array arrays = RenderingServer::get_singleton()->mesh_surface_get_arrays(soft_mesh, 0); - ERR_FAIL_COND(arrays.is_empty()); - - bool success = set_trimesh_body_shape(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]); - if (!success) { - destroy_soft_body(); - } -} - -void SoftBodyBullet::destroy_soft_body() { - soft_mesh = RID(); - - if (!bt_soft_body) { - return; - } - - if (space) { - /// Remove from world before deletion - space->remove_soft_body(this); - } - - destroyBulletCollisionObject(); - bt_soft_body = nullptr; -} - -void SoftBodyBullet::set_soft_transform(const Transform3D &p_transform) { - reset_all_node_positions(); - move_all_nodes(p_transform); -} - -AABB SoftBodyBullet::get_bounds() const { - if (!bt_soft_body) { - return AABB(); - } - - btVector3 aabb_min; - btVector3 aabb_max; - bt_soft_body->getAabb(aabb_min, aabb_max); - - btVector3 size(aabb_max - aabb_min); - - AABB aabb; - B_TO_G(aabb_min, aabb.position); - B_TO_G(size, aabb.size); - - return aabb; -} - -void SoftBodyBullet::move_all_nodes(const Transform3D &p_transform) { - if (!bt_soft_body) { - return; - } - btTransform bt_transf; - G_TO_B(p_transform, bt_transf); - bt_soft_body->transform(bt_transf); -} - -void SoftBodyBullet::set_node_position(int p_node_index, const Vector3 &p_global_position) { - btVector3 bt_pos; - G_TO_B(p_global_position, bt_pos); - set_node_position(p_node_index, bt_pos); -} - -void SoftBodyBullet::set_node_position(int p_node_index, const btVector3 &p_global_position) { - if (bt_soft_body) { - bt_soft_body->m_nodes[p_node_index].m_q = bt_soft_body->m_nodes[p_node_index].m_x; - bt_soft_body->m_nodes[p_node_index].m_x = p_global_position; - } -} - -void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) const { - if (bt_soft_body) { - B_TO_G(bt_soft_body->m_nodes[p_node_index].m_x, r_position); - } -} - -void SoftBodyBullet::set_node_mass(int p_node_index, btScalar p_mass) { - if (0 >= p_mass) { - pin_node(p_node_index); - } else { - unpin_node(p_node_index); - } - if (bt_soft_body) { - ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size()); - bt_soft_body->setMass(p_node_index, p_mass); - } -} - -btScalar SoftBodyBullet::get_node_mass(int p_node_index) const { - if (bt_soft_body) { - ERR_FAIL_INDEX_V(p_node_index, bt_soft_body->m_nodes.size(), 1); - return bt_soft_body->getMass(p_node_index); - } else { - return -1 == search_node_pinned(p_node_index) ? 1 : 0; - } -} - -void SoftBodyBullet::reset_all_node_mass() { - if (bt_soft_body) { - for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { - bt_soft_body->setMass(pinned_nodes[i], 1); - } - } - pinned_nodes.resize(0); -} - -void SoftBodyBullet::reset_all_node_positions() { - if (soft_mesh.is_null()) { - return; - } - - Array arrays = soft_mesh->surface_get_arrays(0); - Vector<Vector3> vs_vertices(arrays[RS::ARRAY_VERTEX]); - const Vector3 *vs_vertices_read = vs_vertices.ptr(); - - for (int vertex_index = bt_soft_body->m_nodes.size() - 1; 0 <= vertex_index; --vertex_index) { - G_TO_B(vs_vertices_read[indices_table[vertex_index][0]], bt_soft_body->m_nodes[vertex_index].m_x); - - bt_soft_body->m_nodes[vertex_index].m_q = bt_soft_body->m_nodes[vertex_index].m_x; - bt_soft_body->m_nodes[vertex_index].m_v = btVector3(0, 0, 0); - bt_soft_body->m_nodes[vertex_index].m_f = btVector3(0, 0, 0); - } -} - -void SoftBodyBullet::set_activation_state(bool p_active) { - if (p_active) { - bt_soft_body->setActivationState(ACTIVE_TAG); - } else { - bt_soft_body->setActivationState(WANTS_DEACTIVATION); - } -} - -void SoftBodyBullet::set_total_mass(real_t p_val) { - if (0 >= p_val) { - p_val = 1; - } - total_mass = p_val; - if (bt_soft_body) { - bt_soft_body->setTotalMass(total_mass); - } -} - -void SoftBodyBullet::set_linear_stiffness(real_t p_val) { - linear_stiffness = p_val; - if (bt_soft_body) { - mat0->m_kLST = linear_stiffness; - } -} - -void SoftBodyBullet::set_simulation_precision(int p_val) { - simulation_precision = p_val; - if (bt_soft_body) { - bt_soft_body->m_cfg.piterations = simulation_precision; - bt_soft_body->m_cfg.viterations = simulation_precision; - bt_soft_body->m_cfg.diterations = simulation_precision; - bt_soft_body->m_cfg.citerations = simulation_precision; - } -} - -void SoftBodyBullet::set_pressure_coefficient(real_t p_val) { - pressure_coefficient = p_val; - if (bt_soft_body) { - bt_soft_body->m_cfg.kPR = pressure_coefficient; - } -} - -void SoftBodyBullet::set_damping_coefficient(real_t p_val) { - damping_coefficient = p_val; - if (bt_soft_body) { - bt_soft_body->m_cfg.kDP = damping_coefficient; - } -} - -void SoftBodyBullet::set_drag_coefficient(real_t p_val) { - drag_coefficient = p_val; - if (bt_soft_body) { - bt_soft_body->m_cfg.kDG = drag_coefficient; - } -} - -bool SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector3> p_vertices) { - ERR_FAIL_COND_V(p_indices.is_empty(), false); - ERR_FAIL_COND_V(p_vertices.is_empty(), false); - - /// Parse rendering server indices to physical indices. - /// Merge all overlapping vertices and create a map of physical vertices to rendering server - - { - /// This is the map of rendering server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map - Vector<int> vs_indices_to_physics_table; - - { // Map vertices - indices_table.resize(0); - - int index = 0; - Map<Vector3, int> unique_vertices; - - const int vs_vertices_size(p_vertices.size()); - - const Vector3 *p_vertices_read = p_vertices.ptr(); - - for (int vs_vertex_index = 0; vs_vertex_index < vs_vertices_size; ++vs_vertex_index) { - Map<Vector3, int>::Element *e = unique_vertices.find(p_vertices_read[vs_vertex_index]); - int vertex_id; - if (e) { - // Already existing - vertex_id = e->value(); - } else { - // Create new one - unique_vertices[p_vertices_read[vs_vertex_index]] = vertex_id = index++; - indices_table.push_back(Vector<int>()); - } - - indices_table.write[vertex_id].push_back(vs_vertex_index); - vs_indices_to_physics_table.push_back(vertex_id); - } - } - - const int indices_map_size(indices_table.size()); - - Vector<btScalar> bt_vertices; - - { // Parse vertices to bullet - - bt_vertices.resize(indices_map_size * 3); - const Vector3 *p_vertices_read = p_vertices.ptr(); - - for (int i = 0; i < indices_map_size; ++i) { - bt_vertices.write[3 * i + 0] = p_vertices_read[indices_table[i][0]].x; - bt_vertices.write[3 * i + 1] = p_vertices_read[indices_table[i][0]].y; - bt_vertices.write[3 * i + 2] = p_vertices_read[indices_table[i][0]].z; - } - } - - Vector<int> bt_triangles; - const int triangles_size(p_indices.size() / 3); - - { // Parse indices - - bt_triangles.resize(triangles_size * 3); - - const int *p_indices_read = p_indices.ptr(); - - for (int i = 0; i < triangles_size; ++i) { - bt_triangles.write[3 * i + 0] = vs_indices_to_physics_table[p_indices_read[3 * i + 2]]; - bt_triangles.write[3 * i + 1] = vs_indices_to_physics_table[p_indices_read[3 * i + 1]]; - bt_triangles.write[3 * i + 2] = vs_indices_to_physics_table[p_indices_read[3 * i + 0]]; - } - } - - btSoftBodyWorldInfo fake_world_info; - bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(fake_world_info, &bt_vertices[0], &bt_triangles[0], triangles_size, false); - setup_soft_body(); - } - - return true; -} - -void SoftBodyBullet::setup_soft_body() { - if (!bt_soft_body) { - return; - } - - // Soft body setup - setupBulletCollisionObject(bt_soft_body); - bt_soft_body->m_worldInfo = nullptr; // Remove fake world info - bt_soft_body->getCollisionShape()->setMargin(0.01); - bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT))); - - // Space setup - if (space) { - space->add_soft_body(this); - } - - mat0 = bt_soft_body->appendMaterial(); - - // Assign soft body data - bt_soft_body->generateBendingConstraints(2, mat0); - - mat0->m_kLST = linear_stiffness; - - // Clusters allow to have Soft vs Soft collision but doesn't work well right now - - //bt_soft_body->m_cfg.kSRHR_CL = 1;// Soft vs rigid hardness [0,1] (cluster only) - //bt_soft_body->m_cfg.kSKHR_CL = 1;// Soft vs kinematic hardness [0,1] (cluster only) - //bt_soft_body->m_cfg.kSSHR_CL = 1;// Soft vs soft hardness [0,1] (cluster only) - //bt_soft_body->m_cfg.kSR_SPLT_CL = 1; // Soft vs rigid impulse split [0,1] (cluster only) - //bt_soft_body->m_cfg.kSK_SPLT_CL = 1; // Soft vs kinematic impulse split [0,1] (cluster only) - //bt_soft_body->m_cfg.kSS_SPLT_CL = 1; // Soft vs Soft impulse split [0,1] (cluster only) - //bt_soft_body->m_cfg.collisions = btSoftBody::fCollision::CL_SS + btSoftBody::fCollision::CL_RS + btSoftBody::fCollision::VF_SS; - //bt_soft_body->generateClusters(64); - - bt_soft_body->m_cfg.piterations = simulation_precision; - bt_soft_body->m_cfg.viterations = simulation_precision; - bt_soft_body->m_cfg.diterations = simulation_precision; - bt_soft_body->m_cfg.citerations = simulation_precision; - bt_soft_body->m_cfg.kDP = damping_coefficient; - bt_soft_body->m_cfg.kDG = drag_coefficient; - bt_soft_body->m_cfg.kPR = pressure_coefficient; - bt_soft_body->setTotalMass(total_mass); - - btSoftBodyHelpers::ReoptimizeLinkOrder(bt_soft_body); - bt_soft_body->updateBounds(); - - // Set pinned nodes - for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { - const int node_index = pinned_nodes[i]; - ERR_CONTINUE(0 > node_index || bt_soft_body->m_nodes.size() <= node_index); - bt_soft_body->setMass(node_index, 0); - } -} - -void SoftBodyBullet::pin_node(int p_node_index) { - if (bt_soft_body) { - ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size()); - } - if (-1 == search_node_pinned(p_node_index)) { - pinned_nodes.push_back(p_node_index); - } -} - -void SoftBodyBullet::unpin_node(int p_node_index) { - if (bt_soft_body) { - ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size()); - } - const int id = search_node_pinned(p_node_index); - if (-1 != id) { - pinned_nodes.remove_at(id); - } -} - -int SoftBodyBullet::search_node_pinned(int p_node_index) const { - for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { - if (p_node_index == pinned_nodes[i]) { - return i; - } - } - return -1; -} diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h deleted file mode 100644 index 84da56ae69..0000000000 --- a/modules/bullet/soft_body_bullet.h +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************/ -/* soft_body_bullet.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 SOFT_BODY_BULLET_H -#define SOFT_BODY_BULLET_H - -#include "collision_object_bullet.h" - -#ifdef None -/// This is required to remove the macro None defined by x11 compiler because this word "None" is used internally by Bullet -#undef None -#define x11_None 0L -#endif - -#include "BulletSoftBody/btSoftBodyHelpers.h" -#include "collision_object_bullet.h" -#include "servers/physics_server_3d.h" - -#ifdef x11_None -/// This is required to re add the macro None defined by x11 compiler -#undef x11_None -#define None 0L -#endif - -/** - @author AndreaCatania -*/ - -class RenderingServerHandler; - -class SoftBodyBullet : public CollisionObjectBullet { -private: - btSoftBody *bt_soft_body = nullptr; - Vector<Vector<int>> indices_table; - btSoftBody::Material *mat0 = nullptr; // This is just a copy of pointer managed by btSoftBody - bool isScratched = false; - - RID soft_mesh; - - int simulation_precision = 5; - real_t total_mass = 1.; - real_t linear_stiffness = 0.5; // [0,1] - real_t pressure_coefficient = 0.; // [-inf,+inf] - real_t damping_coefficient = 0.01; // [0,1] - real_t drag_coefficient = 0.; // [0,1] - Vector<int> pinned_nodes; - - // Other property to add - //btScalar kVC; // Volume conversation coefficient [0,+inf] - //btScalar kDF; // Dynamic friction coefficient [0,1] - //btScalar kMT; // Pose matching coefficient [0,1] - //btScalar kCHR; // Rigid contacts hardness [0,1] - //btScalar kKHR; // Kinetic contacts hardness [0,1] - //btScalar kSHR; // Soft contacts hardness [0,1] - -public: - SoftBodyBullet(); - ~SoftBodyBullet(); - - virtual void reload_body(); - virtual void set_space(SpaceBullet *p_space); - - virtual void dispatch_callbacks() {} - virtual void on_collision_filters_change() {} - virtual void on_collision_checker_start() {} - virtual void on_collision_checker_end() {} - virtual void on_enter_area(AreaBullet *p_area); - virtual void on_exit_area(AreaBullet *p_area); - - _FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; } - - void update_rendering_server(RenderingServerHandler *p_rendering_server_handler); - - void set_soft_mesh(RID p_mesh); - void destroy_soft_body(); - - // Special function. This function has bad performance - void set_soft_transform(const Transform3D &p_transform); - - AABB get_bounds() const; - - 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; - - void set_node_mass(int node_index, btScalar p_mass); - btScalar get_node_mass(int node_index) const; - void reset_all_node_mass(); - void reset_all_node_positions(); - - void set_activation_state(bool p_active); - - void set_total_mass(real_t p_val); - _FORCE_INLINE_ real_t get_total_mass() const { return total_mass; } - - void set_linear_stiffness(real_t p_val); - _FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; } - - void set_simulation_precision(int p_val); - _FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; } - - void set_pressure_coefficient(real_t p_val); - _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; } - - void set_damping_coefficient(real_t p_val); - _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; } - - void set_drag_coefficient(real_t p_val); - _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; } - -private: - bool set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector3> p_vertices); - void setup_soft_body(); - - void pin_node(int p_node_index); - void unpin_node(int p_node_index); - int search_node_pinned(int p_node_index) const; -}; - -#endif // SOFT_BODY_BULLET_H diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp deleted file mode 100644 index 0c7e5eccf0..0000000000 --- a/modules/bullet/space_bullet.cpp +++ /dev/null @@ -1,1440 +0,0 @@ -/*************************************************************************/ -/* space_bullet.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 "space_bullet.h" - -#include "bullet_physics_server.h" -#include "bullet_types_converter.h" -#include "bullet_utilities.h" -#include "constraint_bullet.h" -#include "core/config/project_settings.h" -#include "core/string/ustring.h" -#include "godot_collision_configuration.h" -#include "godot_collision_dispatcher.h" -#include "rigid_body_bullet.h" -#include "servers/physics_server_3d.h" -#include "soft_body_bullet.h" - -#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h> -#include <BulletCollision/CollisionDispatch/btCollisionObject.h> -#include <BulletCollision/CollisionDispatch/btGhostObject.h> -#include <BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h> -#include <BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h> -#include <BulletCollision/NarrowPhaseCollision/btPointCollector.h> -#include <BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h> -#include <BulletSoftBody/btSoftRigidDynamicsWorld.h> -#include <btBulletDynamicsCommon.h> - -#include <assert.h> - -/** - @author AndreaCatania -*/ - -BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_space) : - PhysicsDirectSpaceState3D(), - space(p_space) {} - -int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, 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; - } - - btVector3 bt_point; - G_TO_B(p_point, bt_point); - - btSphereShape sphere_point(0.001f); - btCollisionObject collision_object_point; - collision_object_point.setCollisionShape(&sphere_point); - collision_object_point.setWorldTransform(btTransform(btQuaternion::getIdentity(), bt_point)); - - // Setup query - GodotAllContactResultCallback btResult(&collision_object_point, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas); - btResult.m_collisionFilterGroup = 0; - btResult.m_collisionFilterMask = p_collision_mask; - space->dynamicsWorld->contactTest(&collision_object_point, btResult); - - // The results are already populated by GodotAllConvexResultCallback - return btResult.m_count; -} - -bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_ray) { - btVector3 btVec_from; - btVector3 btVec_to; - - G_TO_B(p_from, btVec_from); - G_TO_B(p_to, btVec_to); - - // setup query - GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude, p_collide_with_bodies, p_collide_with_areas); - btResult.m_collisionFilterGroup = 0; - btResult.m_collisionFilterMask = p_collision_mask; - btResult.m_pickRay = p_pick_ray; - - space->dynamicsWorld->rayTest(btVec_from, btVec_to, btResult); - if (btResult.hasHit()) { - B_TO_G(btResult.m_hitPointWorld, r_result.position); - B_TO_G(btResult.m_hitNormalWorld.normalize(), r_result.normal); - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btResult.m_collisionObject->getUserPointer()); - if (gObj) { - r_result.shape = btResult.m_shapeId; - r_result.rid = gObj->get_self(); - r_result.collider_id = gObj->get_instance_id(); - r_result.collider = r_result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(r_result.collider_id); - } else { - WARN_PRINT("The raycast performed has hit a collision object that is not part of Godot scene, please check it."); - } - return true; - } else { - return false; - } -} - -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; - } - - ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, 0); - - btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale_abs(), p_margin); - if (!btShape->isConvex()) { - bulletdelete(btShape); - ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); - return 0; - } - btConvexShape *btConvex = static_cast<btConvexShape *>(btShape); - - btTransform bt_xform; - G_TO_B(p_xform, bt_xform); - UNSCALE_BT_BASIS(bt_xform); - - btCollisionObject collision_object; - collision_object.setCollisionShape(btConvex); - collision_object.setWorldTransform(bt_xform); - - GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas); - btQuery.m_collisionFilterGroup = 0; - btQuery.m_collisionFilterMask = p_collision_mask; - btQuery.m_closestDistanceThreshold = 0; - space->dynamicsWorld->contactTest(&collision_object, btQuery); - - bulletdelete(btConvex); - - return btQuery.m_count; -} - -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; - G_TO_B(p_motion, bt_motion); - - ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, false); - - btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin); - if (!btShape->isConvex()) { - bulletdelete(btShape); - ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); - return false; - } - btConvexShape *bt_convex_shape = static_cast<btConvexShape *>(btShape); - - btTransform bt_xform_from; - G_TO_B(p_xform, bt_xform_from); - UNSCALE_BT_BASIS(bt_xform_from); - - btTransform bt_xform_to(bt_xform_from); - bt_xform_to.getOrigin() += bt_motion; - - if ((bt_xform_to.getOrigin() - bt_xform_from.getOrigin()).fuzzyZero()) { - r_closest_safe = 1.0f; - r_closest_unsafe = 1.0f; - bulletdelete(btShape); - return true; - } - - GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude, p_collide_with_bodies, p_collide_with_areas); - btResult.m_collisionFilterGroup = 0; - btResult.m_collisionFilterMask = p_collision_mask; - - space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult, space->dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration); - - if (btResult.hasHit()) { - const btScalar l = bt_motion.length(); - r_closest_unsafe = btResult.m_closestHitFraction; - r_closest_safe = MAX(r_closest_unsafe - (1 - ((l - 0.01) / l)), 0); - if (r_info) { - if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { - B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); - } - CollisionObjectBullet *collision_object = static_cast<CollisionObjectBullet *>(btResult.m_hitCollisionObject->getUserPointer()); - B_TO_G(btResult.m_hitPointWorld, r_info->point); - B_TO_G(btResult.m_hitNormalWorld, r_info->normal); - r_info->rid = collision_object->get_self(); - r_info->collider_id = collision_object->get_instance_id(); - r_info->shape = btResult.m_shapeId; - } - } else { - r_closest_safe = 1.0f; - r_closest_unsafe = 1.0f; - } - - bulletdelete(bt_convex_shape); - return true; // Mean success -} - -/// Returns the list of contacts pairs in this order: Local contact, other body contact -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; - } - - ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, false); - - btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin); - if (!btShape->isConvex()) { - bulletdelete(btShape); - ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); - return false; - } - btConvexShape *btConvex = static_cast<btConvexShape *>(btShape); - - btTransform bt_xform; - G_TO_B(p_shape_xform, bt_xform); - UNSCALE_BT_BASIS(bt_xform); - - btCollisionObject collision_object; - collision_object.setCollisionShape(btConvex); - collision_object.setWorldTransform(bt_xform); - - GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas); - btQuery.m_collisionFilterGroup = 0; - btQuery.m_collisionFilterMask = p_collision_mask; - btQuery.m_closestDistanceThreshold = 0; - space->dynamicsWorld->contactTest(&collision_object, btQuery); - - r_result_count = btQuery.m_count; - bulletdelete(btConvex); - - return btQuery.m_count; -} - -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()->get_or_null(p_shape); - ERR_FAIL_COND_V(!shape, false); - - btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin); - if (!btShape->isConvex()) { - bulletdelete(btShape); - ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); - return false; - } - btConvexShape *btConvex = static_cast<btConvexShape *>(btShape); - - btTransform bt_xform; - G_TO_B(p_shape_xform, bt_xform); - UNSCALE_BT_BASIS(bt_xform); - - btCollisionObject collision_object; - collision_object.setCollisionShape(btConvex); - collision_object.setWorldTransform(bt_xform); - - GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude, p_collide_with_bodies, p_collide_with_areas); - btQuery.m_collisionFilterGroup = 0; - btQuery.m_collisionFilterMask = p_collision_mask; - btQuery.m_closestDistanceThreshold = 0; - space->dynamicsWorld->contactTest(&collision_object, btQuery); - - bulletdelete(btConvex); - - if (btQuery.m_collided) { - if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) { - B_TO_G(static_cast<const btRigidBody *>(btQuery.m_rest_info_collision_object)->getVelocityInLocalPoint(btQuery.m_rest_info_bt_point), r_info->linear_velocity); - } - B_TO_G(btQuery.m_rest_info_bt_point, r_info->point); - } - - return btQuery.m_collided; -} - -Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const { - RigidCollisionObjectBullet *rigid_object = space->get_physics_server()->get_rigid_collision_object(p_object); - ERR_FAIL_COND_V(!rigid_object, Vector3()); - - btVector3 out_closest_point(0, 0, 0); - btScalar out_distance = 1e20; - - btVector3 bt_point; - G_TO_B(p_point, bt_point); - - btSphereShape point_shape(0.); - - btCollisionShape *shape; - btConvexShape *convex_shape; - btTransform child_transform; - btTransform body_transform(rigid_object->get_bt_collision_object()->getWorldTransform()); - - btGjkPairDetector::ClosestPointInput input; - input.m_transformA.getBasis().setIdentity(); - input.m_transformA.setOrigin(bt_point); - - bool shapes_found = false; - - for (int i = rigid_object->get_shape_count() - 1; 0 <= i; --i) { - shape = rigid_object->get_bt_shape(i); - if (shape->isConvex()) { - child_transform = rigid_object->get_bt_shape_transform(i); - convex_shape = static_cast<btConvexShape *>(shape); - - input.m_transformB = body_transform * child_transform; - - btPointCollector result; - btGjkPairDetector gjk_pair_detector(&point_shape, convex_shape, space->gjk_simplex_solver, space->gjk_epa_pen_solver); - gjk_pair_detector.getClosestPoints(input, result, nullptr); - - if (out_distance > result.m_distance) { - out_distance = result.m_distance; - out_closest_point = result.m_pointInWorld; - } - } - shapes_found = true; - } - - if (shapes_found) { - Vector3 out; - B_TO_G(out_closest_point, out); - return out; - } else { - // no shapes found, use distance to origin. - return rigid_object->get_transform().get_origin(); - } -} - -SpaceBullet::SpaceBullet() { - create_empty_world(GLOBAL_DEF("physics/3d/active_soft_world", true)); - direct_access = memnew(BulletPhysicsDirectSpaceState(this)); -} - -SpaceBullet::~SpaceBullet() { - memdelete(direct_access); - destroy_world(); -} - -void SpaceBullet::flush_queries() { - const btCollisionObjectArray &colObjArray = dynamicsWorld->getCollisionObjectArray(); - for (int i = colObjArray.size() - 1; 0 <= i; --i) { - static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->dispatch_callbacks(); - } -} - -void SpaceBullet::step(real_t p_delta_time) { - delta_time = p_delta_time; - dynamicsWorld->stepSimulation(p_delta_time, 0, 0); -} - -void SpaceBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) { - assert(dynamicsWorld); - - switch (p_param) { - case PhysicsServer3D::AREA_PARAM_GRAVITY: - gravityMagnitude = p_value; - update_gravity(); - break; - case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: - gravityDirection = p_value; - update_gravity(); - break; - case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: - linear_damp = p_value; - break; - case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: - angular_damp = p_value; - break; - case PhysicsServer3D::AREA_PARAM_PRIORITY: - // Priority is always 0, the lower - break; - case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: - case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: - case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: - break; - default: - WARN_PRINT("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it."); - break; - } -} - -Variant SpaceBullet::get_param(PhysicsServer3D::AreaParameter p_param) { - switch (p_param) { - case PhysicsServer3D::AREA_PARAM_GRAVITY: - return gravityMagnitude; - case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: - return gravityDirection; - case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: - return linear_damp; - case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: - return angular_damp; - case PhysicsServer3D::AREA_PARAM_PRIORITY: - return 0; // Priority is always 0, the lower - case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: - return false; - case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: - return 0; - case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: - return 0; - default: - WARN_PRINT("This get parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it."); - return Variant(); - } -} - -void SpaceBullet::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value) { - switch (p_param) { - case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: - case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: - case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: - case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: - case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: - case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: - default: - WARN_PRINT("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it."); - break; - } -} - -real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) { - switch (p_param) { - case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: - case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: - case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: - case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: - case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: - case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: - default: - WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned."); - return 0.f; - } -} - -void SpaceBullet::add_area(AreaBullet *p_area) { - areas.push_back(p_area); - dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask()); -} - -void SpaceBullet::remove_area(AreaBullet *p_area) { - areas.erase(p_area); - dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost()); -} - -void SpaceBullet::reload_collision_filters(AreaBullet *p_area) { - btGhostObject *ghost_object = p_area->get_bt_ghost(); - - btBroadphaseProxy *ghost_proxy = ghost_object->getBroadphaseHandle(); - ghost_proxy->m_collisionFilterGroup = p_area->get_collision_layer(); - ghost_proxy->m_collisionFilterMask = p_area->get_collision_mask(); - - dynamicsWorld->refreshBroadphaseProxy(ghost_object); -} - -void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) { - if (p_body->is_static()) { - dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); - } else { - dynamicsWorld->addRigidBody(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); - p_body->scratch_space_override_modificator(); - } -} - -void SpaceBullet::remove_rigid_body_constraints(RigidBodyBullet *p_body) { - btRigidBody *btBody = p_body->get_bt_rigid_body(); - - int constraints = btBody->getNumConstraintRefs(); - if (constraints > 0) { - ERR_PRINT("A body connected to joints was removed."); - for (int i = 0; i < constraints; i++) { - dynamicsWorld->removeConstraint(btBody->getConstraintRef(i)); - } - } -} - -void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) { - btRigidBody *btBody = p_body->get_bt_rigid_body(); - - if (p_body->is_static()) { - dynamicsWorld->removeCollisionObject(btBody); - } else { - dynamicsWorld->removeRigidBody(btBody); - } -} - -void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) { - btRigidBody *rigid_body = p_body->get_bt_rigid_body(); - - btBroadphaseProxy *body_proxy = rigid_body->getBroadphaseProxy(); - body_proxy->m_collisionFilterGroup = p_body->get_collision_layer(); - body_proxy->m_collisionFilterMask = p_body->get_collision_mask(); - - dynamicsWorld->refreshBroadphaseProxy(rigid_body); -} - -void SpaceBullet::add_soft_body(SoftBodyBullet *p_body) { - if (is_using_soft_world()) { - if (p_body->get_bt_soft_body()) { - p_body->get_bt_soft_body()->m_worldInfo = get_soft_body_world_info(); - static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->addSoftBody(p_body->get_bt_soft_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); - } - } else { - ERR_PRINT("This soft body can't be added to non soft world"); - } -} - -void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) { - if (is_using_soft_world()) { - if (p_body->get_bt_soft_body()) { - static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body()); - p_body->get_bt_soft_body()->m_worldInfo = nullptr; - } - } -} - -void SpaceBullet::reload_collision_filters(SoftBodyBullet *p_body) { - // This is necessary to change collision filter - remove_soft_body(p_body); - add_soft_body(p_body); -} - -void SpaceBullet::add_constraint(ConstraintBullet *p_constraint, bool disableCollisionsBetweenLinkedBodies) { - p_constraint->set_space(this); - dynamicsWorld->addConstraint(p_constraint->get_bt_constraint(), disableCollisionsBetweenLinkedBodies); -} - -void SpaceBullet::remove_constraint(ConstraintBullet *p_constraint) { - dynamicsWorld->removeConstraint(p_constraint->get_bt_constraint()); -} - -int SpaceBullet::get_num_collision_objects() const { - return dynamicsWorld->getNumCollisionObjects(); -} - -void SpaceBullet::remove_all_collision_objects() { - for (int i = dynamicsWorld->getNumCollisionObjects() - 1; 0 <= i; --i) { - btCollisionObject *btObj = dynamicsWorld->getCollisionObjectArray()[i]; - CollisionObjectBullet *colObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - colObj->set_space(nullptr); - } -} - -void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { - const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray(); - - // Notify all Collision objects the collision checker is started - for (int i = colObjArray.size() - 1; 0 <= i; --i) { - static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->on_collision_checker_start(); - } - - SpaceBullet *sb = static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo()); - sb->check_ghost_overlaps(); - sb->check_body_collision(); - - for (int i = colObjArray.size() - 1; 0 <= i; --i) { - static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->on_collision_checker_end(); - } -} - -BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { - return direct_access; -} - -btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) { - return CLAMP(body0->getRestitution() + body1->getRestitution(), 0, 1); -} - -btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) { - return ABS(MIN(body0->getFriction(), body1->getFriction())); -} - -void SpaceBullet::create_empty_world(bool p_create_soft_world) { - gjk_epa_pen_solver = bulletnew(btGjkEpaPenetrationDepthSolver); - gjk_simplex_solver = bulletnew(btVoronoiSimplexSolver); - - void *world_mem; - if (p_create_soft_world) { - world_mem = malloc(sizeof(btSoftRigidDynamicsWorld)); - } else { - world_mem = malloc(sizeof(btDiscreteDynamicsWorld)); - } - - ERR_FAIL_COND_MSG(!world_mem, "Out of memory."); - - if (p_create_soft_world) { - collisionConfiguration = bulletnew(GodotSoftCollisionConfiguration(static_cast<btDiscreteDynamicsWorld *>(world_mem))); - } else { - collisionConfiguration = bulletnew(GodotCollisionConfiguration(static_cast<btDiscreteDynamicsWorld *>(world_mem))); - } - - dispatcher = bulletnew(GodotCollisionDispatcher(collisionConfiguration)); - broadphase = bulletnew(btDbvtBroadphase); - solver = bulletnew(btSequentialImpulseConstraintSolver); - - if (p_create_soft_world) { - dynamicsWorld = new (world_mem) btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); - soft_body_world_info = bulletnew(btSoftBodyWorldInfo); - } else { - dynamicsWorld = new (world_mem) btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); - } - - ghostPairCallback = bulletnew(btGhostPairCallback); - godotFilterCallback = bulletnew(GodotFilterCallback); - gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution; - gCalculateCombinedFrictionCallback = &calculateGodotCombinedFriction; - gContactAddedCallback = &godotContactAddedCallback; - - dynamicsWorld->setWorldUserInfo(this); - - dynamicsWorld->setInternalTickCallback(onBulletTickCallback, this, false); - dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(ghostPairCallback); // Setup ghost check - dynamicsWorld->getPairCache()->setOverlapFilterCallback(godotFilterCallback); - - if (soft_body_world_info) { - soft_body_world_info->m_broadphase = broadphase; - soft_body_world_info->m_dispatcher = dispatcher; - soft_body_world_info->m_sparsesdf.Initialize(); - } - - update_gravity(); -} - -void SpaceBullet::destroy_world() { - /// The world elements (like: Collision Objects, Constraints, Shapes) are managed by godot - - dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(nullptr); - dynamicsWorld->getPairCache()->setOverlapFilterCallback(nullptr); - - bulletdelete(ghostPairCallback); - bulletdelete(godotFilterCallback); - - // Deallocate world - dynamicsWorld->~btDiscreteDynamicsWorld(); - free(dynamicsWorld); - dynamicsWorld = nullptr; - - bulletdelete(solver); - bulletdelete(broadphase); - bulletdelete(dispatcher); - bulletdelete(collisionConfiguration); - bulletdelete(soft_body_world_info); - bulletdelete(gjk_simplex_solver); - bulletdelete(gjk_epa_pen_solver); -} - -void SpaceBullet::check_ghost_overlaps() { - // For each area - for (int area_idx = 0; area_idx < areas.size(); area_idx++) { - AreaBullet *area = areas[area_idx]; - if (!area->is_monitoring()) { - continue; - } - - btGhostObject *bt_ghost = area->get_bt_ghost(); - const btTransform &area_transform = area->get_transform__bullet(); - const btVector3 &area_scale(area->get_bt_body_scale()); - - // Mark all current overlapping shapes dirty. - area->mark_all_overlaps_dirty(); - - // Broadphase - const btAlignedObjectArray<btCollisionObject *> overlapping_pairs = bt_ghost->getOverlappingPairs(); - // Narrowphase - for (int pair_idx = 0; pair_idx < overlapping_pairs.size(); pair_idx++) { - btCollisionObject *other_bt_collision_object = overlapping_pairs[pair_idx]; - RigidCollisionObjectBullet *other_object = static_cast<RigidCollisionObjectBullet *>(other_bt_collision_object->getUserPointer()); - const btTransform &other_transform = other_object->get_transform__bullet(); - const btVector3 &other_scale(other_object->get_bt_body_scale()); - - if (!area->is_updated() && !other_object->is_updated()) { - area->mark_object_overlaps_inside(other_object); - continue; - } - - if (other_bt_collision_object->getUserIndex() == CollisionObjectBullet::TYPE_AREA) { - if (!static_cast<AreaBullet *>(other_bt_collision_object->getUserPointer())->is_monitorable()) { - continue; - } - } else if (other_bt_collision_object->getUserIndex() != CollisionObjectBullet::TYPE_RIGID_BODY) { - continue; - } - - // For each area shape - for (int our_shape_id = 0; our_shape_id < area->get_shape_count(); our_shape_id++) { - btCollisionShape *area_shape = area->get_bt_shape(our_shape_id); - if (!area_shape->isConvex()) { - continue; - } - btConvexShape *area_convex_shape = static_cast<btConvexShape *>(area_shape); - - btTransform area_shape_transform(area->get_bt_shape_transform(our_shape_id)); - area_shape_transform.getOrigin() *= area_scale; - btGjkPairDetector::ClosestPointInput gjk_input; - gjk_input.m_transformA = area_transform * area_shape_transform; - - // For each other object shape - for (int other_shape_id = 0; other_shape_id < other_object->get_shape_count(); other_shape_id++) { - btCollisionShape *other_shape = other_object->get_bt_shape(other_shape_id); - btTransform other_shape_transform(other_object->get_bt_shape_transform(other_shape_id)); - other_shape_transform.getOrigin() *= other_scale; - gjk_input.m_transformB = other_transform * other_shape_transform; - - if (other_shape->isConvex()) { - btPointCollector result; - btGjkPairDetector gjk_pair_detector( - area_convex_shape, - static_cast<btConvexShape *>(other_shape), - gjk_simplex_solver, - gjk_epa_pen_solver); - - gjk_pair_detector.getClosestPoints(gjk_input, result, nullptr); - if (result.m_distance <= 0) { - area->set_overlap(other_object, other_shape_id, our_shape_id); - } - } else { // Other shape is not convex. - btCollisionObjectWrapper obA(nullptr, area_convex_shape, bt_ghost, gjk_input.m_transformA, -1, our_shape_id); - btCollisionObjectWrapper obB(nullptr, other_shape, other_bt_collision_object, gjk_input.m_transformB, -1, other_shape_id); - btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, nullptr, BT_CONTACT_POINT_ALGORITHMS); - - if (!algorithm) { - continue; - } - - GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB); - algorithm->processCollision(&obA, &obB, dynamicsWorld->getDispatchInfo(), &contactPointResult); - algorithm->~btCollisionAlgorithm(); - dispatcher->freeCollisionAlgorithm(algorithm); - - if (contactPointResult.hasHit()) { - area->set_overlap(other_object, our_shape_id, other_shape_id); - } - } - } // End for each other object shape - } // End for each area shape - } // End for each overlapping pair - - // All overlapping shapes still marked dirty must have exited. - area->mark_all_dirty_overlaps_as_exit(); - } // End for each area -} - -void SpaceBullet::check_body_collision() { -#ifdef DEBUG_ENABLED - reset_debug_contact_count(); -#endif - - const int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds(); - for (int i = 0; i < numManifolds; ++i) { - btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i); - - // I know this static cast is a bit risky. But I'm checking its type just after it. - // This allow me to avoid a lot of other cast and checks - RigidBodyBullet *bodyA = static_cast<RigidBodyBullet *>(contactManifold->getBody0()->getUserPointer()); - RigidBodyBullet *bodyB = static_cast<RigidBodyBullet *>(contactManifold->getBody1()->getUserPointer()); - - if (CollisionObjectBullet::TYPE_RIGID_BODY == bodyA->getType() && CollisionObjectBullet::TYPE_RIGID_BODY == bodyB->getType()) { - if (!bodyA->can_add_collision() && !bodyB->can_add_collision()) { - continue; - } - - const int numContacts = contactManifold->getNumContacts(); - - /// Since I don't need report all contacts for these objects, - /// So report only the first -#define REPORT_ALL_CONTACTS 0 -#if REPORT_ALL_CONTACTS - for (int j = 0; j < numContacts; j++) { - btManifoldPoint &pt = contactManifold->getContactPoint(j); -#else - if (numContacts) { - btManifoldPoint &pt = contactManifold->getContactPoint(0); -#endif - if ( - pt.getDistance() < 0.0 || - bodyA->was_colliding(bodyB) || - bodyB->was_colliding(bodyA)) { - Vector3 collisionWorldPosition; - Vector3 collisionLocalPosition; - Vector3 normalOnB; - real_t appliedImpulse = pt.m_appliedImpulse; - B_TO_G(pt.m_normalWorldOnB, normalOnB); - - // The pt.m_index only contains the shape index when more than one collision shape is used - // and only if the collision shape is not a concave collision shape. - // A value of -1 in pt.m_partId indicates the pt.m_index is a shape index. - int shape_index_a = 0; - if (bodyA->get_shape_count() > 1 && pt.m_partId0 == -1) { - shape_index_a = pt.m_index0; - } - int shape_index_b = 0; - if (bodyB->get_shape_count() > 1 && pt.m_partId1 == -1) { - shape_index_b = pt.m_index1; - } - - if (bodyA->can_add_collision()) { - B_TO_G(pt.getPositionWorldOnB(), collisionWorldPosition); - /// pt.m_localPointB Doesn't report the exact point in local space - B_TO_G(pt.getPositionWorldOnB() - contactManifold->getBody1()->getWorldTransform().getOrigin(), collisionLocalPosition); - bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, appliedImpulse, shape_index_b, shape_index_a); - } - if (bodyB->can_add_collision()) { - B_TO_G(pt.getPositionWorldOnA(), collisionWorldPosition); - /// pt.m_localPointA Doesn't report the exact point in local space - B_TO_G(pt.getPositionWorldOnA() - contactManifold->getBody0()->getWorldTransform().getOrigin(), collisionLocalPosition); - bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, appliedImpulse * -1, shape_index_a, shape_index_b); - } - -#ifdef DEBUG_ENABLED - if (is_debugging_contacts()) { - add_debug_contact(collisionWorldPosition); - } -#endif - } - } - } - } -} - -void SpaceBullet::update_gravity() { - btVector3 btGravity; - G_TO_B(gravityDirection * gravityMagnitude, btGravity); - //dynamicsWorld->setGravity(btGravity); - dynamicsWorld->setGravity(btVector3(0, 0, 0)); - if (soft_body_world_info) { - soft_body_world_info->m_gravity = btGravity; - } -} - -/// IMPORTANT: Please don't turn it ON this is not managed correctly!! -/// I'm leaving this here just for future tests. -/// Debug motion and normal vector drawing -#define debug_test_motion 0 - -#define RECOVERING_MOVEMENT_SCALE 0.4 -#define RECOVERING_MOVEMENT_CYCLES 4 - -#if debug_test_motion - -#include "scene/3d/immediate_geometry.h" - -static ImmediateGeometry3D *motionVec(nullptr); -static ImmediateGeometry3D *normalLine(nullptr); -static Ref<StandardMaterial3D> red_mat; -static Ref<StandardMaterial3D> blue_mat; -#endif - -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, const Set<RID> &p_exclude) { -#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 - if (!normalLine) { - motionVec = memnew(ImmediateGeometry3D); - normalLine = memnew(ImmediateGeometry3D); - SceneTree::get_singleton()->get_current_scene()->add_child(motionVec); - SceneTree::get_singleton()->get_current_scene()->add_child(normalLine); - - motionVec->set_as_top_level(true); - normalLine->set_as_top_level(true); - - red_mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - red_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - red_mat->set_line_width(20.0); - red_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - red_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - red_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - red_mat->set_albedo(Color(1, 0, 0, 1)); - motionVec->set_material_override(red_mat); - - blue_mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - blue_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - blue_mat->set_line_width(20.0); - blue_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - blue_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - blue_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - blue_mat->set_albedo(Color(0, 0, 1, 1)); - normalLine->set_material_override(blue_mat); - } -#endif - - btTransform body_transform; - G_TO_B(p_from, body_transform); - UNSCALE_BT_BASIS(body_transform); - - if (!p_body->get_kinematic_utilities()) { - p_body->init_kinematic_utilities(); - } - - btVector3 initial_recover_motion(0, 0, 0); - { /// Phase one - multi shapes depenetration using margin - for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion, nullptr, p_exclude)) { - break; - } - } - // Add recover movement in order to make it safe - body_transform.getOrigin() += initial_recover_motion; - } - - btVector3 motion; - G_TO_B(p_motion, motion); - real_t total_length = motion.length(); - real_t unsafe_fraction = 1.0; - real_t safe_fraction = 1.0; - { - // Phase two - sweep test, from a secure position without margin - - const int shape_count(p_body->get_shape_count()); - -#if debug_test_motion - Vector3 sup_line; - B_TO_G(body_safe_position.getOrigin(), sup_line); - motionVec->clear(); - motionVec->begin(Mesh::PRIMITIVE_LINES, nullptr); - motionVec->add_vertex(sup_line); - motionVec->add_vertex(sup_line + p_motion * 10); - motionVec->end(); -#endif - - for (int shIndex = 0; shIndex < shape_count; ++shIndex) { - if (p_body->is_shape_disabled(shIndex)) { - continue; - } - - if (!p_body->get_bt_shape(shIndex)->isConvex()) { - // Skip no convex shape - continue; - } - - if (p_exclude_raycast_shapes && p_body->get_bt_shape(shIndex)->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { - // Skip rayshape in order to implement custom separation process - continue; - } - - btConvexShape *convex_shape_test(static_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); - - btTransform shape_world_from = body_transform * p_body->get_kinematic_utilities()->shapes[shIndex].transform; - - btTransform shape_world_to(shape_world_from); - shape_world_to.getOrigin() += motion; - - if ((shape_world_to.getOrigin() - shape_world_from.getOrigin()).fuzzyZero()) { - motion = btVector3(0, 0, 0); - break; - } - - GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia, &p_exclude); - btResult.m_collisionFilterGroup = p_body->get_collision_layer(); - btResult.m_collisionFilterMask = p_body->get_collision_mask(); - - dynamicsWorld->convexSweepTest(convex_shape_test, shape_world_from, shape_world_to, btResult, dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration); - - if (btResult.hasHit()) { - if (total_length > CMP_EPSILON) { - real_t hit_fraction = btResult.m_closestHitFraction * motion.length() / total_length; - if (hit_fraction < unsafe_fraction) { - unsafe_fraction = hit_fraction; - real_t margin = p_body->get_kinematic_utilities()->safe_margin; - safe_fraction = MAX(hit_fraction - (1 - ((total_length - margin) / total_length)), 0); - } - } - - /// Since for each sweep test I fix the motion of new shapes in base the recover result, - /// if another shape will hit something it means that has a deepest penetration respect the previous shape - motion *= btResult.m_closestHitFraction; - } - } - - body_transform.getOrigin() += motion; - } - - bool has_penetration = false; - - { /// Phase three - contact test with margin - - btVector3 __rec(0, 0, 0); - RecoverResult r_recover_result; - - has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result, p_exclude); - - // Parse results - if (r_result) { - B_TO_G(motion + initial_recover_motion + __rec, r_result->motion); - - if (has_penetration) { - const btRigidBody *btRigid = static_cast<const btRigidBody *>(r_recover_result.other_collision_object); - CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer()); - - B_TO_G(motion, r_result->remainder); // is the remaining movements - r_result->remainder = p_motion - r_result->remainder; - - B_TO_G(r_recover_result.pointWorld, r_result->collision_point); - B_TO_G(r_recover_result.normal, r_result->collision_normal); - B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot - r_result->collider = collisionObject->get_self(); - r_result->collider_id = collisionObject->get_instance_id(); - r_result->collider_shape = r_recover_result.other_compound_shape_index; - r_result->collision_local_shape = r_recover_result.local_shape_most_recovered; - r_result->collision_depth = Math::abs(r_recover_result.penetration_distance); - r_result->collision_safe_fraction = safe_fraction; - r_result->collision_unsafe_fraction = unsafe_fraction; - -#if debug_test_motion - Vector3 sup_line2; - B_TO_G(motion, sup_line2); - normalLine->clear(); - normalLine->begin(Mesh::PRIMITIVE_LINES, nullptr); - normalLine->add_vertex(r_result->collision_point); - normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10); - normalLine->end(); -#endif - } else { - r_result->remainder = Vector3(); - } - } - } - - return has_penetration; -} - -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); - - if (!p_body->get_kinematic_utilities()) { - p_body->init_kinematic_utilities(); - } - - btVector3 recover_motion(0, 0, 0); - - int rays_found = 0; - int rays_found_this_round = 0; - - for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - PhysicsServer3D::SeparationResult *next_results = &r_results[rays_found]; - rays_found_this_round = recover_from_penetration_ray(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, p_result_max - rays_found, recover_motion, next_results); - - rays_found += rays_found_this_round; - if (rays_found_this_round == 0) { - body_transform.getOrigin() += recover_motion; - break; - } - } - - B_TO_G(recover_motion, r_recover_motion); - return rays_found; -} - -struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback { -private: - btDbvtVolume bounds; - - const btCollisionObject *self_collision_object; - uint32_t collision_layer = 0; - - struct CompoundLeafCallback : btDbvt::ICollide { - private: - RecoverPenetrationBroadPhaseCallback *parent_callback = nullptr; - btCollisionObject *collision_object = nullptr; - - public: - CompoundLeafCallback(RecoverPenetrationBroadPhaseCallback *p_parent_callback, btCollisionObject *p_collision_object) : - parent_callback(p_parent_callback), - collision_object(p_collision_object) { - } - - void Process(const btDbvtNode *leaf) { - BroadphaseResult result; - result.collision_object = collision_object; - result.compound_child_index = leaf->dataAsInt; - parent_callback->results.push_back(result); - } - }; - -public: - struct BroadphaseResult { - btCollisionObject *collision_object = nullptr; - int compound_child_index = 0; - }; - - Vector<BroadphaseResult> results; - -public: - RecoverPenetrationBroadPhaseCallback(const btCollisionObject *p_self_collision_object, uint32_t p_collision_layer, btVector3 p_aabb_min, btVector3 p_aabb_max) : - self_collision_object(p_self_collision_object), - collision_layer(p_collision_layer) { - bounds = btDbvtVolume::FromMM(p_aabb_min, p_aabb_max); - } - - virtual ~RecoverPenetrationBroadPhaseCallback() {} - - virtual bool process(const btBroadphaseProxy *proxy) { - btCollisionObject *co = static_cast<btCollisionObject *>(proxy->m_clientObject); - if (co->getInternalType() <= btCollisionObject::CO_RIGID_BODY) { - if (self_collision_object != proxy->m_clientObject && (proxy->collision_layer & m_collisionFilterMask)) { - if (co->getCollisionShape()->isCompound()) { - const btCompoundShape *cs = static_cast<btCompoundShape *>(co->getCollisionShape()); - - if (cs->getNumChildShapes() > 1) { - const btDbvt *tree = cs->getDynamicAabbTree(); - ERR_FAIL_COND_V(tree == nullptr, true); - - // Transform bounds into compound shape local space - const btTransform other_in_compound_space = co->getWorldTransform().inverse(); - const btMatrix3x3 abs_b = other_in_compound_space.getBasis().absolute(); - const btVector3 local_center = other_in_compound_space(bounds.Center()); - const btVector3 local_extent = bounds.Extents().dot3(abs_b[0], abs_b[1], abs_b[2]); - const btVector3 local_aabb_min = local_center - local_extent; - const btVector3 local_aabb_max = local_center + local_extent; - const btDbvtVolume local_bounds = btDbvtVolume::FromMM(local_aabb_min, local_aabb_max); - - // Test collision against compound child shapes using its AABB tree - CompoundLeafCallback compound_leaf_callback(this, co); - tree->collideTV(tree->m_root, local_bounds, compound_leaf_callback); - } else { - // If there's only a single child shape then there's no need to search any more, we know which child overlaps - BroadphaseResult result; - result.collision_object = co; - result.compound_child_index = 0; - results.push_back(result); - } - } else { - BroadphaseResult result; - result.collision_object = co; - result.compound_child_index = -1; - results.push_back(result); - } - return true; - } - } - return false; - } -}; - -bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result, const Set<RID> &p_exclude) { - // Calculate the cumulative AABB of all shapes of the kinematic body - btVector3 aabb_min, aabb_max; - bool shapes_found = false; - - for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) { - const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]); - if (!kin_shape.is_active()) { - continue; - } - - if (kin_shape.shape->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { - // Skip rayshape in order to implement custom separation process - continue; - } - - btTransform shape_transform = p_body_position * kin_shape.transform; - shape_transform.getOrigin() += r_delta_recover_movement; - - btVector3 shape_aabb_min, shape_aabb_max; - kin_shape.shape->getAabb(shape_transform, shape_aabb_min, shape_aabb_max); - - if (!shapes_found) { - aabb_min = shape_aabb_min; - aabb_max = shape_aabb_max; - shapes_found = true; - } else { - aabb_min.setX((aabb_min.x() < shape_aabb_min.x()) ? aabb_min.x() : shape_aabb_min.x()); - aabb_min.setY((aabb_min.y() < shape_aabb_min.y()) ? aabb_min.y() : shape_aabb_min.y()); - aabb_min.setZ((aabb_min.z() < shape_aabb_min.z()) ? aabb_min.z() : shape_aabb_min.z()); - - aabb_max.setX((aabb_max.x() > shape_aabb_max.x()) ? aabb_max.x() : shape_aabb_max.x()); - aabb_max.setY((aabb_max.y() > shape_aabb_max.y()) ? aabb_max.y() : shape_aabb_max.y()); - aabb_max.setZ((aabb_max.z() > shape_aabb_max.z()) ? aabb_max.z() : shape_aabb_max.z()); - } - } - - // If there are no shapes then there is no penetration either - if (!shapes_found) { - return false; - } - - // Perform broadphase test - RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), aabb_min, aabb_max); - dynamicsWorld->getBroadphase()->aabbTest(aabb_min, aabb_max, recover_broad_result); - - bool penetration = false; - - // Perform narrowphase per shape - for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) { - const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]); - if (!kin_shape.is_active()) { - continue; - } - - if (kin_shape.shape->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { - // Skip rayshape in order to implement custom separation process - 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; - - for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) { - btCollisionObject *otherObject = recover_broad_result.results[i].collision_object; - - CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer()); - if (p_exclude.has(gObj->get_self())) { - continue; - } - - if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) { - otherObject->activate(); // Force activation of hitten rigid, soft body - continue; - } else if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) { - continue; - } - - if (otherObject->getCollisionShape()->isCompound()) { - const btCompoundShape *cs = static_cast<const btCompoundShape *>(otherObject->getCollisionShape()); - int shape_idx = recover_broad_result.results[i].compound_child_index; - ERR_FAIL_COND_V(shape_idx < 0 || shape_idx >= cs->getNumChildShapes(), false); - - if (cs->getChildShape(shape_idx)->isConvex()) { - if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(shape_idx)), otherObject, kinIndex, shape_idx, shape_transform, otherObject->getWorldTransform() * cs->getChildTransform(shape_idx), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { - penetration = true; - } - } else { - if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(shape_idx), p_body->get_bt_collision_object(), otherObject, kinIndex, shape_idx, shape_transform, otherObject->getWorldTransform() * cs->getChildTransform(shape_idx), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { - penetration = true; - } - } - } else if (otherObject->getCollisionShape()->isConvex()) { /// Execute GJK test against object shape - if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), otherObject, kinIndex, 0, shape_transform, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { - penetration = true; - } - } else { - if (RFP_convex_world_test(kin_shape.shape, otherObject->getCollisionShape(), p_body->get_bt_collision_object(), otherObject, kinIndex, 0, shape_transform, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { - penetration = true; - } - } - } - } - - return penetration; -} - -bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { - // Initialize GJK input - btGjkPairDetector::ClosestPointInput gjk_input; - gjk_input.m_transformA = p_transformA; - gjk_input.m_transformB = p_transformB; - - // Perform GJK test - btPointCollector result; - btGjkPairDetector gjk_pair_detector(p_shapeA, p_shapeB, gjk_simplex_solver, gjk_epa_pen_solver); - gjk_pair_detector.getClosestPoints(gjk_input, result, nullptr); - if (0 > result.m_distance) { - // Has penetration - r_delta_recover_movement += result.m_normalOnBInWorld * (result.m_distance * -1 * p_recover_movement_scale); - - if (r_recover_result) { - if (result.m_distance < r_recover_result->penetration_distance) { - r_recover_result->hasPenetration = true; - r_recover_result->local_shape_most_recovered = p_shapeId_A; - r_recover_result->other_collision_object = p_objectB; - r_recover_result->other_compound_shape_index = p_shapeId_B; - r_recover_result->penetration_distance = result.m_distance; - r_recover_result->pointWorld = result.m_pointInWorld; - r_recover_result->normal = result.m_normalOnBInWorld; - } - } - return true; - } - return false; -} - -bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { - /// Contact test - - btTransform tA(p_transformA); - - btCollisionObjectWrapper obA(nullptr, p_shapeA, p_objectA, tA, -1, p_shapeId_A); - btCollisionObjectWrapper obB(nullptr, p_shapeB, p_objectB, p_transformB, -1, p_shapeId_B); - - btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, nullptr, BT_CONTACT_POINT_ALGORITHMS); - if (algorithm) { - GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB); - //discrete collision detection query - algorithm->processCollision(&obA, &obB, dynamicsWorld->getDispatchInfo(), &contactPointResult); - - algorithm->~btCollisionAlgorithm(); - dispatcher->freeCollisionAlgorithm(algorithm); - - if (contactPointResult.hasHit()) { - r_delta_recover_movement += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1 * p_recover_movement_scale); - if (r_recover_result) { - if (contactPointResult.m_penetration_distance < r_recover_result->penetration_distance) { - r_recover_result->hasPenetration = true; - r_recover_result->local_shape_most_recovered = p_shapeId_A; - r_recover_result->other_collision_object = p_objectB; - r_recover_result->other_compound_shape_index = p_shapeId_B; - r_recover_result->penetration_distance = contactPointResult.m_penetration_distance; - r_recover_result->pointWorld = contactPointResult.m_pointWorld; - r_recover_result->normal = contactPointResult.m_pointNormalWorld; - } - } - return true; - } - } - return false; -} - -int SpaceBullet::add_separation_result(PhysicsServer3D::SeparationResult *r_result, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const { - // optimize results (ignore non-colliding) - if (p_recover_result.penetration_distance < 0.0) { - const btRigidBody *btRigid = static_cast<const btRigidBody *>(p_other_object); - CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(p_other_object->getUserPointer()); - - r_result->collision_depth = p_recover_result.penetration_distance; - B_TO_G(p_recover_result.pointWorld, r_result->collision_point); - B_TO_G(p_recover_result.normal, r_result->collision_normal); - B_TO_G(btRigid->getVelocityInLocalPoint(p_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); - r_result->collision_local_shape = p_shape_id; - r_result->collider_id = collisionObject->get_instance_id(); - r_result->collider = collisionObject->get_self(); - r_result->collider_shape = p_recover_result.other_compound_shape_index; - - return 1; - } else { - return 0; - } -} - -int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer3D::SeparationResult *r_results) { - // Calculate the cumulative AABB of all shapes of the kinematic body - btVector3 aabb_min, aabb_max; - bool shapes_found = false; - - for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) { - const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]); - if (!kin_shape.is_active()) { - continue; - } - - if (kin_shape.shape->getShapeType() != CUSTOM_CONVEX_SHAPE_TYPE) { - continue; - } - - btTransform shape_transform = p_body_position * kin_shape.transform; - shape_transform.getOrigin() += r_delta_recover_movement; - - btVector3 shape_aabb_min, shape_aabb_max; - kin_shape.shape->getAabb(shape_transform, shape_aabb_min, shape_aabb_max); - - if (!shapes_found) { - aabb_min = shape_aabb_min; - aabb_max = shape_aabb_max; - shapes_found = true; - } else { - aabb_min.setX((aabb_min.x() < shape_aabb_min.x()) ? aabb_min.x() : shape_aabb_min.x()); - aabb_min.setY((aabb_min.y() < shape_aabb_min.y()) ? aabb_min.y() : shape_aabb_min.y()); - aabb_min.setZ((aabb_min.z() < shape_aabb_min.z()) ? aabb_min.z() : shape_aabb_min.z()); - - aabb_max.setX((aabb_max.x() > shape_aabb_max.x()) ? aabb_max.x() : shape_aabb_max.x()); - aabb_max.setY((aabb_max.y() > shape_aabb_max.y()) ? aabb_max.y() : shape_aabb_max.y()); - aabb_max.setZ((aabb_max.z() > shape_aabb_max.z()) ? aabb_max.z() : shape_aabb_max.z()); - } - } - - // If there are no shapes then there is no penetration either - if (!shapes_found) { - return 0; - } - - // Perform broadphase test - RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), aabb_min, aabb_max); - dynamicsWorld->getBroadphase()->aabbTest(aabb_min, aabb_max, recover_broad_result); - - int ray_count = 0; - - // Perform narrowphase per shape - for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) { - if (ray_count >= p_result_max) { - break; - } - - const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]); - if (!kin_shape.is_active()) { - continue; - } - - if (kin_shape.shape->getShapeType() != CUSTOM_CONVEX_SHAPE_TYPE) { - continue; - } - - btTransform shape_transform = p_body_position * kin_shape.transform; - shape_transform.getOrigin() += r_delta_recover_movement; - - for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) { - btCollisionObject *otherObject = recover_broad_result.results[i].collision_object; - if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) { - otherObject->activate(); // Force activation of hitten rigid, soft body - continue; - } else if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) { - continue; - } - - if (otherObject->getCollisionShape()->isCompound()) { - const btCompoundShape *cs = static_cast<const btCompoundShape *>(otherObject->getCollisionShape()); - int shape_idx = recover_broad_result.results[i].compound_child_index; - ERR_FAIL_COND_V(shape_idx < 0 || shape_idx >= cs->getNumChildShapes(), false); - - RecoverResult recover_result; - if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(shape_idx), p_body->get_bt_collision_object(), otherObject, kinIndex, shape_idx, shape_transform, otherObject->getWorldTransform() * cs->getChildTransform(shape_idx), p_recover_movement_scale, r_delta_recover_movement, &recover_result)) { - ray_count = add_separation_result(&r_results[ray_count], recover_result, kinIndex, otherObject); - } - } else { - RecoverResult recover_result; - if (RFP_convex_world_test(kin_shape.shape, otherObject->getCollisionShape(), p_body->get_bt_collision_object(), otherObject, kinIndex, 0, shape_transform, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, &recover_result)) { - ray_count = add_separation_result(&r_results[ray_count], recover_result, kinIndex, otherObject); - } - } - } - } - - return ray_count; -} diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h deleted file mode 100644 index cf8549030d..0000000000 --- a/modules/bullet/space_bullet.h +++ /dev/null @@ -1,223 +0,0 @@ -/*************************************************************************/ -/* space_bullet.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 SPACE_BULLET_H -#define SPACE_BULLET_H - -#include "core/templates/vector.h" -#include "core/variant/variant.h" -#include "godot_result_callbacks.h" -#include "rid_bullet.h" -#include "servers/physics_server_3d.h" - -#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h> -#include <BulletCollision/BroadphaseCollision/btOverlappingPairCache.h> -#include <LinearMath/btScalar.h> -#include <LinearMath/btTransform.h> -#include <LinearMath/btVector3.h> - -/** - @author AndreaCatania -*/ - -class AreaBullet; -class btBroadphaseInterface; -class btCollisionDispatcher; -class btConstraintSolver; -class btDefaultCollisionConfiguration; -class btDynamicsWorld; -class btDiscreteDynamicsWorld; -class btEmptyShape; -class btGhostPairCallback; -class btSoftRigidDynamicsWorld; -struct btSoftBodyWorldInfo; -class ConstraintBullet; -class CollisionObjectBullet; -class RigidBodyBullet; -class SpaceBullet; -class SoftBodyBullet; -class btGjkEpaPenetrationDepthSolver; - -extern ContactAddedCallback gContactAddedCallback; - -class BulletPhysicsDirectSpaceState : public PhysicsDirectSpaceState3D { - GDCLASS(BulletPhysicsDirectSpaceState, PhysicsDirectSpaceState3D); - -private: - SpaceBullet *space; - -public: - BulletPhysicsDirectSpaceState(SpaceBullet *p_space); - - 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 = UINT32_MAX, 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 = UINT32_MAX, 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 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 = UINT32_MAX, 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 = UINT32_MAX, 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 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 = UINT32_MAX, 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 = UINT32_MAX, 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; -}; - -class SpaceBullet : public RIDBullet { - friend class AreaBullet; - friend void onBulletTickCallback(btDynamicsWorld *world, btScalar timeStep); - friend class BulletPhysicsDirectSpaceState; - - btBroadphaseInterface *broadphase = nullptr; - btDefaultCollisionConfiguration *collisionConfiguration = nullptr; - btCollisionDispatcher *dispatcher = nullptr; - btConstraintSolver *solver = nullptr; - btDiscreteDynamicsWorld *dynamicsWorld = nullptr; - btSoftBodyWorldInfo *soft_body_world_info = nullptr; - btGhostPairCallback *ghostPairCallback = nullptr; - GodotFilterCallback *godotFilterCallback = nullptr; - - btGjkEpaPenetrationDepthSolver *gjk_epa_pen_solver = nullptr; - btVoronoiSimplexSolver *gjk_simplex_solver = nullptr; - - BulletPhysicsDirectSpaceState *direct_access; - Vector3 gravityDirection = Vector3(0, -1, 0); - real_t gravityMagnitude = 10.0; - - real_t linear_damp = 0.0; - real_t angular_damp = 0.0; - - Vector<AreaBullet *> areas; - - Vector<Vector3> contactDebug; - int contactDebugCount = 0; - real_t delta_time = 0.; - -public: - SpaceBullet(); - virtual ~SpaceBullet(); - - void flush_queries(); - real_t get_delta_time() { return delta_time; } - void step(real_t p_delta_time); - - _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() const { return broadphase; } - _FORCE_INLINE_ btDefaultCollisionConfiguration *get_collision_configuration() const { return collisionConfiguration; } - _FORCE_INLINE_ btCollisionDispatcher *get_dispatcher() const { return dispatcher; } - _FORCE_INLINE_ btConstraintSolver *get_solver() const { return solver; } - _FORCE_INLINE_ btDiscreteDynamicsWorld *get_dynamic_world() const { return dynamicsWorld; } - _FORCE_INLINE_ btSoftBodyWorldInfo *get_soft_body_world_info() const { return soft_body_world_info; } - _FORCE_INLINE_ bool is_using_soft_world() { return soft_body_world_info; } - - /// Used to set some parameters to Bullet world - /// @param p_param: - /// AREA_PARAM_GRAVITY to set the gravity magnitude of entire world - /// AREA_PARAM_GRAVITY_VECTOR to set the gravity direction of entire world - void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value); - /// Used to get some parameters to Bullet world - /// @param p_param: - /// AREA_PARAM_GRAVITY to get the gravity magnitude of entire world - /// AREA_PARAM_GRAVITY_VECTOR to get the gravity direction of entire world - Variant get_param(PhysicsServer3D::AreaParameter p_param); - - void set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value); - real_t get_param(PhysicsServer3D::SpaceParameter p_param); - - void add_area(AreaBullet *p_area); - void remove_area(AreaBullet *p_area); - void reload_collision_filters(AreaBullet *p_area); - - void add_rigid_body(RigidBodyBullet *p_body); - void remove_rigid_body_constraints(RigidBodyBullet *p_body); - void remove_rigid_body(RigidBodyBullet *p_body); - void reload_collision_filters(RigidBodyBullet *p_body); - - void add_soft_body(SoftBodyBullet *p_body); - void remove_soft_body(SoftBodyBullet *p_body); - void reload_collision_filters(SoftBodyBullet *p_body); - - void add_constraint(ConstraintBullet *p_constraint, bool disableCollisionsBetweenLinkedBodies = false); - void remove_constraint(ConstraintBullet *p_constraint); - - int get_num_collision_objects() const; - void remove_all_collision_objects(); - - BulletPhysicsDirectSpaceState *get_direct_state(); - - void set_debug_contacts(int p_amount) { contactDebug.resize(p_amount); } - _FORCE_INLINE_ bool is_debugging_contacts() const { return !contactDebug.is_empty(); } - _FORCE_INLINE_ void reset_debug_contact_count() { - contactDebugCount = 0; - } - _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { - if (contactDebugCount < contactDebug.size()) { - contactDebug.write[contactDebugCount++] = p_contact; - } - } - _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contactDebug; } - _FORCE_INLINE_ int get_debug_contact_count() { return contactDebugCount; } - - const Vector3 &get_gravity_direction() const { return gravityDirection; } - real_t get_gravity_magnitude() const { return gravityMagnitude; } - - void update_gravity(); - - 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 Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>()); - 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); - void destroy_world(); - void check_ghost_overlaps(); - void check_body_collision(); - - struct RecoverResult { - bool hasPenetration = false; - btVector3 normal = btVector3(0, 0, 0); - btVector3 pointWorld = btVector3(0, 0, 0); - btScalar penetration_distance = 1e20; // Negative mean penetration - int other_compound_shape_index = 0; - const btCollisionObject *other_collision_object = nullptr; - int local_shape_most_recovered = 0; - - RecoverResult() {} - }; - - bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr, const Set<RID> &p_exclude = Set<RID>()); - /// This is an API that recover a kinematic object from penetration - /// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions - bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr); - /// This is an API that recover a kinematic object from penetration - /// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm - bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr); - - int add_separation_result(PhysicsServer3D::SeparationResult *r_results, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const; - int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer3D::SeparationResult *r_results); -}; -#endif diff --git a/modules/camera/camera_osx.h b/modules/camera/camera_osx.h index 84274f0bf6..b0db844599 100644 --- a/modules/camera/camera_osx.h +++ b/modules/camera/camera_osx.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -39,7 +39,6 @@ class CameraOSX : public CameraServer { public: CameraOSX(); - ~CameraOSX(); void update_feeds(); }; diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm index 6def813e5c..d199c31b2f 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_osx.mm @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -114,18 +114,12 @@ if (output) { [self removeOutput:output]; [output setSampleBufferDelegate:nil queue:nullptr]; - [output release]; output = nullptr; } [self commitConfiguration]; } -- (void)dealloc { - // bye bye - [super dealloc]; -} - - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { // This gets called every time our camera has a new image for us to process. // May need to investigate in a way to throttle this if we get more images then we're rendering frames.. @@ -208,7 +202,6 @@ public: AVCaptureDevice *get_device() const; CameraFeedOSX(); - ~CameraFeedOSX(); void set_device(AVCaptureDevice *p_device); @@ -227,11 +220,10 @@ CameraFeedOSX::CameraFeedOSX() { void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { device = p_device; - [device retain]; // get some info NSString *device_name = p_device.localizedName; - name = device_name.UTF8String; + name = String::utf8(device_name.UTF8String); position = CameraFeed::FEED_UNSPECIFIED; if ([p_device position] == AVCaptureDevicePositionBack) { position = CameraFeed::FEED_BACK; @@ -240,18 +232,6 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { }; }; -CameraFeedOSX::~CameraFeedOSX() { - if (capture_session != nullptr) { - [capture_session release]; - capture_session = nullptr; - }; - - if (device != nullptr) { - [device release]; - device = nullptr; - }; -}; - bool CameraFeedOSX::activate_feed() { if (capture_session) { // Already recording! @@ -282,7 +262,6 @@ void CameraFeedOSX::deactivate_feed() { // end camera capture if we have one if (capture_session) { [capture_session cleanup]; - [capture_session release]; capture_session = nullptr; }; }; @@ -317,8 +296,6 @@ void CameraFeedOSX::deactivate_feed() { // remove notifications [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceWasConnectedNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceWasDisconnectedNotification object:nil]; - - [super dealloc]; } @end @@ -376,7 +353,3 @@ CameraOSX::CameraOSX() { // should only have one of these.... device_notifications = [[MyDeviceNotifications alloc] initForServer:this]; }; - -CameraOSX::~CameraOSX() { - [device_notifications release]; -}; diff --git a/modules/camera/camera_win.cpp b/modules/camera/camera_win.cpp index 226a642dcf..ab7cfec01a 100644 --- a/modules/camera/camera_win.cpp +++ b/modules/camera/camera_win.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/camera/camera_win.h b/modules/camera/camera_win.h index 671e7d5beb..9563326acb 100644 --- a/modules/camera/camera_win.h +++ b/modules/camera/camera_win.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp index 0d33ff9ddc..98a4b5ca1a 100644 --- a/modules/camera/register_types.cpp +++ b/modules/camera/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,7 +37,11 @@ #include "camera_osx.h" #endif -void register_camera_types() { +void initialize_camera_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #if defined(WINDOWS_ENABLED) CameraServer::make_default<CameraWindows>(); #endif @@ -46,5 +50,8 @@ void register_camera_types() { #endif } -void unregister_camera_types() { +void uninitialize_camera_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/camera/register_types.h b/modules/camera/register_types.h index 0ae9aa2c0b..4ac4426588 100644 --- a/modules/camera/register_types.h +++ b/modules/camera/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef CAMERA_REGISTER_TYPES_H #define CAMERA_REGISTER_TYPES_H -void register_camera_types(); -void unregister_camera_types(); +#include "modules/register_module_types.h" + +void initialize_camera_module(ModuleInitializationLevel p_level); +void uninitialize_camera_module(ModuleInitializationLevel p_level); #endif // CAMERA_REGISTER_TYPES_H diff --git a/modules/csg/SCsub b/modules/csg/SCsub index 641a42c187..c7307ddefd 100644 --- a/modules/csg/SCsub +++ b/modules/csg/SCsub @@ -3,7 +3,10 @@ Import("env") Import("env_modules") +# Godot's own source files env_csg = env_modules.Clone() # Godot's own source files env_csg.add_source_files(env.modules_sources, "*.cpp") +if env["tools"]: + env_csg.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index a70e153abd..177014e5a7 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -194,7 +194,7 @@ void CSGBrush::_regen_face_aabbs() { } } -void CSGBrush::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 CSGBrush::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_flip_faces) { faces.clear(); int vc = p_vertices.size(); @@ -208,8 +208,8 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< const bool *rs = p_smooth.ptr(); int mc = p_materials.size(); const Ref<Material> *rm = p_materials.ptr(); - int ic = p_invert_faces.size(); - const bool *ri = p_invert_faces.ptr(); + int ic = p_flip_faces.size(); + const bool *ri = p_flip_faces.ptr(); Map<Ref<Material>, int> material_map; @@ -1336,9 +1336,9 @@ CSGBrushOperation::Build2DFaces::Build2DFaces(const CSGBrush &p_brush, int p_fac plane = Plane(points_3D[0], points_3D[1], points_3D[2]); to_3D.origin = points_3D[0]; - to_3D.basis.set_axis(2, plane.normal); - to_3D.basis.set_axis(0, (points_3D[1] - points_3D[2]).normalized()); - to_3D.basis.set_axis(1, to_3D.basis.get_axis(0).cross(to_3D.basis.get_axis(2)).normalized()); + to_3D.basis.set_column(2, plane.normal); + to_3D.basis.set_column(0, (points_3D[1] - points_3D[2]).normalized()); + to_3D.basis.set_column(1, to_3D.basis.get_column(0).cross(to_3D.basis.get_column(2)).normalized()); to_2D = to_3D.affine_inverse(); Face2D face; @@ -1387,13 +1387,13 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face } // Ensure B has points either side of or in the plane of A. - int in_plane_count = 0, over_count = 0, under_count = 0; + int over_count = 0, under_count = 0; Plane plane_a(vertices_a[0], vertices_a[1], vertices_a[2]); ERR_FAIL_COND_MSG(plane_a.normal == Vector3(), "Couldn't form plane from Brush A face."); for (int i = 0; i < 3; i++) { if (plane_a.has_point(vertices_b[i])) { - in_plane_count++; + // In plane. } else if (plane_a.is_point_over(vertices_b[i])) { over_count++; } else { @@ -1406,7 +1406,6 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face } // Ensure A has points either side of or in the plane of B. - in_plane_count = 0; over_count = 0; under_count = 0; Plane plane_b(vertices_b[0], vertices_b[1], vertices_b[2]); @@ -1414,7 +1413,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face for (int i = 0; i < 3; i++) { if (plane_b.has_point(vertices_a[i])) { - in_plane_count++; + // In plane. } else if (plane_b.is_point_over(vertices_a[i])) { over_count++; } else { diff --git a/modules/csg/csg.h b/modules/csg/csg.h index b1fe933268..9ff7b13a44 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index b9be7535dc..a5b3db89d9 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -125,7 +125,7 @@ bool CSGShape3D::get_collision_mask_value(int p_layer_number) const { } bool CSGShape3D::is_root_shape() const { - return !parent; + return !parent_shape; } void CSGShape3D::set_snap(float p_snap) { @@ -136,13 +136,13 @@ float CSGShape3D::get_snap() const { return snap; } -void CSGShape3D::_make_dirty() { - if (!is_inside_tree()) { - return; +void CSGShape3D::_make_dirty(bool p_parent_removing) { + if ((p_parent_removing || is_root_shape()) && !dirty) { + call_deferred(SNAME("_update_shape")); // Must be deferred; otherwise, is_root_shape() will use the previous parent } - if (parent) { - parent->_make_dirty(); + if (!is_root_shape()) { + parent_shape->_make_dirty(); } else if (!dirty) { call_deferred(SNAME("_update_shape")); } @@ -164,7 +164,7 @@ CSGBrush *CSGShape3D::_get_brush() { if (!child) { continue; } - if (!child->is_visible_in_tree()) { + if (!child->is_visible()) { continue; } @@ -280,7 +280,7 @@ void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const } void CSGShape3D::_update_shape() { - if (parent || !is_inside_tree()) { + if (!is_root_shape()) { return; } @@ -303,17 +303,19 @@ void CSGShape3D::_update_shape() { ERR_CONTINUE(mat < -1 || mat >= face_count.size()); int idx = mat == -1 ? face_count.size() - 1 : mat; - Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]); + if (n->faces[i].smooth) { + Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]); - for (int j = 0; j < 3; j++) { - Vector3 v = n->faces[i].vertices[j]; - Vector3 add; - if (vec_map.lookup(v, add)) { - add += p.normal; - } else { - add = p.normal; + for (int j = 0; j < 3; j++) { + Vector3 v = n->faces[i].vertices[j]; + Vector3 add; + if (vec_map.lookup(v, add)) { + add += p.normal; + } else { + add = p.normal; + } + vec_map.set(v, add); } - vec_map.set(v, add); } face_count.write[idx]++; @@ -345,27 +347,6 @@ void CSGShape3D::_update_shape() { } } - // Update collision faces. - if (root_collision_shape.is_valid()) { - Vector<Vector3> physics_faces; - physics_faces.resize(n->faces.size() * 3); - Vector3 *physicsw = physics_faces.ptrw(); - - for (int i = 0; i < n->faces.size(); i++) { - int order[3] = { 0, 1, 2 }; - - if (n->faces[i].invert) { - SWAP(order[1], order[2]); - } - - physicsw[i * 3 + 0] = n->faces[i].vertices[order[0]]; - physicsw[i * 3 + 1] = n->faces[i].vertices[order[1]]; - physicsw[i * 3 + 2] = n->faces[i].vertices[order[2]]; - } - - root_collision_shape->set_faces(physics_faces); - } - //fill arrays { for (int i = 0; i < n->faces.size(); i++) { @@ -458,6 +439,32 @@ void CSGShape3D::_update_shape() { } set_base(root_mesh->get_rid()); + + _update_collision_faces(); +} + +void CSGShape3D::_update_collision_faces() { + if (use_collision && is_root_shape() && root_collision_shape.is_valid()) { + CSGBrush *n = _get_brush(); + ERR_FAIL_COND_MSG(!n, "Cannot get CSGBrush."); + Vector<Vector3> physics_faces; + physics_faces.resize(n->faces.size() * 3); + Vector3 *physicsw = physics_faces.ptrw(); + + for (int i = 0; i < n->faces.size(); i++) { + int order[3] = { 0, 1, 2 }; + + if (n->faces[i].invert) { + SWAP(order[1], order[2]); + } + + physicsw[i * 3 + 0] = n->faces[i].vertices[order[0]]; + physicsw[i * 3 + 1] = n->faces[i].vertices[order[1]]; + physicsw[i * 3 + 2] = n->faces[i].vertices[order[2]]; + } + + root_collision_shape->set_faces(physics_faces); + } } AABB CSGShape3D::get_aabb() const { @@ -486,66 +493,75 @@ Vector<Vector3> CSGShape3D::get_brush_faces() { return faces; } -Vector<Face3> CSGShape3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void CSGShape3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - Node *parentn = get_parent(); - if (parentn) { - parent = Object::cast_to<CSGShape3D>(parentn); - if (parent) { - set_base(RID()); - root_mesh.unref(); + switch (p_what) { + case NOTIFICATION_PARENTED: { + Node *parentn = get_parent(); + if (parentn) { + parent_shape = Object::cast_to<CSGShape3D>(parentn); + if (parent_shape) { + set_base(RID()); + root_mesh.unref(); + } } - } - - if (use_collision && is_root_shape()) { - 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()); - PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); - PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space()); - PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); - set_collision_layer(collision_layer); - set_collision_mask(collision_mask); - } + if (!brush || parent_shape) { + // Update this node if uninitialized, or both this node and its new parent if it gets added to another CSG shape + _make_dirty(); + } + last_visible = is_visible(); + } break; - _make_dirty(); - } + case NOTIFICATION_UNPARENTED: { + if (!is_root_shape()) { + // Update this node and its previous parent only if it's currently being removed from another CSG shape + _make_dirty(true); // Must be forced since is_root_shape() uses the previous parent + } + parent_shape = nullptr; + } break; - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { - PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); - } - } + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_root_shape() && last_visible != is_visible()) { + // Update this node's parent only if its own visibility has changed, not the visibility of parent nodes + parent_shape->_make_dirty(); + } + last_visible = is_visible(); + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (parent) { - parent->_make_dirty(); - } - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (!is_root_shape()) { + // Update this node's parent only if its own transformation has changed, not the transformation of parent nodes + parent_shape->_make_dirty(); + } + } break; - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (parent) { - parent->_make_dirty(); - } - } + case NOTIFICATION_ENTER_TREE: { + if (use_collision && is_root_shape()) { + 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()); + PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); + PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space()); + PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); + set_collision_layer(collision_layer); + set_collision_mask(collision_mask); + _update_collision_faces(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - if (parent) { - parent->_make_dirty(); - } - parent = nullptr; + case NOTIFICATION_EXIT_TREE: { + if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { + PhysicsServer3D::get_singleton()->free(root_collision_instance); + root_collision_instance = RID(); + root_collision_shape.unref(); + } + } break; - if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { - PhysicsServer3D::get_singleton()->free(root_collision_instance); - root_collision_instance = RID(); - root_collision_shape.unref(); - } - _make_dirty(); + case NOTIFICATION_TRANSFORM_CHANGED: { + if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { + PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); + } + } break; } } @@ -666,7 +682,7 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver int ic = invert.size(); bool *w = invert.ptrw(); for (int i = 0; i < ic; i++) { - w[i] = invert_faces; + w[i] = flip_faces; } } brush->build_from_faces(p_vertices, p_uv, p_smooth, p_materials, invert); @@ -675,28 +691,28 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver } void CSGPrimitive3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive3D::set_invert_faces); - ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive3D::is_inverting_faces); + ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &CSGPrimitive3D::set_flip_faces); + ClassDB::bind_method(D_METHOD("get_flip_faces"), &CSGPrimitive3D::get_flip_faces); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_faces"), "set_invert_faces", "is_inverting_faces"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces"); } -void CSGPrimitive3D::set_invert_faces(bool p_invert) { - if (invert_faces == p_invert) { +void CSGPrimitive3D::set_flip_faces(bool p_invert) { + if (flip_faces == p_invert) { return; } - invert_faces = p_invert; + flip_faces = p_invert; _make_dirty(); } -bool CSGPrimitive3D::is_inverting_faces() { - return invert_faces; +bool CSGPrimitive3D::get_flip_faces() { + return flip_faces; } CSGPrimitive3D::CSGPrimitive3D() { - invert_faces = false; + flip_faces = false; } ///////////////////// @@ -905,7 +921,7 @@ CSGBrush *CSGSphere3D::_build_brush() { int face_count = rings * radial_segments * 2 - radial_segments * 2; - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -953,6 +969,10 @@ CSGBrush *CSGSphere3D::_build_brush() { double u0 = double(j) / radial_segments; double longitude1 = longitude_step * (j + 1); + if (j == radial_segments - 1) { + longitude1 = 0; + } + double x1 = Math::sin(longitude1); double z1 = Math::cos(longitude1); double u1 = double(j + 1) / radial_segments; @@ -1090,7 +1110,7 @@ Ref<Material> CSGSphere3D::get_material() const { CSGSphere3D::CSGSphere3D() { // defaults - radius = 1.0; + radius = 0.5; radial_segments = 12; rings = 6; smooth_faces = true; @@ -1105,7 +1125,7 @@ CSGBrush *CSGBox3D::_build_brush() { int face_count = 12; //it's a cube.. - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1238,7 +1258,7 @@ CSGBrush *CSGCylinder3D::_build_brush() { int face_count = sides * (cone ? 1 : 2) + sides + (cone ? 0 : sides); - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1269,6 +1289,9 @@ CSGBrush *CSGCylinder3D::_build_brush() { for (int i = 0; i < sides; i++) { float inc = float(i) / sides; float inc_n = float((i + 1)) / sides; + if (i == sides - 1) { + inc_n = 0; + } float ang = inc * Math_TAU; float ang_n = inc_n * Math_TAU; @@ -1451,8 +1474,8 @@ Ref<Material> CSGCylinder3D::get_material() const { CSGCylinder3D::CSGCylinder3D() { // defaults - radius = 1.0; - height = 1.0; + radius = 0.5; + height = 2.0; sides = 8; cone = false; smooth_faces = true; @@ -1480,7 +1503,7 @@ CSGBrush *CSGTorus3D::_build_brush() { int face_count = ring_sides * sides * 2; - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1509,6 +1532,9 @@ CSGBrush *CSGTorus3D::_build_brush() { for (int i = 0; i < sides; i++) { float inci = float(i) / sides; float inci_n = float((i + 1)) / sides; + if (i == sides - 1) { + inci_n = 0; + } float angi = inci * Math_TAU; float angi_n = inci_n * Math_TAU; @@ -1519,6 +1545,9 @@ CSGBrush *CSGTorus3D::_build_brush() { for (int j = 0; j < ring_sides; j++) { float incj = float(j) / ring_sides; float incj_n = float((j + 1)) / ring_sides; + if (j == ring_sides - 1) { + incj_n = 0; + } float angj = incj * Math_TAU; float angj_n = incj_n * Math_TAU; @@ -1671,8 +1700,8 @@ Ref<Material> CSGTorus3D::get_material() const { CSGTorus3D::CSGTorus3D() { // defaults - inner_radius = 2.0; - outer_radius = 3.0; + inner_radius = 0.5; + outer_radius = 1.0; sides = 8; ring_sides = 6; smooth_faces = true; @@ -1694,7 +1723,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { } int shape_sides = shape_polygon.size(); Vector<int> shape_faces = Geometry2D::triangulate_polygon(shape_polygon); - ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon"); + ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon. Make sure the polygon doesn't have any intersecting edges."); // Get polygon enclosing Rect2. Rect2 shape_rect(shape_polygon[0], Vector2()); @@ -1760,7 +1789,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { } int face_count = extrusions * extrusion_face_count + end_count * shape_face_count; - // Intialize variables used to create the mesh. + // Initialize variables used to create the mesh. Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1852,7 +1881,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { smoothw[face] = false; materialsw[face] = material; - invertw[face] = invert_faces; + invertw[face] = flip_faces; face++; } } @@ -1957,7 +1986,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { uvsw[face * 3 + 2] = u[2]; smoothw[face] = smooth_faces; - invertw[face] = invert_faces; + invertw[face] = flip_faces; materialsw[face] = material; face++; @@ -1972,7 +2001,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { uvsw[face * 3 + 2] = u[0]; smoothw[face] = smooth_faces; - invertw[face] = invert_faces; + invertw[face] = flip_faces; materialsw[face] = material; face++; @@ -1997,7 +2026,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { smoothw[face] = false; materialsw[face] = material; - invertw[face] = invert_faces; + invertw[face] = flip_faces; face++; } } diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index c85cce776b..0eaf5c3727 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -52,13 +52,14 @@ public: private: Operation operation = OPERATION_UNION; - CSGShape3D *parent = nullptr; + CSGShape3D *parent_shape = nullptr; CSGBrush *brush = nullptr; AABB node_aabb; bool dirty = false; + bool last_visible = false; float snap = 0.001; bool use_collision = false; @@ -104,11 +105,12 @@ private: const tbool bIsOrientationPreserving, const int iFace, const int iVert); void _update_shape(); + void _update_collision_faces(); protected: void _notification(int p_what); virtual CSGBrush *_build_brush() = 0; - void _make_dirty(); + void _make_dirty(bool p_parent_removing = false); static void _bind_methods(); @@ -126,7 +128,6 @@ public: virtual Vector<Vector3> get_brush_faces(); virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; void set_use_collision(bool p_enable); bool is_using_collision() const; @@ -170,13 +171,13 @@ class CSGPrimitive3D : public CSGShape3D { GDCLASS(CSGPrimitive3D, CSGShape3D); protected: - bool invert_faces; + bool flip_faces; CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials); static void _bind_methods(); public: - void set_invert_faces(bool p_invert); - bool is_inverting_faces(); + void set_flip_faces(bool p_invert); + bool get_flip_faces(); CSGPrimitive3D(); }; @@ -239,7 +240,7 @@ class CSGBox3D : public CSGPrimitive3D { virtual CSGBrush *_build_brush() override; Ref<Material> material; - Vector3 size = Vector3(2, 2, 2); + Vector3 size = Vector3(1, 1, 1); protected: static void _bind_methods(); @@ -367,7 +368,7 @@ private: PathRotation path_rotation; bool path_local; - Path3D *path; + Path3D *path = nullptr; bool smooth_faces; bool path_continuous_u; diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml index d64e58ae4d..591110fa38 100644 --- a/modules/csg/doc_classes/CSGBox3D.xml +++ b/modules/csg/doc_classes/CSGBox3D.xml @@ -1,18 +1,20 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.0"> +<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A CSG Box shape. </brief_description> <description> This node allows you to create a box for use with the CSG system. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> <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(1, 1, 1)"> The box's width, height and depth. </member> </members> diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml index 422c5d35b7..1601602601 100644 --- a/modules/csg/doc_classes/CSGCombiner3D.xml +++ b/modules/csg/doc_classes/CSGCombiner3D.xml @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.0"> +<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A CSG node that allows you to combine other CSG modifiers. </brief_description> <description> For complex arrangements of shapes, it is sometimes needed to add structure to your CSG nodes. The CSGCombiner3D node allows you to create this structure. The node encapsulates the result of the CSG operations of its children. In this way, it is possible to do operations on one set of shapes that are children of one CSGCombiner3D node, and a set of separate operations on a second set of shapes that are children of a second CSGCombiner3D node, and then do an operation that takes the two end results as its input to create the final shape. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> </class> diff --git a/modules/csg/doc_classes/CSGCylinder3D.xml b/modules/csg/doc_classes/CSGCylinder3D.xml index 40e989bfb3..ea026c5ee9 100644 --- a/modules/csg/doc_classes/CSGCylinder3D.xml +++ b/modules/csg/doc_classes/CSGCylinder3D.xml @@ -1,24 +1,26 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.0"> +<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A CSG Cylinder shape. </brief_description> <description> This node allows you to create a cylinder (or cone) for use with the CSG system. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> <member name="cone" type="bool" setter="set_cone" getter="is_cone" default="false"> If [code]true[/code] a cone is created, the [member radius] will only apply to one side. </member> - <member name="height" type="float" setter="set_height" getter="get_height" default="1.0"> + <member name="height" type="float" setter="set_height" getter="get_height" default="2.0"> The height of the cylinder. </member> <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the cylinder. </member> - <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0"> + <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5"> The radius of the cylinder. </member> <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8"> diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml index 2810343139..3318fb21c8 100644 --- a/modules/csg/doc_classes/CSGMesh3D.xml +++ b/modules/csg/doc_classes/CSGMesh3D.xml @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.0"> +<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> 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 than 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. See also [CSGPolygon3D] for drawing 2D extruded polygons to be used as CSG nodes. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> <member name="material" type="Material" setter="set_material" getter="get_material"> diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index ecbb7962d1..cacad21453 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.0"> +<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Extrudes a 2D polygon shape to create a 3D mesh. </brief_description> <description> - An array of 2D points is extruded to quickly and easily create a variety of 3D meshes. + An array of 2D points is extruded to quickly and easily create a variety of 3D meshes. See also [CSGMesh3D] for using 3D meshes as CSG nodes. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0"> @@ -46,7 +48,8 @@ When [member mode] is [constant MODE_PATH], this is the distance along the path, in meters, the texture coordinates will tile. When set to 0, texture coordinates will match geometry exactly with no tiling. </member> <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)"> - The point array that defines the 2D polygon that is extruded. + The point array that defines the 2D polygon that is extruded. This can be a convex or concave polygon with 3 or more points. The polygon must [i]not[/i] have any intersecting edges. Otherwise, triangulation will fail and no mesh will be generated. + [b]Note:[/b] If only 1 or 2 points are defined in [member polygon], no mesh will be generated. </member> <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false"> If [code]true[/code], applies smooth shading to the extrusions. diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml index 8f4c8b9451..6ea413c991 100644 --- a/modules/csg/doc_classes/CSGPrimitive3D.xml +++ b/modules/csg/doc_classes/CSGPrimitive3D.xml @@ -1,16 +1,18 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.0"> +<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Base class for CSG primitives. </brief_description> <description> Parent class for various CSG primitives. It contains code and functionality that is common between them. It cannot be used directly. Instead use one of the various classes that inherit from it. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> - <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false"> - Invert the faces of the mesh. + <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false"> + If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn. </member> </members> </class> diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index f5031064d6..f1cd28e00f 100644 --- a/modules/csg/doc_classes/CSGShape3D.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.0"> +<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> The CSG base class. </brief_description> <description> This is the CSG base class that provides CSG operation support to the various CSG nodes in Godot. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <methods> <method name="get_collision_layer_value" qualifiers="const"> diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml index b8dfb4cf5f..d2f985b3a2 100644 --- a/modules/csg/doc_classes/CSGSphere3D.xml +++ b/modules/csg/doc_classes/CSGSphere3D.xml @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.0"> +<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A CSG Sphere shape. </brief_description> <description> This node allows you to create a sphere for use with the CSG system. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> <member name="material" type="Material" setter="set_material" getter="get_material"> @@ -15,7 +17,7 @@ <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12"> Number of vertical slices for the sphere. </member> - <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0"> + <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5"> Radius of the sphere. </member> <member name="rings" type="int" setter="set_rings" getter="get_rings" default="6"> diff --git a/modules/csg/doc_classes/CSGTorus3D.xml b/modules/csg/doc_classes/CSGTorus3D.xml index 91ee63a4c9..ea555a5449 100644 --- a/modules/csg/doc_classes/CSGTorus3D.xml +++ b/modules/csg/doc_classes/CSGTorus3D.xml @@ -1,21 +1,23 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.0"> +<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A CSG Torus shape. </brief_description> <description> This node allows you to create a torus for use with the CSG system. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. </description> <tutorials> + <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> - <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0"> + <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="0.5"> The inner radius of the torus. </member> <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the torus. </member> - <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="3.0"> + <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="1.0"> The outer radius of the torus. </member> <member name="ring_sides" type="int" setter="set_ring_sides" getter="get_ring_sides" default="6"> diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 2f8b354bb7..4d972e46c6 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -29,6 +29,10 @@ /*************************************************************************/ #include "csg_gizmos.h" + +#ifdef TOOLS_ENABLED + +#include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" @@ -50,7 +54,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { create_handle_material("handles"); } -String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const { +String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -72,7 +76,7 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, return ""; } -Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const { +Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -98,7 +102,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo return Variant(); } -void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { +void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); Transform3D gt = cs->get_global_transform(); @@ -201,7 +205,7 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i } } -void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { +void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -343,6 +347,14 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_lines(lines, material); p_gizmo->add_collision_segments(lines); + if (cs->is_root_shape()) { + Array csg_meshes = cs->get_meshes(); + Ref<Mesh> csg_mesh = csg_meshes[1]; + if (csg_mesh.is_valid()) { + p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh()); + } + } + if (p_gizmo->is_selected()) { // Draw a translucent representation of the CSG node Ref<ArrayMesh> mesh = memnew(ArrayMesh); @@ -409,7 +421,9 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } } -EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) { +EditorPluginCSG::EditorPluginCSG() { Ref<CSGShape3DGizmoPlugin> gizmo_plugin = Ref<CSGShape3DGizmoPlugin>(memnew(CSGShape3DGizmoPlugin)); Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); } + +#endif // TOOLS_ENABLED diff --git a/modules/csg/csg_gizmos.h b/modules/csg/editor/csg_gizmos.h index 2a6ab91102..fa51010f98 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/editor/csg_gizmos.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef CSG_GIZMOS_H #define CSG_GIZMOS_H -#include "csg_shape.h" +#ifdef TOOLS_ENABLED + +#include "../csg_shape.h" #include "editor/editor_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" @@ -45,10 +47,10 @@ public: virtual bool is_selectable_when_hidden() const override; virtual void redraw(EditorNode3DGizmo *p_gizmo) override; - virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; - virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) override; + virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) override; CSGShape3DGizmoPlugin(); }; @@ -57,7 +59,9 @@ class EditorPluginCSG : public EditorPlugin { GDCLASS(EditorPluginCSG, EditorPlugin); public: - EditorPluginCSG(EditorNode *p_editor); + EditorPluginCSG(); }; +#endif // TOOLS_ENABLED + #endif // CSG_GIZMOS_H diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp index a47390c2b2..9b5888dafe 100644 --- a/modules/csg/register_types.cpp +++ b/modules/csg/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,27 +30,37 @@ #include "register_types.h" -#include "csg_gizmos.h" -#include "csg_shape.h" - -void register_csg_types() { #ifndef _3D_DISABLED - 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); +#include "csg_shape.h" #ifdef TOOLS_ENABLED - EditorPlugins::add_by_type<EditorPluginCSG>(); +#include "editor/csg_gizmos.h" #endif + +void initialize_csg_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { + GDREGISTER_ABSTRACT_CLASS(CSGShape3D); + GDREGISTER_ABSTRACT_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 + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + EditorPlugins::add_by_type<EditorPluginCSG>(); + } #endif } -void unregister_csg_types() { +void uninitialize_csg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } + +#endif // _3D_DISABLED diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h index 8747b3fade..ec65adde9c 100644 --- a/modules/csg/register_types.h +++ b/modules/csg/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef CSG_REGISTER_TYPES_H #define CSG_REGISTER_TYPES_H -void register_csg_types(); -void unregister_csg_types(); +#include "modules/register_module_types.h" + +void initialize_csg_module(ModuleInitializationLevel p_level); +void uninitialize_csg_module(ModuleInitializationLevel p_level); #endif // CSG_REGISTER_TYPES_H diff --git a/modules/cvtt/SCsub b/modules/cvtt/SCsub index e56177d6e9..1d5a7ff6a3 100644 --- a/modules/cvtt/SCsub +++ b/modules/cvtt/SCsub @@ -11,7 +11,16 @@ thirdparty_obj = [] thirdparty_dir = "#thirdparty/cvtt/" thirdparty_sources = [ - "ConvectionKernels.cpp", + "ConvectionKernels_API.cpp", + "ConvectionKernels_ETC.cpp", + "ConvectionKernels_BC67.cpp", + "ConvectionKernels_IndexSelector.cpp", + "ConvectionKernels_BC6H_IO.cpp", + "ConvectionKernels_S3TC.cpp", + "ConvectionKernels_BC7_PrioData.cpp", + "ConvectionKernels_SingleFile.cpp", + "ConvectionKernels_BCCommon.cpp", + "ConvectionKernels_Util.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 3beca3d12a..a7cfcaa262 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -41,12 +41,12 @@ struct CVTTCompressionJobParams { bool is_hdr = false; bool is_signed = false; int bytes_per_pixel = 0; - + cvtt::BC7EncodingPlan bc7_plan; cvtt::Options options; }; struct CVTTCompressionRowTask { - const uint8_t *in_mm_bytes; + const uint8_t *in_mm_bytes = nullptr; uint8_t *out_mm_bytes = nullptr; int y_start = 0; int width = 0; @@ -55,7 +55,7 @@ struct CVTTCompressionRowTask { struct CVTTCompressionJobQueue { CVTTCompressionJobParams job_params; - const CVTTCompressionRowTask *job_tasks; + const CVTTCompressionRowTask *job_tasks = nullptr; uint32_t num_tasks = 0; SafeNumeric<uint32_t> current_task; }; @@ -116,7 +116,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const cvtt::Kernels::EncodeBC6HU(output_blocks, input_blocks_hdr, p_job_params.options); } } else { - cvtt::Kernels::EncodeBC7(output_blocks, input_blocks_ldr, p_job_params.options); + cvtt::Kernels::EncodeBC7(output_blocks, input_blocks_ldr, p_job_params.options, p_job_params.bc7_plan); } unsigned int num_real_blocks = ((w - x_start) + 3) / 4; @@ -141,7 +141,6 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann if (p_image->get_format() >= Image::FORMAT_BPTC_RGBA) { return; //do not compress, already compressed } - int w = p_image->get_width(); int h = p_image->get_height(); @@ -153,22 +152,8 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann } cvtt::Options options; - uint32_t flags = cvtt::Flags::Fastest; - - if (p_lossy_quality > 0.85) { - flags = cvtt::Flags::Ultra; - } else if (p_lossy_quality > 0.75) { - flags = cvtt::Flags::Better; - } else if (p_lossy_quality > 0.55) { - flags = cvtt::Flags::Default; - } else if (p_lossy_quality > 0.35) { - flags = cvtt::Flags::Fast; - } else if (p_lossy_quality > 0.15) { - flags = cvtt::Flags::Faster; - } - + uint32_t flags = cvtt::Flags::Default; flags |= cvtt::Flags::BC7_RespectPunchThrough; - if (p_channels == Image::USED_CHANNELS_RG) { //guessing this is a normal map flags |= cvtt::Flags::Uniform; } @@ -215,12 +200,15 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann job_queue.job_params.is_signed = is_signed; job_queue.job_params.options = options; job_queue.job_params.bytes_per_pixel = is_hdr ? 6 : 4; + cvtt::Kernels::ConfigureBC7EncodingPlanFromQuality(job_queue.job_params.bc7_plan, 5); -#ifdef NO_THREADS int num_job_threads = 0; -#else - int num_job_threads = OS::get_singleton()->can_use_threads() ? (OS::get_singleton()->get_processor_count() - 1) : 0; -#endif + // Amdahl's law (Wikipedia) + // If a program needs 20 hours to complete using a single thread, but a one-hour portion of the program cannot be parallelized, + // therefore only the remaining 19 hours (p = 0.95) of execution time can be parallelized, then regardless of how many threads are devoted + // to a parallelized execution of this program, the minimum execution time cannot be less than one hour. + // + // The number of executions with different inputs can be increased while the latency is the same. Vector<CVTTCompressionRowTask> tasks; @@ -278,7 +266,6 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann memdelete(threads_wb[i]); } } - p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); } @@ -388,6 +375,5 @@ void image_decompress_cvtt(Image *p_image) { w >>= 1; h >>= 1; } - p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); } diff --git a/modules/cvtt/image_compress_cvtt.h b/modules/cvtt/image_compress_cvtt.h index bef5653fa9..a8dbe1d929 100644 --- a/modules/cvtt/image_compress_cvtt.h +++ b/modules/cvtt/image_compress_cvtt.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp index 055b5dc6e3..ff22c0f53e 100644 --- a/modules/cvtt/register_types.cpp +++ b/modules/cvtt/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,19 @@ #include "image_compress_cvtt.h" -void register_cvtt_types() { +void initialize_cvtt_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + Image::set_compress_bptc_func(image_compress_cvtt); Image::_image_decompress_bptc = image_decompress_cvtt; } -void unregister_cvtt_types() {} +void uninitialize_cvtt_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} #endif diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h index e62e8c0e9a..38a375eb44 100644 --- a/modules/cvtt/register_types.h +++ b/modules/cvtt/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,8 +33,10 @@ #ifdef TOOLS_ENABLED -void register_cvtt_types(); -void unregister_cvtt_types(); +#include "modules/register_module_types.h" + +void initialize_cvtt_module(ModuleInitializationLevel p_level); +void uninitialize_cvtt_module(ModuleInitializationLevel p_level); #endif // TOOLS_ENABLED diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp index 60282c3f36..e819c92dd3 100644 --- a/modules/dds/register_types.cpp +++ b/modules/dds/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,12 +34,20 @@ static Ref<ResourceFormatDDS> resource_loader_dds; -void register_dds_types() { +void initialize_dds_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + resource_loader_dds.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_dds); } -void unregister_dds_types() { +void uninitialize_dds_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + ResourceLoader::remove_resource_format_loader(resource_loader_dds); resource_loader_dds.unref(); } diff --git a/modules/dds/register_types.h b/modules/dds/register_types.h index b84bcd06c8..3cd154d576 100644 --- a/modules/dds/register_types.h +++ b/modules/dds/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef DDS_REGISTER_TYPES_H #define DDS_REGISTER_TYPES_H -void register_dds_types(); -void unregister_dds_types(); +#include "modules/register_module_types.h" + +void initialize_dds_module(ModuleInitializationLevel p_level); +void uninitialize_dds_module(ModuleInitializationLevel p_level); #endif // DDS_REGISTER_TYPES_H diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index fced61a600..2c0e604e66 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -68,7 +68,7 @@ enum DDSFormat { }; struct DDSFormatInfo { - const char *name; + const char *name = nullptr; bool compressed = false; bool palette = false; uint32_t divisor = 0; @@ -94,23 +94,23 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = { { "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 } }; -RES ResourceFormatDDS::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<Resource> ResourceFormatDDS::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(); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { + return Ref<Resource>(); } - FileAccessRef fref(f); + Ref<FileAccess> fref(f); if (r_error) { *r_error = ERR_FILE_CORRUPT; } - ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open DDS texture file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open DDS texture file '" + p_path + "'."); uint32_t magic = f->get_32(); uint32_t hsize = f->get_32(); @@ -131,7 +131,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, // We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing, // but non-mandatory when reading (as some writers don't set them)... if (magic != DDS_MAGIC || hsize != 124) { - ERR_FAIL_V_MSG(RES(), "Invalid or unsupported DDS texture file '" + p_path + "'."); + ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid or unsupported DDS texture file '" + p_path + "'."); } /* uint32_t format_size = */ f->get_32(); @@ -204,7 +204,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, dds_format = DDS_BGR565; } else { printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n", format_fourcc, format_flags, format_rgb_bits, format_red_mask, format_green_mask, format_blue_mask, format_alpha_mask); - ERR_FAIL_V_MSG(RES(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'."); + ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'."); } if (!(flags & DDSD_MIPMAPCOUNT)) { @@ -221,12 +221,12 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, //compressed bc uint32_t size = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size; - ERR_FAIL_COND_V(size != pitch, RES()); - ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), RES()); + ERR_FAIL_COND_V(size != pitch, Ref<Resource>()); + ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), Ref<Resource>()); for (uint32_t i = 1; i < mipmaps; i++) { - w = MAX(1, w >> 1); - h = MAX(1, h >> 1); + w = MAX(1u, w >> 1); + h = MAX(1u, h >> 1); uint32_t bsize = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size; //printf("%i x %i - block: %i\n",w,h,bsize); size += bsize; @@ -238,11 +238,11 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, } else if (info.palette) { //indexed - ERR_FAIL_COND_V(!(flags & DDSD_PITCH), RES()); - ERR_FAIL_COND_V(format_rgb_bits != 8, RES()); + ERR_FAIL_COND_V(!(flags & DDSD_PITCH), Ref<Resource>()); + ERR_FAIL_COND_V(format_rgb_bits != 8, Ref<Resource>()); uint32_t size = pitch * height; - ERR_FAIL_COND_V(size != width * height * info.block_size, RES()); + ERR_FAIL_COND_V(size != width * height * info.block_size, Ref<Resource>()); uint8_t palette[256 * 4]; f->get_buffer(palette, 256 * 4); diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h index cf93156423..701f8f4a13 100644 --- a/modules/dds/texture_loader_dds.h +++ b/modules/dds/texture_loader_dds.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,7 +36,7 @@ class ResourceFormatDDS : 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 Ref<Resource> 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; diff --git a/modules/denoise/denoise_wrapper.cpp b/modules/denoise/denoise_wrapper.cpp index e71fce5958..ef97c1a184 100644 --- a/modules/denoise/denoise_wrapper.cpp +++ b/modules/denoise/denoise_wrapper.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/denoise/denoise_wrapper.h b/modules/denoise/denoise_wrapper.h index 25e342bc93..44e61ce31d 100644 --- a/modules/denoise/denoise_wrapper.h +++ b/modules/denoise/denoise_wrapper.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/denoise/lightmap_denoiser.cpp b/modules/denoise/lightmap_denoiser.cpp index 71dcc1d75f..a0dbd07b10 100644 --- a/modules/denoise/lightmap_denoiser.cpp +++ b/modules/denoise/lightmap_denoiser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/denoise/lightmap_denoiser.h b/modules/denoise/lightmap_denoiser.h index f1992a1733..452a7cae85 100644 --- a/modules/denoise/lightmap_denoiser.h +++ b/modules/denoise/lightmap_denoiser.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/denoise/register_types.cpp b/modules/denoise/register_types.cpp index 936e5f604d..891a03c657 100644 --- a/modules/denoise/register_types.cpp +++ b/modules/denoise/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,9 +32,16 @@ #include "core/config/engine.h" #include "lightmap_denoiser.h" -void register_denoise_types() { +void initialize_denoise_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + LightmapDenoiserOIDN::make_default_denoiser(); } -void unregister_denoise_types() { +void uninitialize_denoise_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/denoise/register_types.h b/modules/denoise/register_types.h index 516a91b134..13eba88d17 100644 --- a/modules/denoise/register_types.h +++ b/modules/denoise/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef DENOISE_REGISTER_TYPES_H #define DENOISE_REGISTER_TYPES_H -void register_denoise_types(); -void unregister_denoise_types(); +#include "modules/register_module_types.h" + +void initialize_denoise_module(ModuleInitializationLevel p_level); +void uninitialize_denoise_module(ModuleInitializationLevel p_level); #endif // DENOISE_REGISTER_TYPES_H diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml index fcdf282a7d..14aad0cb39 100644 --- a/modules/enet/doc_classes/ENetConnection.xml +++ b/modules/enet/doc_classes/ENetConnection.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ENetConnection" inherits="RefCounted" version="4.0"> +<class name="ENetConnection" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A wrapper class for an [url=http://enet.bespin.org/group__host.html]ENetHost[/url]. </brief_description> @@ -50,7 +50,7 @@ <argument index="2" name="channels" type="int" default="0" /> <argument index="3" name="data" type="int" default="0" /> <description> - Initiates a connection to a foreign [code]address[/code] using the specified [code]port[/code] and allocting the requested [code]channels[/code]. Optional [code]data[/code] can be passed during connection in the form of a 32 bit integer. + Initiates a connection to a foreign [code]address[/code] using the specified [code]port[/code] and allocating the requested [code]channels[/code]. Optional [code]data[/code] can be passed during connection in the form of a 32 bit integer. [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method. </description> </method> @@ -61,7 +61,7 @@ <argument index="2" name="in_bandwidth" type="int" default="0" /> <argument index="3" name="out_bandwidth" type="int" default="0" /> <description> - Create an ENetHost that will allow up to [code]max_peers[/code] connected peers, each allocating up to [code]max_channels[/code] channels, optionally limiting bandwith to [code]in_bandwidth[/code] and [code]out_bandwidth[/code]. + Create an ENetHost that will allow up to [code]max_peers[/code] connected peers, each allocating up to [code]max_channels[/code] channels, optionally limiting bandwidth to [code]in_bandwidth[/code] and [code]out_bandwidth[/code]. </description> </method> <method name="create_host_bound"> @@ -174,7 +174,7 @@ A connection request initiated by enet_host_connect has completed. The array will contain the peer which successfully connected. </constant> <constant name="EVENT_DISCONNECT" value="2" enum="EventType"> - A peer has disconnected. This event is generated on a successful completion of a disconnect initiated by [method ENetPacketPeer.peer_disconnect], if a peer has timed out, or if a connection request intialized by [method connect_to_host] has timed out. The array will contain the peer which disconnected. The data field contains user supplied data describing the disconnection, or 0, if none is available. + A peer has disconnected. This event is generated on a successful completion of a disconnect initiated by [method ENetPacketPeer.peer_disconnect], if a peer has timed out, or if a connection request initialized by [method connect_to_host] has timed out. The array will contain the peer which disconnected. The data field contains user supplied data describing the disconnection, or 0, if none is available. </constant> <constant name="EVENT_RECEIVE" value="3" enum="EventType"> A packet has been received from a peer. The array will contain the peer which sent the packet, the channel number upon which the packet was received, and the received packet. diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index d2456d3360..2ecf6b4122 100644 --- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> +<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A MultiplayerPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library. </brief_description> @@ -62,7 +62,7 @@ <return type="ENetPacketPeer" /> <argument index="0" name="id" type="int" /> <description> - Return the [ENetPacketPeer] associated to the given [code]id[/code]. + Returns the [ENetPacketPeer] associated to the given [code]id[/code]. </description> </method> <method name="set_bind_ip"> diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml index 4116ba17f2..5de5a60853 100644 --- a/modules/enet/doc_classes/ENetPacketPeer.xml +++ b/modules/enet/doc_classes/ENetPacketPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ENetPacketPeer" inherits="PacketPeer" version="4.0"> +<class name="ENetPacketPeer" inherits="PacketPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A wrapper class for an [url=http://enet.bespin.org/group__peer.html]ENetPeer[/url]. </brief_description> diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp index 62f03b444b..629974d7c7 100644 --- a/modules/enet/enet_connection.cpp +++ b/modules/enet/enet_connection.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h index bffda81906..0c873b6c55 100644 --- a/modules/enet/enet_connection.h +++ b/modules/enet/enet_connection.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index cb22d349f8..cd94cc9425 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -107,7 +107,7 @@ Error ENetMultiplayerPeer::add_mesh_peer(int p_id, Ref<ENetConnection> p_host) { ERR_FAIL_COND_V_MSG(active_mode != MODE_MESH, ERR_UNCONFIGURED, "The multiplayer instance is not configured as a mesh. Call 'create_mesh' first."); List<Ref<ENetPacketPeer>> host_peers; p_host->get_peers(host_peers); - ERR_FAIL_COND_V_MSG(host_peers.size() != 1 || host_peers[0]->get_state() != ENetPacketPeer::STATE_CONNECTED, ERR_INVALID_PARAMETER, "The provided host must have excatly one peer in the connected state."); + ERR_FAIL_COND_V_MSG(host_peers.size() != 1 || host_peers[0]->get_state() != ENetPacketPeer::STATE_CONNECTED, ERR_INVALID_PARAMETER, "The provided host must have exactly one peer in the connected state."); hosts[p_id] = p_host; peers[p_id] = host_peers[0]; emit_signal(SNAME("peer_connected"), p_id); diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index abec1e432e..e7b61169fb 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -103,7 +103,7 @@ public: virtual void poll() override; virtual bool is_server() const override; - // Overriden so we can instrument the DTLSServer when needed. + // Overridden so we can instrument the DTLSServer when needed. virtual void set_refuse_new_connections(bool p_enabled) override; virtual ConnectionStatus get_connection_status() const override; diff --git a/modules/enet/enet_packet_peer.cpp b/modules/enet/enet_packet_peer.cpp index d7d2ec9ebe..62c0550edb 100644 --- a/modules/enet/enet_packet_peer.cpp +++ b/modules/enet/enet_packet_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/enet/enet_packet_peer.h b/modules/enet/enet_packet_peer.h index 9af004de2f..eaf70a276a 100644 --- a/modules/enet/enet_packet_peer.h +++ b/modules/enet/enet_packet_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp index 7570f5b643..14f3374e24 100644 --- a/modules/enet/register_types.cpp +++ b/modules/enet/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,7 +36,11 @@ static bool enet_ok = false; -void register_enet_types() { +void initialize_enet_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + if (enet_initialize() != 0) { ERR_PRINT("ENet initialization failure"); } else { @@ -44,11 +48,15 @@ void register_enet_types() { } GDREGISTER_CLASS(ENetMultiplayerPeer); - GDREGISTER_VIRTUAL_CLASS(ENetPacketPeer); + GDREGISTER_ABSTRACT_CLASS(ENetPacketPeer); GDREGISTER_CLASS(ENetConnection); } -void unregister_enet_types() { +void uninitialize_enet_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + if (enet_ok) { enet_deinitialize(); } diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h index 75f4cba61b..b4f491287d 100644 --- a/modules/enet/register_types.h +++ b/modules/enet/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef ENET_REGISTER_TYPES_H #define ENET_REGISTER_TYPES_H -void register_enet_types(); -void unregister_enet_types(); +#include "modules/register_module_types.h" + +void initialize_enet_module(ModuleInitializationLevel p_level); +void uninitialize_enet_module(ModuleInitializationLevel p_level); #endif // ENET_REGISTER_TYPES_H diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp index aff7538fb6..7d5557d197 100644 --- a/modules/etcpak/image_compress_etcpak.cpp +++ b/modules/etcpak/image_compress_etcpak.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -132,8 +132,39 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua // 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(); + int width = r_img->get_width(); + int height = r_img->get_height(); + + /* + The first mipmap level of a compressed texture must be a multiple of 4. Quote from D3D11.3 spec: + + BC format surfaces are always multiples of full blocks, each block representing 4x4 pixels. + For mipmaps, the top level map is required to be a multiple of 4 size in all dimensions. + The sizes for the lower level maps are computed as they are for all mipmapped surfaces, + and thus may not be a multiple of 4, for example a top level map of 20 results in a second level + map size of 10. For these cases, there is a differing 'physical' size and a 'virtual' size. + The virtual size is that computed for each mip level without adjustment, which is 10 for the example. + The physical size is the virtual size rounded up to the next multiple of 4, which is 12 for the example, + and this represents the actual memory size. The sampling hardware will apply texture address + processing based on the virtual size (using, for example, border color if specified for accesses + beyond 10), and thus for the example case will not access the 11th and 12th row of the resource. + So for mipmap chains when an axis becomes < 4 in size, only texels 'a','b','e','f' + are used for a 2x2 map, and texel 'a' is used for 1x1. Note that this is similar to, but distinct from, + the surface pitch, which can encompass additional padding beyond the physical surface size. + */ + int next_width = width <= 2 ? width : (width + 3) & ~3; + int next_height = height <= 2 ? height : (height + 3) & ~3; + if (next_width != width || next_height != height) { + r_img->resize(next_width, next_height, Image::INTERPOLATE_LANCZOS); + width = r_img->get_width(); + height = r_img->get_height(); + } + // ERR_FAIL_COND(width % 4 != 0 || height % 4 != 0); // FIXME: No longer guaranteed. + // Multiple-of-4 should be guaranteed by above. + // However, power-of-two 3d textures will create Nx2 and Nx1 mipmap levels, + // which are individually compressed Image objects that violate the above rule. + // Hence, we allow Nx1 and Nx2 images through without forcing to multiple-of-4. + 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))); @@ -144,24 +175,48 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua uint8_t *dest_write = dest_data.ptrw(); int mip_count = mipmaps ? Image::get_image_required_mipmaps(width, height, target_format) : 0; + Vector<uint32_t> padded_src; 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); + int orig_mip_w, orig_mip_h; + int mip_ofs = Image::get_image_mipmap_offset_and_dimensions(width, height, target_format, i, orig_mip_w, orig_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; + int mip_w = (orig_mip_w + 3) & ~3; + int mip_h = (orig_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]; + // Pad textures to nearest block by smearing. + if (mip_w != orig_mip_w || mip_h != orig_mip_h) { + padded_src.resize(mip_w * mip_h); + uint32_t *ptrw = padded_src.ptrw(); + int x = 0, y = 0; + for (y = 0; y < orig_mip_h; y++) { + for (x = 0; x < orig_mip_w; x++) { + ptrw[mip_w * y + x] = src_mip_read[orig_mip_w * y + x]; + } + // First, smear in x. + for (; x < mip_w; x++) { + ptrw[mip_w * y + x] = ptrw[mip_w * y + x - 1]; + } + } + // Then, smear in y. + for (; y < mip_h; y++) { + for (x = 0; x < mip_w; x++) { + ptrw[mip_w * y + x] = ptrw[mip_w * y + x - mip_w]; + } + } + // Override the src_mip_read pointer to our temporary Vector. + src_mip_read = padded_src.ptr(); + } 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) { diff --git a/modules/etcpak/image_compress_etcpak.h b/modules/etcpak/image_compress_etcpak.h index ccf157fada..691528c235 100644 --- a/modules/etcpak/image_compress_etcpak.h +++ b/modules/etcpak/image_compress_etcpak.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/etcpak/register_types.cpp b/modules/etcpak/register_types.cpp index d57d2f747a..eaad1e7b01 100644 --- a/modules/etcpak/register_types.cpp +++ b/modules/etcpak/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,11 +32,18 @@ #include "image_compress_etcpak.h" -void register_etcpak_types() { +void initialize_etcpak_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + 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() { +void uninitialize_etcpak_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/etcpak/register_types.h b/modules/etcpak/register_types.h index a9e10a4aae..2048a62737 100644 --- a/modules/etcpak/register_types.h +++ b/modules/etcpak/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,11 @@ #ifndef ETCPAK_REGISTER_TYPES_H #define ETCPAK_REGISTER_TYPES_H -void register_etcpak_types(); -void unregister_etcpak_types(); +#include "modules/register_module_types.h" + +#include "modules/register_module_types.h" + +void initialize_etcpak_module(ModuleInitializationLevel p_level); +void uninitialize_etcpak_module(ModuleInitializationLevel p_level); #endif // ETCPAK_REGISTER_TYPES_H diff --git a/modules/fbx/README.md b/modules/fbx/README.md deleted file mode 100644 index 8eca4bd3c9..0000000000 --- a/modules/fbx/README.md +++ /dev/null @@ -1,196 +0,0 @@ -# Open Source FBX Specification for the Importer - -The goal of this document is to make everything in FBX clearly stated, any errors will be corrected over time this -is a first draft. - -## fbx parser - originally from assimp - -- Folder: /modules/fbx/fbx_parser -- Upstream: assimp -- Original Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019) -- License: BSD-3-Clause - -This can never be updated from upstream, we have heavily modified the parser to provide memory safety and add some -functionality. If anything we should give this parser back to assimp at some point as it has a lot of new features. - -# 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. - -Many days were put into rewriting the parser to use safe code and safe memory accessors. - -# File Headers - -FBX Binaries start with the header "Kaydara FBX Binary" - -FBX ASCII documents contain a larger header, sometimes with copyright information for a file. - -Detecting these is pretty simple. - -# What is an OP link? -It's an object to property link. It lists the properties for that object in some cases. Source and destination based by -ID. - -# What is a OO link? -Its an object to object link, it contains the ID source and destination ID. - -# FBX Node connections - -Nodes in FBX are connected using OO links, This means Object to Object. - -FBX has a single other kind of link which is Object Property, this is used for Object to Property Links, this can be - extra attributes, defaults, or even some simple settings. - -# Bones / Joints / Locators - -Bones in FBX are nodes, they initially have the Model:: Type, then have links to SubDeformer the sub deformer -is part of the skin there is also an explicit Skin link, which then links to the geometry using OO links in the -document. - -# Rotation Order in FBX compared to Godot - -**Godot uses the rotation order:** YXZ - -**FBX has dynamic rotation order to prevent gimbal lock with complex animations** - -```cpp -enum RotOrder { - RotOrder_EulerXYZ = 0 - RotOrder_EulerXZY, - RotOrder_EulerYZX, - RotOrder_EulerYXZ, - RotOrder_EulerZXY, - RotOrder_EulerZYX, - RotOrder_SphericXYZ // nobody uses this - as far as we can tell -}; -``` - - -# Pivot transforms - -### Pivot description: -- Maya and 3DS max consider everything to be in node space (bones joints, skins, lights, cameras, etc) -- Everything is a node, this means essentially nodes are auto or variants -- They are local to the node in the tree. -- They are used to calculate where a node is in space -```c++ -// For a better reference you can check editor_scene_importer_fbx.h -// references: GenFBXTransform / read the data in -// references: ComputePivotTransform / run the calculation -// This is the local pivot transform for the node, not the global transforms -Transform ComputePivotTransform( - Transform3D chain[TransformationComp_MAXIMUM], - Transform3D &geometric_transform) { - // Maya pivots - 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 - 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; - // Calculate standard maya pivots - return T * Roff * Rp * Rpre * R * Rpost.inverse() * Rp.inverse() * Soff * Sp * S * Sp.inverse(); -} -``` - -# Transform inheritance for FBX Nodes - -The goal of below is to explain why they implement this in the first place. - -The use case is to make nodes have an option to override their local scaling or to make scaling influenced by orientation, which i would imagine would be useful for when you need to rotate a node and the child to scale based on the orientation rather than setting on the rotation matrix planes. -```cpp -// not modified the formatting here since this code must remain clear -enum TransformInheritance { - Transform_RrSs = 0, - // Parent Rotation * Local Rotation * Parent Scale * Local Scale -- Parent Rotation Offset * Parent ScalingOffset (Local scaling is offset by rotation of parent node) - Transform_RSrs = 1, // Parent Rotation * Parent Scale * Local Rotation * Local Scale -- Parent * Local (normal mode) - Transform_Rrs = 2, // Parent Rotation * Local Rotation * Local Scale -- Node transform scale is the only relevant component - TransformInheritance_MAX // end-of-enum sentinel -}; - -enum TransformInheritance { - Transform_RrSs = 0, - // Local scaling is offset by rotation of parent node - Transform_RSrs = 1, - // Parent * Local (normal mode) - Transform_Rrs = 2, - // Node transform scale is the only relevant component - TransformInheritance_MAX // end-of-enum sentinel -}; -``` - -# Axis in FBX - -Godot has one format for the declared axis - -AXIS X, AXIS Y, -AXIS Z - -FBX supports any format you can think of. As it has to support Maya and 3DS Max. - -#### FBX File Header -```json -GlobalSettings: { - Version: 1000 - Properties70: { - P: "UpAxis", "int", "Integer", "",1 - P: "UpAxisSign", "int", "Integer", "",1 - P: "FrontAxis", "int", "Integer", "",2 - P: "FrontAxisSign", "int", "Integer", "",1 - P: "CoordAxis", "int", "Integer", "",0 - P: "CoordAxisSign", "int", "Integer", "",1 - P: "OriginalUpAxis", "int", "Integer", "",1 - P: "OriginalUpAxisSign", "int", "Integer", "",1 - P: "UnitScaleFactor", "double", "Number", "",1 - P: "OriginalUnitScaleFactor", "double", "Number", "",1 - P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 - P: "DefaultCamera", "KString", "", "", "Producer Perspective" - P: "TimeMode", "enum", "", "",6 - P: "TimeProtocol", "enum", "", "",2 - P: "SnapOnFrameMode", "enum", "", "",0 - P: "TimeSpanStart", "KTime", "Time", "",0 - P: "TimeSpanStop", "KTime", "Time", "",92372316000 - P: "CustomFrameRate", "double", "Number", "",-1 - P: "TimeMarker", "Compound", "", "" - P: "CurrentTimeMarker", "int", "Integer", "",-1 - } -} -``` - -#### FBX FILE declares axis dynamically using FBX header -Coord is X -Up is Y -Front is Z - -#### GODOT - constant reference point -Coord is X positive, -Y is up positive, -Front is -Z negative - -### Explaining MeshGeometry indexing - -Reference type declared: -- Direct (directly related to the mapping information type) -- IndexToDirect (Map with key value, meaning depends on the MappingInformationType) - -ControlPoint is a vertex -* None The mapping is undetermined. -* ByVertex There will be one mapping coordinate for each surface control point/vertex. - * 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. - * One mapping per polygon polygon x has this normal x - * For each vertex of the polygon then set the normal to x -* ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id) -* AllSame There can be only one mapping coordinate for the whole surface. diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub deleted file mode 100644 index 0311fddfee..0000000000 --- a/modules/fbx/SCsub +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -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") -env_fbx.add_source_files(env.modules_sources, "fbx_parser/*.cpp") -env_fbx.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/fbx/config.py b/modules/fbx/config.py deleted file mode 100644 index 78929800b3..0000000000 --- a/modules/fbx/config.py +++ /dev/null @@ -1,16 +0,0 @@ -def can_build(env, platform): - return env["tools"] - - -def configure(env): - pass - - -def get_doc_classes(): - return [ - "EditorSceneImporterFBX", - ] - - -def get_doc_path(): - return "doc_classes" diff --git a/modules/fbx/data/fbx_anim_container.h b/modules/fbx/data/fbx_anim_container.h deleted file mode 100644 index 8c25d65871..0000000000 --- a/modules/fbx/data/fbx_anim_container.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************/ -/* fbx_anim_container.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 FBX_ANIM_CONTAINER_H -#define FBX_ANIM_CONTAINER_H - -#include "core/math/vector3.h" - -// Generic keyframes 99.99 percent of files will be vector3, except if quat interp is used, or visibility tracks -// FBXTrack is used in a map in the implementation in fbx/editor_scene_importer_fbx.cpp -// to avoid having to rewrite the entire logic I refactored this into the code instead. -// once it works I can rewrite so we can add the fun misc features / small features -struct FBXTrack { - bool has_default = false; - Vector3 default_value; - std::map<int64_t, Vector3> keyframes; -}; - -#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H diff --git a/modules/fbx/data/fbx_bone.cpp b/modules/fbx/data/fbx_bone.cpp deleted file mode 100644 index 38dada33af..0000000000 --- a/modules/fbx/data/fbx_bone.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************/ -/* fbx_bone.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 "fbx_bone.h" - -#include "fbx_node.h" -#include "import_state.h" - -Ref<FBXNode> FBXSkinDeformer::get_link(const ImportState &state) const { - print_verbose("bone name: " + bone->bone_name); - - // safe for when deformers must be polyfilled when skin has different count of binds to bones in the scene ;) - if (!cluster) { - return nullptr; - } - - ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node"); - - Ref<FBXNode> link_node; - uint64_t id = cluster->TargetNode()->ID(); - if (state.fbx_target_map.has(id)) { - link_node = state.fbx_target_map[id]; - } else { - print_error("link node not found for " + itos(id)); - } - - // the node in space this is for, like if it's FOR a target. - return link_node; -} diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h deleted file mode 100644 index 83918ad1e2..0000000000 --- a/modules/fbx/data/fbx_bone.h +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************/ -/* fbx_bone.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 FBX_BONE_H -#define FBX_BONE_H - -#include "fbx_node.h" -#include "import_state.h" - -#include "fbx_parser/FBXDocument.h" - -struct PivotTransform; - -struct FBXBone : public RefCounted { - uint64_t parent_bone_id = 0; - uint64_t bone_id = 0; - - bool valid_parent = false; // if the parent bone id is set up. - String bone_name = String(); // bone name - - bool is_root_bone() const { - return !valid_parent; - } - - // Godot specific data - int godot_bone_id = -2; // godot internal bone id assigned after import - - // if a bone / armature is the root then FBX skeleton will contain the bone not any other skeleton. - // this is to support joints by themselves in scenes - bool valid_armature_id = false; - uint64_t armature_id = 0; - - /* link node is the parent bone */ - mutable const FBXDocParser::Geometry *geometry = nullptr; - mutable const FBXDocParser::ModelLimbNode *limb_node = nullptr; - - void set_node(Ref<FBXNode> p_node) { - node = p_node; - } - - // Stores the pivot xform for this bone - - Ref<FBXNode> node = nullptr; - Ref<FBXBone> parent_bone = nullptr; - Ref<FBXSkeleton> fbx_skeleton = nullptr; -}; - -struct FBXSkinDeformer { - FBXSkinDeformer(Ref<FBXBone> p_bone, const FBXDocParser::Cluster *p_cluster) : - cluster(p_cluster), bone(p_bone) {} - ~FBXSkinDeformer() {} - const FBXDocParser::Cluster *cluster; - Ref<FBXBone> bone; - - /* get associate model - the model can be invalid sometimes */ - Ref<FBXBone> get_associate_model() const { - return bone->parent_bone; - } - - Ref<FBXNode> get_link(const ImportState &state) const; -}; - -#endif // FBX_BONE_H diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp deleted file mode 100644 index 26c9ef8d54..0000000000 --- a/modules/fbx/data/fbx_material.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/*************************************************************************/ -/* fbx_material.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 "fbx_material.h" - -// FIXME: Shouldn't depend on core_bind.h! Use DirAccessRef like the rest of -// the engine instead of core_bind::Directory. -#include "core/core_bind.h" -#include "scene/resources/material.h" -#include "scene/resources/texture.h" -#include "tools/validation_tools.h" - -String FBXMaterial::get_material_name() const { - return material_name; -} - -void FBXMaterial::set_imported_material(FBXDocParser::Material *p_material) { - material = p_material; -} - -void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths) { - if (search_directory.is_empty()) { - texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(p_filename)); - } else { - texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(search_directory + "/" + p_filename)); - texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file("../" + search_directory + "/" + p_filename)); - } -} - -String find_file(const String &p_base, const String &p_file_to_find) { - core_bind::Directory dir; - dir.open(p_base); - - dir.list_dir_begin(); - String n = dir.get_next(); - while (!n.is_empty()) { - if (n == "." || n == "..") { - n = dir.get_next(); - continue; - } - if (dir.current_is_dir()) { - // Don't use `path_to` or the returned path will be wrong. - const String f = find_file(p_base + "/" + n, p_file_to_find); - if (!f.is_empty()) { - return f; - } - } else if (n == p_file_to_find) { - return p_base + "/" + n; - } - n = dir.get_next(); - } - dir.list_dir_end(); - - return String(); -} - -// fbx will not give us good path information and let's not regex them to fix them -// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK. -String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) { - core_bind::Directory dir; - Vector<String> paths; - add_search_string(p_filename, p_current_directory, "", paths); - add_search_string(p_filename, p_current_directory, "texture", paths); - add_search_string(p_filename, p_current_directory, "textures", paths); - add_search_string(p_filename, p_current_directory, "Textures", paths); - add_search_string(p_filename, p_current_directory, "materials", paths); - add_search_string(p_filename, p_current_directory, "mats", paths); - add_search_string(p_filename, p_current_directory, "pictures", paths); - add_search_string(p_filename, p_current_directory, "images", paths); - - for (int i = 0; i < paths.size(); i++) { - if (dir.file_exists(paths[i])) { - return paths[i]; - } - } - - // We were not able to find the texture in the common locations, - // try to find it into the project globally. - // The common textures can be stored into one of those folders: - // res://asset - // res://texture - // res://material - // res://mat - // res://image - // res://picture - // - // Note the folders can also be called with custom names, like: - // res://my_assets - // since the keyword `asset` is into the directory name the textures will be - // searched there too. - - dir.open("res://"); - dir.list_dir_begin(); - String n = dir.get_next(); - while (!n.is_empty()) { - if (n == "." || n == "..") { - n = dir.get_next(); - continue; - } - if (dir.current_is_dir()) { - const String lower_n = n.to_lower(); - if ( - // Don't need to use plural. - lower_n.find("asset") >= 0 || - lower_n.find("texture") >= 0 || - lower_n.find("material") >= 0 || - lower_n.find("mat") >= 0 || - lower_n.find("image") >= 0 || - lower_n.find("picture") >= 0) { - // Don't use `path_to` or the returned path will be wrong. - const String f = find_file(String("res://") + n, p_filename); - if (!f.is_empty()) { - return f; - } - } - } - n = dir.get_next(); - } - dir.list_dir_end(); - - return ""; -} - -template <class T> -T extract_from_prop(FBXDocParser::PropertyPtr prop, const T &p_default, const std::string &p_name, const String &p_type) { - ERR_FAIL_COND_V_MSG(prop == nullptr, p_default, "invalid property passed to extractor"); - const FBXDocParser::TypedProperty<T> *val = dynamic_cast<const FBXDocParser::TypedProperty<T> *>(prop); - - ERR_FAIL_COND_V_MSG(val == nullptr, p_default, "The FBX is corrupted, the property `" + String(p_name.c_str()) + "` is a `" + String(typeid(*prop).name()) + "` but should be a " + p_type); - // Make sure to not lost any eventual opacity. - return val->Value(); -} - -Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { - ERR_FAIL_COND_V(material == nullptr, nullptr); - - const String p_fbx_current_directory = state.path; - - Ref<StandardMaterial3D> spatial_material; - spatial_material.instantiate(); - - // read the material file - // is material two sided - // read material name - print_verbose("[material] material name: " + ImportUtils::FBXNodeToName(material->Name())); - - material_name = ImportUtils::FBXNodeToName(material->Name()); - - for (const std::pair<std::string, const FBXDocParser::Texture *> iter : material->Textures()) { - const uint64_t texture_id = iter.second->ID(); - const std::string &fbx_mapping_name = iter.first; - const FBXDocParser::Texture *fbx_texture_data = iter.second; - const String absolute_texture_path = iter.second->FileName().c_str(); - const String texture_name = absolute_texture_path.get_file(); - const String file_extension = absolute_texture_path.get_extension().to_upper(); - - const String debug_string = "texture id: " + itos(texture_id) + " texture name: " + String(iter.second->Name().c_str()) + " mapping name: " + String(fbx_mapping_name.c_str()); - // remember errors STILL need this string at the end for when you aren't in verbose debug mode :) they need context for when you're not verbose-ing. - print_verbose(debug_string); - - const String file_extension_uppercase = file_extension.to_upper(); - - if (fbx_transparency_flags.count(fbx_mapping_name) > 0) { - // just enable it later let's make this fine-tuned. - spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA); - } - - ERR_CONTINUE_MSG(file_extension.is_empty(), "your texture has no file extension so we had to ignore it, let us know if you think this is wrong file an issue on github! " + debug_string); - ERR_CONTINUE_MSG(fbx_texture_map.count(fbx_mapping_name) <= 0, "This material has a texture with mapping name: " + String(fbx_mapping_name.c_str()) + " which is not yet supported by this importer. Consider opening an issue so we can support it."); - ERR_CONTINUE_MSG( - file_extension_uppercase != "PNG" && - file_extension_uppercase != "JPEG" && - file_extension_uppercase != "JPG" && - file_extension_uppercase != "TGA" && - file_extension_uppercase != "WEBP" && - file_extension_uppercase != "DDS", - "The FBX file contains a texture with an unrecognized extension: " + file_extension_uppercase); - - print_verbose("Getting FBX mapping mode for " + String(fbx_mapping_name.c_str())); - // get the texture map type - const StandardMaterial3D::TextureParam mapping_mode = fbx_texture_map.at(fbx_mapping_name); - print_verbose("Set FBX mapping mode to " + get_texture_param_name(mapping_mode)); - - Ref<Texture> texture; - print_verbose("texture mapping name: " + texture_name); - - if (state.cached_image_searches.has(texture_name)) { - texture = state.cached_image_searches[texture_name]; - } else { - String path = find_texture_path_by_filename(texture_name, p_fbx_current_directory); - if (!path.is_empty()) { - Ref<Texture2D> image_texture = ResourceLoader::load(path); - - ERR_CONTINUE(image_texture.is_null()); - - texture = image_texture; - state.cached_image_searches.insert(texture_name, texture); - print_verbose("Created texture from loaded image file."); - - } 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.instantiate(); // oooo double instance bug? why make Image::_png_blah call - - const String extension = texture_name.get_extension().to_upper(); - if (extension == "PNG") { - // The stored file is a PNG. - image = Image::_png_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded PNG image load fail."); - - } else if ( - extension == "JPEG" || - extension == "JPG") { - // The stored file is a JPEG. - image = Image::_jpg_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded JPEG image load fail."); - - } else if (extension == "TGA") { - // The stored file is a TGA. - image = Image::_tga_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail."); - - } else if (extension == "WEBP") { - // The stored file is a WEBP. - image = Image::_webp_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded WEBP image load fail."); - - // } else if (extension == "DDS") { - // // In this moment is not possible to extract a DDS from a buffer, TODO consider add it to godot. See `textureloader_dds.cpp::load(). - // // The stored file is a DDS. - } else { - ERR_CONTINUE_MSG(true, "The embedded image with extension: " + extension + " is not yet supported. Open an issue please."); - } - - Ref<ImageTexture> image_texture; - image_texture.instantiate(); - image_texture->create_from_image(image); - - texture = image_texture; - - // TODO: this is potentially making something with the same name have a match incorrectly USE FBX ID as Hash. #fuck it later. - state.cached_image_searches[texture_name] = texture; - print_verbose("Created texture from embedded image."); - } else { - ERR_CONTINUE_MSG(true, "The FBX texture, with name: `" + texture_name + "`, is not found into the project nor is stored as embedded file. Make sure to insert the texture as embedded file or into the project, then reimport."); - } - } - - spatial_material->set_texture(mapping_mode, texture); - } - - if (spatial_material.is_valid()) { - spatial_material->set_name(material_name); - } - - /// ALL below is related to properties - for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) { - const std::string name = iter.first; - - if (name.empty()) { - continue; - } - - PropertyDesc desc = PROPERTY_DESC_NOT_FOUND; - if (fbx_properties_desc.count(name) > 0) { - desc = fbx_properties_desc.at(name); - } - - // check if we can ignore this it will be done at the next phase - if (desc == PROPERTY_DESC_NOT_FOUND || desc == PROPERTY_DESC_IGNORE) { - // count the texture mapping references. Skip this one if it's found and we can't look up a property value. - if (fbx_texture_map.count(name) > 0) { - continue; // safe to ignore it's a texture mapping. - } - } - - if (desc == PROPERTY_DESC_IGNORE) { - //WARN_PRINT("[Ignored] The FBX material parameter: `" + String(name.c_str()) + "` is ignored."); - continue; - } else { - print_verbose("FBX Material parameter: " + String(name.c_str())); - - // Check for Diffuse material system / lambert materials / legacy basically - if (name == "Diffuse" && !warning_non_pbr_material) { - ValidationTracker::get_singleton()->add_validation_error(state.path, "Invalid material settings change to Ai Standard Surface shader, mat name: " + material_name.c_escape()); - warning_non_pbr_material = true; - } - } - - // DISABLE when adding support for all weird and wonderful material formats - if (desc == PROPERTY_DESC_NOT_FOUND) { - continue; - } - - 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; - 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.instantiate(); - } - - const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop); - const FBXDocParser::TypedProperty<Vector3> *vector_value = dynamic_cast<const FBXDocParser::TypedProperty<Vector3> *>(prop); - - if (!real_value && !vector_value) { - //WARN_PRINT("unsupported datatype in property: " + String(name.c_str())); - continue; - } - - if (vector_value && !real_value) { - if (vector_value->Value() == Vector3(0, 0, 0) && !real_value) { - continue; - } - } - - switch (desc) { - case PROPERTY_DESC_ALBEDO_COLOR: { - if (vector_value) { - const Vector3 &color = vector_value->Value(); - // Make sure to not lost any eventual opacity. - if (color != Vector3(0, 0, 0)) { - Color c = Color(); - c[0] = color[0]; - c[1] = color[1]; - c[2] = color[2]; - spatial_material->set_albedo(c); - } - - } else if (real_value) { - print_error("albedo is unsupported format?"); - } - } break; - case PROPERTY_DESC_TRANSPARENT: { - if (real_value) { - const real_t opacity = real_value->Value(); - if (opacity < (1.0 - CMP_EPSILON)) { - Color c = spatial_material->get_albedo(); - c.a = opacity; - spatial_material->set_albedo(c); - - spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA); - spatial_material->set_depth_draw_mode(BaseMaterial3D::DEPTH_DRAW_OPAQUE_ONLY); - } - } else if (vector_value) { - print_error("unsupported transparent desc type vector!"); - } - } break; - case PROPERTY_DESC_SPECULAR: { - if (real_value) { - print_verbose("specular real value: " + rtos(real_value->Value())); - spatial_material->set_specular(MIN(1.0, real_value->Value())); - } - - if (vector_value) { - print_error("unsupported specular vector value: " + vector_value->Value()); - } - } break; - - case PROPERTY_DESC_SPECULAR_COLOR: { - if (vector_value) { - print_error("unsupported specular color: " + vector_value->Value()); - } - } break; - case PROPERTY_DESC_SHINYNESS: { - if (real_value) { - print_error("unsupported shinyness:" + rtos(real_value->Value())); - } - } break; - case PROPERTY_DESC_METALLIC: { - if (real_value) { - print_verbose("metallic real value: " + rtos(real_value->Value())); - spatial_material->set_metallic(MIN(1.0f, real_value->Value())); - } else { - print_error("unsupported value type for metallic"); - } - } break; - case PROPERTY_DESC_ROUGHNESS: { - if (real_value) { - print_verbose("roughness real value: " + rtos(real_value->Value())); - spatial_material->set_roughness(MIN(1.0f, real_value->Value())); - } else { - print_error("unsupported value type for roughness"); - } - } break; - case PROPERTY_DESC_COAT: { - if (real_value) { - print_verbose("clearcoat real value: " + rtos(real_value->Value())); - spatial_material->set_clearcoat(MIN(1.0f, real_value->Value())); - } else { - print_error("unsupported value type for clearcoat"); - } - } break; - case PROPERTY_DESC_COAT_ROUGHNESS: { - // meaning is that approx equal to zero is disabled not actually zero. ;) - 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 { - print_error("unsupported value type for clearcoat gloss"); - } - } break; - case PROPERTY_DESC_EMISSIVE: { - 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))) { - const Vector3 &color = vector_value->Value(); - Color c; - c[0] = color[0]; - c[1] = color[1]; - c[2] = color[2]; - spatial_material->set_emission(c); - } - } break; - case PROPERTY_DESC_EMISSIVE_COLOR: { - if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) { - const Vector3 &color = vector_value->Value(); - Color c; - c[0] = color[0]; - c[1] = color[1]; - c[2] = color[2]; - spatial_material->set_emission(c); - } else { - print_error("unsupported value type for emissive color"); - } - } break; - case PROPERTY_DESC_NOT_FOUND: - case PROPERTY_DESC_IGNORE: - break; - default: - break; - } - } - - return spatial_material; -} diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h deleted file mode 100644 index 5fd4d9212b..0000000000 --- a/modules/fbx/data/fbx_material.h +++ /dev/null @@ -1,285 +0,0 @@ -/*************************************************************************/ -/* fbx_material.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 FBX_MATERIAL_H -#define FBX_MATERIAL_H - -#include "tools/import_utils.h" - -#include "core/object/ref_counted.h" -#include "core/string/ustring.h" - -struct FBXMaterial : public RefCounted { - String material_name = String(); - bool warning_non_pbr_material = false; - FBXDocParser::Material *material = nullptr; - - /* Godot materials - *** Texture Maps: - * Albedo - color, texture - * Metallic - specular, metallic, texture - * Roughness - roughness, texture - * Emission - color, texture - * Normal Map - scale, texture - * Ambient Occlusion - texture - * Refraction - scale, texture - *** Has Settings for: - * UV1 - SCALE, OFFSET - * UV2 - SCALE, OFFSET - *** Flags for - * Transparent - * Cull Mode - */ - - enum class MapMode { - AlbedoM = 0, - MetallicM, - SpecularM, - EmissionM, - RoughnessM, - NormalM, - AmbientOcclusionM, - RefractionM, - ReflectionM, - }; - - /* Returns the string representation of the TextureParam enum */ - static String get_texture_param_name(StandardMaterial3D::TextureParam param) { - switch (param) { - case StandardMaterial3D::TEXTURE_ALBEDO: - return "TEXTURE_ALBEDO"; - case StandardMaterial3D::TEXTURE_METALLIC: - return "TEXTURE_METALLIC"; - case StandardMaterial3D::TEXTURE_ROUGHNESS: - return "TEXTURE_ROUGHNESS"; - case StandardMaterial3D::TEXTURE_EMISSION: - return "TEXTURE_EMISSION"; - case StandardMaterial3D::TEXTURE_NORMAL: - return "TEXTURE_NORMAL"; - case StandardMaterial3D::TEXTURE_RIM: - return "TEXTURE_RIM"; - case StandardMaterial3D::TEXTURE_CLEARCOAT: - return "TEXTURE_CLEARCOAT"; - case StandardMaterial3D::TEXTURE_FLOWMAP: - return "TEXTURE_FLOWMAP"; - case StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION: - return "TEXTURE_AMBIENT_OCCLUSION"; - // case StandardMaterial3D::TEXTURE_DEPTH: // TODO: work out how to make this function again! - // return "TEXTURE_DEPTH"; - case StandardMaterial3D::TEXTURE_SUBSURFACE_SCATTERING: - return "TEXTURE_SUBSURFACE_SCATTERING"; - // case StandardMaterial3D::TEXTURE_TRANSMISSION: // TODO: work out how to make this function again! - // return "TEXTURE_TRANSMISSION"; - case StandardMaterial3D::TEXTURE_REFRACTION: - return "TEXTURE_REFRACTION"; - case StandardMaterial3D::TEXTURE_DETAIL_MASK: - return "TEXTURE_DETAIL_MASK"; - case StandardMaterial3D::TEXTURE_DETAIL_ALBEDO: - return "TEXTURE_DETAIL_ALBEDO"; - case StandardMaterial3D::TEXTURE_DETAIL_NORMAL: - return "TEXTURE_DETAIL_NORMAL"; - case StandardMaterial3D::TEXTURE_MAX: - return "TEXTURE_MAX"; - default: - return "broken horribly"; - } - }; - - // TODO make this static? - const std::map<std::string, bool> fbx_transparency_flags = { - /* Transparent */ - { "TransparentColor", true }, - { "Maya|opacity", true } - }; - - // TODO make this static? - const std::map<std::string, StandardMaterial3D::TextureParam> fbx_texture_map = { - /* Diffuse */ - { "Maya|base", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "DiffuseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|DiffuseTexture", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|baseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|baseColor|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "3dsMax|Parameters|base_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|TEX_color_map|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|TEX_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - /* Emission */ - { "EmissiveColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "EmissiveFactor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|emissionColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|emissionColor|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "3dsMax|Parameters|emission_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|TEX_emissive_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|TEX_emissive_map|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - /* Metallic */ - { "Maya|metalness", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "Maya|metalness|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "3dsMax|Parameters|metalness_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "Maya|TEX_metallic_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "Maya|TEX_metallic_map|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - - /* Roughness */ - // Arnold Roughness Map - { "Maya|specularRoughness", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - - { "3dsMax|Parameters|roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - { "Maya|TEX_roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - { "Maya|TEX_roughness_map|file", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - - /* Normal */ - { "NormalMap", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - //{ "Bump", Material::TextureParam::TEXTURE_NORMAL }, - //{ "3dsMax|Parameters|bump_map", Material::TextureParam::TEXTURE_NORMAL }, - { "Maya|NormalTexture", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - //{ "Maya|normalCamera", Material::TextureParam::TEXTURE_NORMAL }, - //{ "Maya|normalCamera|file", Material::TextureParam::TEXTURE_NORMAL }, - { "Maya|TEX_normal_map", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - { "Maya|TEX_normal_map|file", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - /* AO */ - { "Maya|TEX_ao_map", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION }, - { "Maya|TEX_ao_map|file", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION }, - - // TODO: specular workflow conversion - // { "SpecularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "Maya|specularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "Maya|SpecularTexture", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "Maya|SpecularTexture|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "ShininessExponent", SpatialMaterial::TextureParam::UNSUPPORTED }, - // { "ReflectionFactor", SpatialMaterial::TextureParam::UNSUPPORTED }, - - //{ "TransparentColor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA }, - //{ "TransparencyFactor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA } - - // TODO: diffuse roughness - //{ "Maya|diffuseRoughness", SpatialMaterial::TextureParam::UNSUPPORTED }, - //{ "Maya|diffuseRoughness|file", SpatialMaterial::TextureParam::UNSUPPORTED }, - - }; - - // TODO make this static? - enum PropertyDesc { - PROPERTY_DESC_NOT_FOUND, - PROPERTY_DESC_ALBEDO_COLOR, - PROPERTY_DESC_TRANSPARENT, - PROPERTY_DESC_METALLIC, - PROPERTY_DESC_ROUGHNESS, - PROPERTY_DESC_SPECULAR, - PROPERTY_DESC_SPECULAR_COLOR, - PROPERTY_DESC_SHINYNESS, - PROPERTY_DESC_COAT, - PROPERTY_DESC_COAT_ROUGHNESS, - PROPERTY_DESC_EMISSIVE, - PROPERTY_DESC_EMISSIVE_COLOR, - PROPERTY_DESC_IGNORE - }; - - const std::map<std::string, PropertyDesc> fbx_properties_desc = { - /* Albedo */ - { "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR }, - { "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR }, - - /* Specular */ - { "Maya|specular", PROPERTY_DESC_SPECULAR }, - { "Maya|specularColor", PROPERTY_DESC_SPECULAR_COLOR }, - - /* Specular roughness - arnold roughness map */ - { "Maya|specularRoughness", PROPERTY_DESC_ROUGHNESS }, - - /* Transparent */ - { "Opacity", PROPERTY_DESC_TRANSPARENT }, - { "TransparencyFactor", PROPERTY_DESC_TRANSPARENT }, - { "Maya|opacity", PROPERTY_DESC_TRANSPARENT }, - - { "Maya|metalness", PROPERTY_DESC_METALLIC }, - { "Maya|metallic", PROPERTY_DESC_METALLIC }, - - /* Roughness */ - { "Maya|roughness", PROPERTY_DESC_ROUGHNESS }, - - /* Coat */ - //{ "Maya|coat", PROPERTY_DESC_COAT }, - - /* Coat roughness */ - //{ "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS }, - - /* Emissive */ - { "Maya|emission", PROPERTY_DESC_EMISSIVE }, - { "Maya|emissive", PROPERTY_DESC_EMISSIVE }, - - /* Emissive color */ - { "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR }, - { "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR }, - - /* Ignore */ - { "Shininess", PROPERTY_DESC_IGNORE }, - { "Reflectivity", PROPERTY_DESC_IGNORE }, - { "Maya|diffuseRoughness", PROPERTY_DESC_IGNORE }, - { "Maya", PROPERTY_DESC_IGNORE }, - { "Diffuse", PROPERTY_DESC_ALBEDO_COLOR }, - { "Maya|TypeId", PROPERTY_DESC_IGNORE }, - { "Ambient", PROPERTY_DESC_IGNORE }, - { "AmbientColor", PROPERTY_DESC_IGNORE }, - { "ShininessExponent", PROPERTY_DESC_IGNORE }, - { "Specular", PROPERTY_DESC_IGNORE }, - { "SpecularColor", PROPERTY_DESC_IGNORE }, - { "SpecularFactor", PROPERTY_DESC_IGNORE }, - //{ "BumpFactor", PROPERTY_DESC_IGNORE }, - { "Maya|exitToBackground", PROPERTY_DESC_IGNORE }, - { "Maya|indirectDiffuse", PROPERTY_DESC_IGNORE }, - { "Maya|indirectSpecular", PROPERTY_DESC_IGNORE }, - { "Maya|internalReflections", PROPERTY_DESC_IGNORE }, - { "DiffuseFactor", PROPERTY_DESC_IGNORE }, - { "AmbientFactor", PROPERTY_DESC_IGNORE }, - { "ReflectionColor", PROPERTY_DESC_IGNORE }, - { "Emissive", PROPERTY_DESC_IGNORE }, - { "Maya|coatColor", PROPERTY_DESC_IGNORE }, - { "Maya|coatNormal", PROPERTY_DESC_IGNORE }, - { "Maya|coatIOR", PROPERTY_DESC_IGNORE }, - }; - - /* storing the texture properties like color */ - template <class T> - struct TexturePropertyMapping : RefCounted { - StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO; - const T property = T(); - }; - - static void add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths); - - static String find_texture_path_by_filename(const String p_filename, const String p_current_directory); - - String get_material_name() const; - - void set_imported_material(FBXDocParser::Material *p_material); - - Ref<StandardMaterial3D> import_material(ImportState &state); -}; - -#endif // FBX_MATERIAL_H diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp deleted file mode 100644 index e1eacc68b3..0000000000 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ /dev/null @@ -1,1435 +0,0 @@ -/*************************************************************************/ -/* fbx_mesh_data.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 "fbx_mesh_data.h" - -#include "core/templates/local_vector.h" -#include "scene/resources/importer_mesh.h" -#include "scene/resources/mesh.h" -#include "scene/resources/surface_tool.h" - -#include "thirdparty/misc/polypartition.h" - -template <class T> -T collect_first(const Vector<VertexData<T>> *p_data, T p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - return (*p_data)[0].data; -} - -template <class T> -HashMap<int, T> collect_all(const Vector<VertexData<T>> *p_data, HashMap<int, T> p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - HashMap<int, T> collection; - for (int i = 0; i < p_data->size(); i += 1) { - const VertexData<T> &vd = (*p_data)[i]; - collection[vd.polygon_index] = vd.data; - } - return collection; -} - -template <class T> -T collect_average(const Vector<VertexData<T>> *p_data, T p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - T combined = (*p_data)[0].data; // Make sure the data is always correctly initialized. - print_verbose("size of data: " + itos(p_data->size())); - for (int i = 1; i < p_data->size(); i += 1) { - combined += (*p_data)[i].data; - } - combined = combined / real_t(p_data->size()); - - return combined.normalized(); -} - -HashMap<int, Vector3> collect_normal(const Vector<VertexData<Vector3>> *p_data, HashMap<int, Vector3> p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - HashMap<int, Vector3> collection; - for (int i = 0; i < p_data->size(); i += 1) { - const VertexData<Vector3> &vd = (*p_data)[i]; - collection[vd.polygon_index] = vd.data; - } - return collection; -} - -HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, HashMap<int, Vector2> p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - HashMap<int, Vector2> collection; - for (int i = 0; i < p_data->size(); i += 1) { - const VertexData<Vector2> &vd = (*p_data)[i]; - collection[vd.polygon_index] = vd.data; - } - return collection; -} - -ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) { - mesh_geometry = p_mesh_geometry; - // todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately. - const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials(); - - // TODO: perf hotspot on large files - // this can be a very large copy - std::vector<int> polygon_indices = mesh_geometry->get_polygon_indices(); - std::vector<Vector3> vertices = mesh_geometry->get_vertices(); - - // Phase 1. Parse all FBX data. - HashMap<int, Vector3> normals; - HashMap<int, HashMap<int, Vector3>> normals_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_normals(), - &collect_all, - HashMap<int, Vector3>()); - - HashMap<int, Vector2> uvs_0; - HashMap<int, HashMap<int, Vector2>> uvs_0_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_uv_0(), - &collect_all, - HashMap<int, Vector2>()); - - HashMap<int, Vector2> uvs_1; - HashMap<int, HashMap<int, Vector2>> uvs_1_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_uv_1(), - &collect_all, - HashMap<int, Vector2>()); - - HashMap<int, Color> colors; - HashMap<int, HashMap<int, Color>> colors_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_colors(), - &collect_all, - HashMap<int, Color>()); - - // TODO what about tangents? - // TODO what about bi-nomials? - // TODO there is other? - - HashMap<int, SurfaceId> polygon_surfaces = extract_per_polygon( - vertices.size(), - polygon_indices, - mesh_geometry->get_material_allocation_id(), - -1); - - HashMap<String, MorphVertexData> morphs; - extract_morphs(mesh_geometry, morphs); - - // TODO please add skinning. - //mesh_id = mesh_geometry->ID(); - - sanitize_vertex_weights(state); - - // Re organize polygon vertices to to correctly take into account strange - // UVs. - reorganize_vertices( - polygon_indices, - vertices, - normals, - uvs_0, - uvs_1, - colors, - morphs, - normals_raw, - colors_raw, - uvs_0_raw, - uvs_1_raw); - - const int color_count = colors.size(); - print_verbose("Vertex color count: " + itos(color_count)); - - // Make sure that from this moment on the mesh_geometry is no used anymore. - // This is a safety step, because the mesh_geometry data are no more valid - // at this point. - - const int vertex_count = vertices.size(); - - print_verbose("Vertex count: " + itos(vertex_count)); - - // The map key is the material allocator id that is also used as surface id. - HashMap<SurfaceId, SurfaceData> surfaces; - - // Phase 2. For each material create a surface tool (So a different mesh). - { - if (polygon_surfaces.is_empty()) { - // No material, just use the default one with index -1. - // Set -1 to all polygons. - const int polygon_count = count_polygons(polygon_indices); - for (int p = 0; p < polygon_count; p += 1) { - polygon_surfaces[p] = -1; - } - } - - // Create the surface now. - for (const int *polygon_id = polygon_surfaces.next(nullptr); polygon_id != nullptr; polygon_id = polygon_surfaces.next(polygon_id)) { - const int surface_id = polygon_surfaces[*polygon_id]; - if (surfaces.has(surface_id) == false) { - SurfaceData sd; - sd.surface_tool.instantiate(); - sd.surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); - - if (surface_id < 0) { - // nothing to do - } else if (surface_id < (int)material_lookup.size()) { - const FBXDocParser::Material *mat_mapping = material_lookup.at(surface_id); - const uint64_t mapping_id = mat_mapping->ID(); - if (state.cached_materials.has(mapping_id)) { - sd.material = state.cached_materials[mapping_id]; - } - } else { - WARN_PRINT("out of bounds surface detected, FBX file has corrupt material data"); - } - - surfaces.set(surface_id, sd); - } - } - } - - // Phase 3. Map the vertices relative to each surface, in this way we can - // just insert the vertices that we need per each surface. - { - PolygonId polygon_index = -1; - SurfaceId surface_id = -1; - SurfaceData *surface_data = nullptr; - - for (size_t polygon_vertex = 0; polygon_vertex < polygon_indices.size(); polygon_vertex += 1) { - if (is_start_of_polygon(polygon_indices, polygon_vertex)) { - polygon_index += 1; - ERR_FAIL_COND_V_MSG(polygon_surfaces.has(polygon_index) == false, nullptr, "The FBX file is corrupted, This surface_index is not expected."); - surface_id = polygon_surfaces[polygon_index]; - surface_data = surfaces.getptr(surface_id); - CRASH_COND(surface_data == nullptr); // Can't be null. - } - - const int vertex = get_vertex_from_polygon_vertex(polygon_indices, polygon_vertex); - - // The vertex position in the surface - // Uses a lookup table for speed with large scenes - bool has_polygon_vertex_index = surface_data->lookup_table.has(vertex); - int surface_polygon_vertex_index = -1; - - if (has_polygon_vertex_index) { - surface_polygon_vertex_index = surface_data->lookup_table[vertex]; - } else { - surface_polygon_vertex_index = surface_data->vertices_map.size(); - surface_data->lookup_table[vertex] = surface_polygon_vertex_index; - surface_data->vertices_map.push_back(vertex); - } - - surface_data->surface_polygon_vertex[polygon_index].push_back(surface_polygon_vertex_index); - } - } - - //print_verbose("[debug UV 1] UV1: " + itos(uvs_0.size())); - //print_verbose("[debug UV 2] UV2: " + itos(uvs_1.size())); - - // Phase 4. Per each surface just insert the vertices and add the indices. - for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { - SurfaceData *surface = surfaces.getptr(*surface_id); - - // Just add the vertices data. - for (unsigned int i = 0; i < surface->vertices_map.size(); i += 1) { - const Vertex vertex = surface->vertices_map[i]; - - // This must be done before add_vertex because the surface tool is - // expecting this before the st->add_vertex() call - add_vertex(state, - surface->surface_tool, - state.scale, - vertex, - vertices, - normals, - uvs_0, - uvs_1, - colors); - } - - // 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, - *indices, - vertices); - } - } - - // Phase 5. Compose the morphs if any. - for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { - SurfaceData *surface = surfaces.getptr(*surface_id); - - for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { - MorphVertexData *morph_data = morphs.getptr(*morph_name); - - // As said by the docs, this is not supposed to be different than - // vertex_count. - CRASH_COND(morph_data->vertices.size() != vertex_count); - CRASH_COND(morph_data->normals.size() != vertex_count); - - Vector3 *vertices_ptr = morph_data->vertices.ptrw(); - Vector3 *normals_ptr = morph_data->normals.ptrw(); - - Ref<SurfaceTool> morph_st; - 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]; - add_vertex( - state, - morph_st, - state.scale, - vertex, - vertices, - normals, - uvs_0, - uvs_1, - colors, - vertices_ptr[vertex], - normals_ptr[vertex]); - } - - if (state.is_blender_fbx) { - morph_st->generate_normals(); - } - morph_st->generate_tangents(); - surface->morphs.push_back(morph_st->commit_to_arrays()); - } - } - - // Phase 6. Compose the mesh and return it. - Ref<ImporterMesh> mesh; - mesh.instantiate(); - - // Add blend shape info. - for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { - mesh->add_blend_shape(*morph_name); - } - - // TODO always normalized, Why? - mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); - - // Add surfaces. - for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { - SurfaceData *surface = surfaces.getptr(*surface_id); - - if (state.is_blender_fbx) { - surface->surface_tool->generate_normals(); - } - // you can't generate them without a valid uv map. - if (uvs_0_raw.size() > 0) { - surface->surface_tool->generate_tangents(); - } - - Array mesh_array = surface->surface_tool->commit_to_arrays(); - Array blend_shapes = surface->morphs; - - if (surface->material.is_valid()) { - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes, Dictionary(), surface->material, surface->material->get_name()); - } else { - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes); - } - } - - ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D); - godot_mesh->set_mesh(mesh); - const String name = ImportUtils::FBXNodeToName(model->Name()); - godot_mesh->set_name(name); // hurry up compiling >.< - mesh->set_name("mesh3d-" + name); - return godot_mesh; -} - -void FBXMeshData::sanitize_vertex_weights(const ImportState &state) { - const int max_vertex_influence_count = RS::ARRAY_WEIGHTS_SIZE; - Map<int, int> skeleton_to_skin_bind_id; - // TODO: error's need added - const FBXDocParser::Skin *fbx_skin = mesh_geometry->DeformerSkin(); - - if (fbx_skin == nullptr || fbx_skin->Clusters().size() == 0) { - return; // do nothing - } - - // - // Precalculate the skin cluster mapping - // - - int bind_id = 0; - for (const FBXDocParser::Cluster *cluster : fbx_skin->Clusters()) { - ERR_CONTINUE_MSG(!state.fbx_bone_map.has(cluster->TargetNode()->ID()), "Missing bone map for cluster target node with id " + uitos(cluster->TargetNode()->ID()) + "."); - Ref<FBXBone> bone = state.fbx_bone_map[cluster->TargetNode()->ID()]; - skeleton_to_skin_bind_id.insert(bone->godot_bone_id, bind_id); - bind_id++; - } - - for (const Vertex *v = vertex_weights.next(nullptr); v != nullptr; v = vertex_weights.next(v)) { - VertexWeightMapping *vm = vertex_weights.getptr(*v); - ERR_CONTINUE(vm->bones.size() != vm->weights.size()); // No message, already checked. - ERR_CONTINUE(vm->bones_ref.size() != vm->weights.size()); // No message, already checked. - - const int initial_size = vm->weights.size(); - { - // Init bone id - int *bones_ptr = vm->bones.ptrw(); - Ref<FBXBone> *bones_ref_ptr = vm->bones_ref.ptrw(); - - for (int i = 0; i < vm->weights.size(); i += 1) { - // At this point this is not possible because the skeleton is already initialized. - CRASH_COND(bones_ref_ptr[i]->godot_bone_id == -2); - bones_ptr[i] = skeleton_to_skin_bind_id[bones_ref_ptr[i]->godot_bone_id]; - } - - // From this point on the data is no more valid. - vm->bones_ref.clear(); - } - - { - // Sort - float *weights_ptr = vm->weights.ptrw(); - int *bones_ptr = vm->bones.ptrw(); - for (int i = 0; i < vm->weights.size(); i += 1) { - for (int x = i + 1; x < vm->weights.size(); x += 1) { - if (weights_ptr[i] < weights_ptr[x]) { - SWAP(weights_ptr[i], weights_ptr[x]); - SWAP(bones_ptr[i], bones_ptr[x]); - } - } - } - } - - { - // Resize - vm->weights.resize(max_vertex_influence_count); - vm->bones.resize(max_vertex_influence_count); - float *weights_ptr = vm->weights.ptrw(); - int *bones_ptr = vm->bones.ptrw(); - for (int i = initial_size; i < max_vertex_influence_count; i += 1) { - weights_ptr[i] = 0.0; - bones_ptr[i] = 0; - } - - // Normalize - real_t sum = 0.0; - for (int i = 0; i < max_vertex_influence_count; i += 1) { - sum += weights_ptr[i]; - } - if (sum > 0.0) { - for (int i = 0; i < vm->weights.size(); i += 1) { - weights_ptr[i] = weights_ptr[i] / sum; - } - } - } - } -} - -void FBXMeshData::reorganize_vertices( - // TODO: perf hotspot on insane files - std::vector<int> &r_polygon_indices, - std::vector<Vector3> &r_vertices, - HashMap<int, Vector3> &r_normals, - HashMap<int, Vector2> &r_uv_1, - HashMap<int, Vector2> &r_uv_2, - HashMap<int, Color> &r_color, - HashMap<String, MorphVertexData> &r_morphs, - HashMap<int, HashMap<int, Vector3>> &r_normals_raw, - HashMap<int, HashMap<int, Color>> &r_colors_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw) { - // Key: OldVertex; Value: [New vertices]; - HashMap<int, Vector<int>> duplicated_vertices; - - PolygonId polygon_index = -1; - for (int pv = 0; pv < (int)r_polygon_indices.size(); pv += 1) { - if (is_start_of_polygon(r_polygon_indices, pv)) { - polygon_index += 1; - } - const Vertex index = get_vertex_from_polygon_vertex(r_polygon_indices, pv); - - bool need_duplication = false; - Vector2 this_vert_poly_uv1 = Vector2(); - Vector2 this_vert_poly_uv2 = Vector2(); - Vector3 this_vert_poly_normal = Vector3(); - Color this_vert_poly_color = Color(); - - // Take the normal and see if we need to duplicate this polygon. - if (r_normals_raw.has(index)) { - const HashMap<PolygonId, Vector3> *nrml_arr = r_normals_raw.getptr(index); - - if (nrml_arr->has(polygon_index)) { - this_vert_poly_normal = nrml_arr->get(polygon_index); - } else if (nrml_arr->has(-1)) { - this_vert_poly_normal = nrml_arr->get(-1); - } else { - print_error("invalid normal detected: " + itos(index) + " polygon index: " + itos(polygon_index)); - for (const PolygonId *pid = nrml_arr->next(nullptr); pid != nullptr; pid = nrml_arr->next(pid)) { - print_verbose("debug contents key: " + itos(*pid)); - - if (nrml_arr->has(*pid)) { - print_verbose("contents valid: " + nrml_arr->get(*pid)); - } - } - } - - // Now, check if we need to duplicate it. - for (const PolygonId *pid = nrml_arr->next(nullptr); pid != nullptr; pid = nrml_arr->next(pid)) { - if (*pid == polygon_index) { - continue; - } - - const Vector3 vert_poly_normal = *nrml_arr->getptr(*pid); - if (!vert_poly_normal.is_equal_approx(this_vert_poly_normal)) { - // Yes this polygon need duplication. - need_duplication = true; - break; - } - } - } - - // TODO: make me vertex color - // Take the normal and see if we need to duplicate this polygon. - if (r_colors_raw.has(index)) { - const HashMap<PolygonId, Color> *color_arr = r_colors_raw.getptr(index); - - if (color_arr->has(polygon_index)) { - this_vert_poly_color = color_arr->get(polygon_index); - } else if (color_arr->has(-1)) { - this_vert_poly_color = color_arr->get(-1); - } else { - print_error("invalid color detected: " + itos(index) + " polygon index: " + itos(polygon_index)); - for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) { - print_verbose("debug contents key: " + itos(*pid)); - - if (color_arr->has(*pid)) { - print_verbose("contents valid: " + color_arr->get(*pid)); - } - } - } - - // Now, check if we need to duplicate it. - for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) { - if (*pid == polygon_index) { - continue; - } - - const Color vert_poly_color = *color_arr->getptr(*pid); - if (!this_vert_poly_color.is_equal_approx(vert_poly_color)) { - // Yes this polygon need duplication. - need_duplication = true; - break; - } - } - } - - // Take the UV1 and UV2 and see if we need to duplicate this polygon. - { - HashMap<int, HashMap<int, Vector2>> *uv_raw = &r_uv_1_raw; - Vector2 *this_vert_poly_uv = &this_vert_poly_uv1; - for (int kk = 0; kk < 2; kk++) { - if (uv_raw->has(index)) { - const HashMap<PolygonId, Vector2> *uvs = uv_raw->getptr(index); - - if (uvs->has(polygon_index)) { - // This Polygon has its own uv. - (*this_vert_poly_uv) = *uvs->getptr(polygon_index); - - // Check if we need to duplicate it. - for (const PolygonId *pid = uvs->next(nullptr); pid != nullptr; pid = uvs->next(pid)) { - if (*pid == polygon_index) { - continue; - } - const Vector2 vert_poly_uv = *uvs->getptr(*pid); - if (!vert_poly_uv.is_equal_approx(*this_vert_poly_uv)) { - // Yes this polygon need duplication. - need_duplication = true; - break; - } - } - } else if (uvs->has(-1)) { - // It has the default UV. - (*this_vert_poly_uv) = *uvs->getptr(-1); - } else if (uvs->size() > 0) { - // No uv, this is strange, just take the first and duplicate. - (*this_vert_poly_uv) = *uvs->getptr(*uvs->next(nullptr)); - WARN_PRINT("No UVs for this polygon, while there is no default and some other polygons have it. This FBX file may be corrupted."); - } - } - uv_raw = &r_uv_2_raw; - this_vert_poly_uv = &this_vert_poly_uv2; - } - } - - // If we want to duplicate it, Let's see if we already duplicated this - // vertex. - if (need_duplication) { - if (duplicated_vertices.has(index)) { - Vertex similar_vertex = -1; - // Let's see if one of the new vertices has the same data of this. - const Vector<int> *new_vertices = duplicated_vertices.getptr(index); - for (int j = 0; j < new_vertices->size(); j += 1) { - const Vertex new_vertex = (*new_vertices)[j]; - bool same_uv1 = false; - bool same_uv2 = false; - bool same_normal = false; - bool same_color = false; - - if (r_uv_1.has(new_vertex)) { - if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - same_uv1 = true; - } - } - - if (r_uv_2.has(new_vertex)) { - if ((this_vert_poly_uv2 - (*r_uv_2.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - same_uv2 = true; - } - } - - if (r_color.has(new_vertex)) { - if (this_vert_poly_color.is_equal_approx((*r_color.getptr(new_vertex)))) { - same_color = true; - } - } - - if (r_normals.has(new_vertex)) { - if ((this_vert_poly_normal - (*r_normals.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - same_uv2 = true; - } - } - - if (same_uv1 && same_uv2 && same_normal && same_color) { - similar_vertex = new_vertex; - break; - } - } - - if (similar_vertex != -1) { - // Update polygon. - if (is_end_of_polygon(r_polygon_indices, pv)) { - r_polygon_indices[pv] = ~similar_vertex; - } else { - r_polygon_indices[pv] = similar_vertex; - } - need_duplication = false; - } - } - } - - if (need_duplication) { - const Vertex old_index = index; - const Vertex new_index = r_vertices.size(); - - // Polygon index. - if (is_end_of_polygon(r_polygon_indices, pv)) { - r_polygon_indices[pv] = ~new_index; - } else { - r_polygon_indices[pv] = new_index; - } - - // Vertex position. - r_vertices.push_back(r_vertices[old_index]); - - // Normals - if (r_normals_raw.has(old_index)) { - r_normals.set(new_index, this_vert_poly_normal); - r_normals_raw.getptr(old_index)->erase(polygon_index); - r_normals_raw[new_index][polygon_index] = this_vert_poly_normal; - } - - // Vertex Color - if (r_colors_raw.has(old_index)) { - r_color.set(new_index, this_vert_poly_color); - r_colors_raw.getptr(old_index)->erase(polygon_index); - r_colors_raw[new_index][polygon_index] = this_vert_poly_color; - } - - // UV 0 - if (r_uv_1_raw.has(old_index)) { - r_uv_1.set(new_index, this_vert_poly_uv1); - r_uv_1_raw.getptr(old_index)->erase(polygon_index); - r_uv_1_raw[new_index][polygon_index] = this_vert_poly_uv1; - } - - // UV 1 - if (r_uv_2_raw.has(old_index)) { - r_uv_2.set(new_index, this_vert_poly_uv2); - r_uv_2_raw.getptr(old_index)->erase(polygon_index); - r_uv_2_raw[new_index][polygon_index] = this_vert_poly_uv2; - } - - // Morphs - for (const String *mname = r_morphs.next(nullptr); mname != nullptr; mname = r_morphs.next(mname)) { - MorphVertexData *d = r_morphs.getptr(*mname); - // This can't never happen. - CRASH_COND(d == nullptr); - if (d->vertices.size() > old_index) { - d->vertices.push_back(d->vertices[old_index]); - } - if (d->normals.size() > old_index) { - d->normals.push_back(d->normals[old_index]); - } - } - - if (vertex_weights.has(old_index)) { - vertex_weights.set(new_index, vertex_weights[old_index]); - } - - duplicated_vertices[old_index].push_back(new_index); - } else { - if (r_normals_raw.has(index) && - r_normals.has(index) == false) { - r_normals.set(index, this_vert_poly_normal); - } - - if (r_colors_raw.has(index) && r_color.has(index) == false) { - r_color.set(index, this_vert_poly_color); - } - - if (r_uv_1_raw.has(index) && - r_uv_1.has(index) == false) { - r_uv_1.set(index, this_vert_poly_uv1); - } - - if (r_uv_2_raw.has(index) && - r_uv_2.has(index) == false) { - r_uv_2.set(index, this_vert_poly_uv2); - } - } - } -} - -void FBXMeshData::add_vertex( - const ImportState &state, - Ref<SurfaceTool> p_surface_tool, - real_t p_scale, - Vertex p_vertex, - const std::vector<Vector3> &p_vertices_position, - const HashMap<int, Vector3> &p_normals, - const HashMap<int, Vector2> &p_uvs_0, - const HashMap<int, Vector2> &p_uvs_1, - const HashMap<int, Color> &p_colors, - const Vector3 &p_morph_value, - const Vector3 &p_morph_normal) { - ERR_FAIL_INDEX_MSG(p_vertex, (Vertex)p_vertices_position.size(), "FBX file is corrupted, the position of the vertex can't be retrieved."); - - if (p_normals.has(p_vertex) && !state.is_blender_fbx) { - p_surface_tool->set_normal(p_normals[p_vertex] + p_morph_normal); - } - - if (p_uvs_0.has(p_vertex)) { - //print_verbose("uv1: [" + itos(p_vertex) + "] " + p_uvs_0[p_vertex]); - // Inverts Y UV. - p_surface_tool->set_uv(Vector2(p_uvs_0[p_vertex].x, 1 - p_uvs_0[p_vertex].y)); - } - - if (p_uvs_1.has(p_vertex)) { - //print_verbose("uv2: [" + itos(p_vertex) + "] " + p_uvs_1[p_vertex]); - // Inverts Y UV. - p_surface_tool->set_uv2(Vector2(p_uvs_1[p_vertex].x, 1 - p_uvs_1[p_vertex].y)); - } - - if (p_colors.has(p_vertex)) { - p_surface_tool->set_color(p_colors[p_vertex]); - } - - // TODO what about binormals? - // TODO there is other? - - if (vertex_weights.has(p_vertex)) { - // Let's extract the weight info. - const VertexWeightMapping *vm = vertex_weights.getptr(p_vertex); - const Vector<int> &bones = vm->bones; - - // the bug is that the bone idx is wrong because it is not ref'ing the skin. - - if (bones.size() > RS::ARRAY_WEIGHTS_SIZE) { - print_error("[weight overflow detected]"); - } - - p_surface_tool->set_weights(vm->weights); - // 0 1 2 3 4 5 6 7 < local skeleton / skin for mesh - // 0 1 2 3 4 5 6 7 8 9 10 < actual skeleton with all joints - p_surface_tool->set_bones(bones); - } - - // The surface tool want the vertex position as last thing. - p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale); -} - -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]); - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[0]); - return; - } else if (polygon_vertex_count == 2) { - // line to triangle - st->add_index(p_polygon_vertex[1]); - st->add_index(p_polygon_vertex[1]); - st->add_index(p_polygon_vertex[0]); - return; - } else if (polygon_vertex_count == 3) { - // triangle to triangle - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[1]); - return; - } else if (polygon_vertex_count == 4) { - // quad to triangle - this code is awesome for import times - // it prevents triangles being generated slowly - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[1]); - st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[3]); - return; - } else { - // non triangulated - we must run the triangulation algorithm - bool is_simple_convex = false; - // this code is 'slow' but required it triangulates all the unsupported geometry. - // Doesn't allow for bigger polygons because those are unlikely be convex - if (polygon_vertex_count <= 6) { - // Start from true, check if it's false. - is_simple_convex = true; - Vector3 first_vec; - for (int i = 0; i < polygon_vertex_count; i += 1) { - 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; - - const Vector3 res = edge1.normalized().cross(edge2.normalized()).normalized(); - if (i == 0) { - first_vec = res; - } else { - if (first_vec.dot(res) < 0.0) { - // Ok we found an angle that is not the same dir of the - // others. - is_simple_convex = false; - break; - } - } - } - } - - if (is_simple_convex) { - // This is a convex polygon, so just triangulate it. - for (int i = 0; i < (polygon_vertex_count - 2); i += 1) { - st->add_index(p_polygon_vertex[2 + i]); - st->add_index(p_polygon_vertex[1 + i]); - st->add_index(p_polygon_vertex[0]); - } - return; - } - } - - { - // This is a concave polygon. - - std::vector<Vector3> poly_vertices(polygon_vertex_count); - for (int i = 0; i < polygon_vertex_count; i += 1) { - poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]]; - } - - const Vector3 poly_norm = get_poly_normal(poly_vertices); - if (poly_norm.length_squared() <= CMP_EPSILON) { - ERR_FAIL_COND_MSG(poly_norm.length_squared() <= CMP_EPSILON, "The normal of this poly was not computed. Is this FBX file corrupted."); - } - - // Select the plan coordinate. - int axis_1_coord = 0; - int axis_2_coord = 1; - { - real_t inv = poly_norm.z; - - const real_t axis_x = ABS(poly_norm.x); - const real_t axis_y = ABS(poly_norm.y); - const real_t axis_z = ABS(poly_norm.z); - - if (axis_x > axis_y) { - if (axis_x > axis_z) { - // For the most part the normal point toward X. - axis_1_coord = 1; - axis_2_coord = 2; - inv = poly_norm.x; - } - } else if (axis_y > axis_z) { - // For the most part the normal point toward Y. - axis_1_coord = 2; - axis_2_coord = 0; - inv = poly_norm.y; - } - - // Swap projection axes to take the negated projection vector into account - if (inv < 0.0f) { - SWAP(axis_1_coord, axis_2_coord); - } - } - - TPPLPoly tppl_poly; - tppl_poly.Init(polygon_vertex_count); - std::vector<Vector2> projected_vertices(polygon_vertex_count); - for (int i = 0; i < polygon_vertex_count; i += 1) { - const Vector2 pv(poly_vertices[i][axis_1_coord], poly_vertices[i][axis_2_coord]); - projected_vertices[i] = pv; - tppl_poly.GetPoint(i) = pv; - } - tppl_poly.SetOrientation(TPPL_ORIENTATION_CCW); - - List<TPPLPoly> out_poly; - - TPPLPartition tppl_partition; - if (tppl_partition.Triangulate_OPT(&tppl_poly, &out_poly) == 0) { // Good result. - if (tppl_partition.Triangulate_EC(&tppl_poly, &out_poly) == 0) { // Medium result. - if (tppl_partition.Triangulate_MONO(&tppl_poly, &out_poly) == 0) { // Really poor result. - ERR_FAIL_MSG("The triangulation of this polygon failed, please try to triangulate your mesh or check if it has broken polygons."); - } - } - } - - std::vector<Vector2> tris(out_poly.size()); - 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 returned more points, how this is possible?"); - // Find Index - for (int i = 2; i >= 0; i -= 1) { - const Vector2 vertex = tp.GetPoint(i); - bool done = false; - // Find Index - for (int y = 0; y < polygon_vertex_count; y += 1) { - if ((projected_vertices[y] - vertex).length_squared() <= CMP_EPSILON) { - // This seems the right vertex - st->add_index(p_polygon_vertex[y]); - done = true; - break; - } - } - ERR_FAIL_COND(done == false); - } - } - } -} - -void FBXMeshData::gen_weight_info(Ref<SurfaceTool> st, Vertex vertex_id) const { - if (vertex_weights.is_empty()) { - return; - } - - if (vertex_weights.has(vertex_id)) { - // Let's extract the weight info. - const VertexWeightMapping *vm = vertex_weights.getptr(vertex_id); - st->set_weights(vm->weights); - st->set_bones(vm->bones); - } -} - -int FBXMeshData::get_vertex_from_polygon_vertex(const std::vector<int> &p_polygon_indices, int p_index) const { - if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { - return -1; - } - - const int vertex = p_polygon_indices[p_index]; - if (vertex >= 0) { - return vertex; - } else { - // Negative numbers are the end of the face, reversing the bits is - // possible to obtain the positive correct vertex number. - return ~vertex; - } -} - -bool FBXMeshData::is_end_of_polygon(const std::vector<int> &p_polygon_indices, int p_index) const { - if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { - return false; - } - - const int vertex = p_polygon_indices[p_index]; - - // If the index is negative this is the end of the Polygon. - return vertex < 0; -} - -bool FBXMeshData::is_start_of_polygon(const std::vector<int> &p_polygon_indices, int p_index) const { - if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { - return false; - } - - if (p_index == 0) { - return true; - } - - // If the previous indices is negative this is the begin of a new Polygon. - return p_polygon_indices[p_index - 1] < 0; -} - -int FBXMeshData::count_polygons(const std::vector<int> &p_polygon_indices) const { - // The negative numbers define the end of the polygon. Counting the amount of - // negatives the numbers of polygons are obtained. - int count = 0; - for (size_t i = 0; i < p_polygon_indices.size(); i += 1) { - if (p_polygon_indices[i] < 0) { - count += 1; - } - } - return count; -} - -template <class R, class T> -HashMap<int, R> FBXMeshData::extract_per_vertex_data( - int p_vertex_count, - const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edge_map, - const std::vector<int> &p_mesh_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data, - R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back), - R p_fall_back) const { - /* When index_to_direct is set - * index size is 184 ( contains index for the data array [values 0, 96] ) - * data size is 96 (contains uv coordinates) - * this means index is simple data reduction basically - */ - //// - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0) { - print_verbose("debug count: index size: " + itos(p_mapping_data.index.size()) + ", data size: " + itos(p_mapping_data.data.size())); - print_verbose("vertex indices count: " + itos(p_mesh_indices.size())); - print_verbose("Edge map size: " + itos(p_edge_map.size())); - } - - ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "FBX importer needs to map correctly to this field, please specify the override index name to fix this problem!"); - ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "The FBX seems corrupted"); - - // Aggregate vertex data. - HashMap<Vertex, Vector<VertexData<T>>> aggregate_vertex_data; - - switch (p_mapping_data.map_type) { - case FBXDocParser::MeshGeometry::MapType::none: { - // No data nothing to do. - return (HashMap<int, R>()); - } - case FBXDocParser::MeshGeometry::MapType::vertex: { - ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct, (HashMap<int, R>()), "We will support in future"); - - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data is mapped per vertex directly. - ERR_FAIL_COND_V_MSG((int)p_mapping_data.data.size() != p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR01"); - for (size_t vertex_index = 0; vertex_index < p_mapping_data.data.size(); vertex_index += 1) { - aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[vertex_index] }); - } - } else { - // The data is mapped per vertex using a reference. - // The indices array, contains a *reference_id for each vertex. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG((int)p_mapping_data.index.size() != p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR02"); - for (size_t vertex_index = 0; vertex_index < p_mapping_data.index.size(); vertex_index += 1) { - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[vertex_index], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR03."); - aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[p_mapping_data.index[vertex_index]] }); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::polygon_vertex: { - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct) { - // The data is mapped using each index from the indexes array then direct to the data (data reduction algorithm) - ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR04"); - int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_id += 1; - } - 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: #ERR05"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06"); - const int index_to_direct = p_mapping_data.index[polygon_vertex_index]; - T value = p_mapping_data.data[index_to_direct]; - aggregate_vertex_data[vertex_index].push_back({ polygon_id, value }); - } - } else if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per polygon vertex directly. - ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR04"); - int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.data.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_id += 1; - } - 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: #ERR05"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06"); - - aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[polygon_vertex_index] }); - } - } else { - // The data is mapped per polygon_vertex using a reference. - // The indices array, contains a *reference_id for each polygon_vertex. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(p_mesh_indices.size() != p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR7"); - int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_id += 1; - } - 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(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]] }); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::polygon: { - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per polygon directly. - const int polygon_count = count_polygons(p_mesh_indices); - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR12"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - int polygon_index = -1; - for (size_t polygon_vertex_index = 0; - polygon_vertex_index < p_mesh_indices.size(); - polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_index += 1; - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR13"); - } - - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR14"); - - aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[polygon_index] }); - } - ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR16. Not all Polygons are present in the file."); - } else { - // The data is mapped per polygon using a reference. - // The indices array, contains a *reference_id for each polygon. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - const int polygon_count = count_polygons(p_mesh_indices); - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR17"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - int polygon_index = -1; - for (size_t polygon_vertex_index = 0; - polygon_vertex_index < p_mesh_indices.size(); - polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_index += 1; - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR18"); - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[polygon_index], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR19"); - } - - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR20"); - - aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[p_mapping_data.index[polygon_index]] }); - } - ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR22. Not all Polygons are present in the file."); - } - } break; - case FBXDocParser::MeshGeometry::MapType::edge: { - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per edge directly. - ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR23"); - for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) { - const FBXDocParser::MeshGeometry::Edge edge = FBXDocParser::MeshGeometry::get_edge(p_edge_map, edge_index); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR24"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR25"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR26"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR27"); - aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[edge_index] }); - aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[edge_index] }); - } - } else { - // The data is mapped per edge using a reference. - // The indices array, contains a *reference_id for each polygon. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR28"); - for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) { - const FBXDocParser::MeshGeometry::Edge edge = FBXDocParser::MeshGeometry::get_edge(p_edge_map, edge_index); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR29"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR30"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR31"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR32"); - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_0], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR33"); - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_1], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR34"); - aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] }); - aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] }); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::all_the_same: { - // No matter the mode, no matter the data size; The first always win - // and is set to all the vertices. - ERR_FAIL_COND_V_MSG(p_mapping_data.data.size() <= 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR35"); - if (p_mapping_data.data.size() > 0) { - for (int vertex_index = 0; vertex_index < p_vertex_count; vertex_index += 1) { - aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[0] }); - } - } - } break; - } - - if (aggregate_vertex_data.size() == 0) { - return (HashMap<int, R>()); - } - - // A map is used because turns out that the some FBX file are not well organized - // with vertices well compacted. Using a map allows avoid those issues. - HashMap<Vertex, R> result; - - // Aggregate the collected data. - for (const Vertex *index = aggregate_vertex_data.next(nullptr); index != nullptr; index = aggregate_vertex_data.next(index)) { - Vector<VertexData<T>> *aggregated_vertex = aggregate_vertex_data.getptr(*index); - // This can't be null because we are just iterating. - CRASH_COND(aggregated_vertex == nullptr); - - ERR_FAIL_INDEX_V_MSG(0, aggregated_vertex->size(), (HashMap<int, R>()), "The FBX file is corrupted, No valid data for this vertex index."); - result[*index] = collector_function(aggregated_vertex, p_fall_back); - } - - // Sanitize the data now, if the file is broken we can try import it anyway. - bool problem_found = false; - for (size_t i = 0; i < p_mesh_indices.size(); i += 1) { - const Vertex vertex = get_vertex_from_polygon_vertex(p_mesh_indices, i); - if (result.has(vertex) == false) { - result[vertex] = p_fall_back; - problem_found = true; - } - } - if (problem_found) { - WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN0."); - } - - return result; -} - -template <class T> -HashMap<int, T> FBXMeshData::extract_per_polygon( - int p_vertex_count, - const std::vector<int> &p_polygon_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data, - T p_fallback_value) const { - ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.data.size() == 0, (HashMap<int, T>()), "invalid index to direct array"); - ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_fbx_data.index.size() == 0, (HashMap<int, T>()), "The FBX seems corrupted"); - - const int polygon_count = count_polygons(p_polygon_indices); - - // Aggregate vertex data. - HashMap<int, Vector<T>> aggregate_polygon_data; - - switch (p_fbx_data.map_type) { - case FBXDocParser::MeshGeometry::MapType::none: { - // No data nothing to do. - return (HashMap<int, T>()); - } - case FBXDocParser::MeshGeometry::MapType::vertex: { - ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per vertex. This should not happen."); - } break; - case FBXDocParser::MeshGeometry::MapType::polygon_vertex: { - ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per polygon vertex. This should not happen."); - } break; - case FBXDocParser::MeshGeometry::MapType::polygon: { - if (p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct) { - // The data is stored efficiently index_to_direct allows less data in the FBX file. - for (int polygon_index = 0; - polygon_index < polygon_count; - polygon_index += 1) { - if (p_fbx_data.index.size() == 0) { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62"); - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]); - } else { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62"); - - const int index_to_direct = p_fbx_data.index[polygon_index]; - T value = p_fbx_data.data[index_to_direct]; - aggregate_polygon_data[polygon_index].push_back(value); - } - } - } else if (p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per polygon directly. - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR51"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - for (int polygon_index = 0; - polygon_index < polygon_count; - polygon_index += 1) { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR52"); - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]); - } - } else { - // The data is mapped per polygon using a reference. - // The indices array, contains a *reference_id for each polygon. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file seems corrupted: #ERR52"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - for (int polygon_index = 0; - polygon_index < polygon_count; - polygon_index += 1) { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR53"); - ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[polygon_index], (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR54"); - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[p_fbx_data.index[polygon_index]]); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::edge: { - ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per edge. This should not happen."); - } break; - case FBXDocParser::MeshGeometry::MapType::all_the_same: { - // No matter the mode, no matter the data size; The first always win - // and is set to all the vertices. - ERR_FAIL_COND_V_MSG(p_fbx_data.data.size() <= 0, (HashMap<int, T>()), "FBX file seems corrupted: #ERR55"); - if (p_fbx_data.data.size() > 0) { - for (int polygon_index = 0; polygon_index < polygon_count; polygon_index += 1) { - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[0]); - } - } - } break; - } - - if (aggregate_polygon_data.size() == 0) { - return (HashMap<int, T>()); - } - - // A map is used because turns out that the some FBX file are not well organized - // with vertices well compacted. Using a map allows avoid those issues. - HashMap<int, T> polygons; - - // Take the first value for each vertex. - for (const Vertex *index = aggregate_polygon_data.next(nullptr); index != nullptr; index = aggregate_polygon_data.next(index)) { - Vector<T> *aggregated_polygon = aggregate_polygon_data.getptr(*index); - // This can't be null because we are just iterating. - CRASH_COND(aggregated_polygon == nullptr); - - ERR_FAIL_INDEX_V_MSG(0, (int)aggregated_polygon->size(), (HashMap<int, T>()), "The FBX file is corrupted, No valid data for this polygon index."); - - // Validate the final value. - polygons[*index] = (*aggregated_polygon)[0]; - } - - // Sanitize the data now, if the file is broken we can try import it anyway. - bool problem_found = false; - for (int polygon_i = 0; polygon_i < polygon_count; polygon_i += 1) { - if (polygons.has(polygon_i) == false) { - polygons[polygon_i] = p_fallback_value; - problem_found = true; - } - } - if (problem_found) { - WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN1."); - } - - return polygons; -} - -void FBXMeshData::extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data) { - r_data.clear(); - - const int vertex_count = mesh_geometry->get_vertices().size(); - - for (const FBXDocParser::BlendShape *blend_shape : mesh_geometry->get_blend_shapes()) { - for (const FBXDocParser::BlendShapeChannel *blend_shape_channel : blend_shape->BlendShapeChannels()) { - const std::vector<const FBXDocParser::ShapeGeometry *> &shape_geometries = blend_shape_channel->GetShapeGeometries(); - for (const FBXDocParser::ShapeGeometry *shape_geometry : shape_geometries) { - String morph_name = ImportUtils::FBXAnimMeshName(shape_geometry->Name()).c_str(); - if (morph_name.is_empty()) { - morph_name = "morph"; - } - - // TODO we have only these?? - const std::vector<unsigned int> &morphs_vertex_indices = shape_geometry->GetIndices(); - const std::vector<Vector3> &morphs_vertices = shape_geometry->GetVertices(); - const std::vector<Vector3> &morphs_normals = shape_geometry->GetNormals(); - - ERR_FAIL_COND_MSG((int)morphs_vertex_indices.size() > vertex_count, "The FBX file is corrupted: #ERR103"); - ERR_FAIL_COND_MSG(morphs_vertex_indices.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR104"); - ERR_FAIL_COND_MSG((int)morphs_vertices.size() > vertex_count, "The FBX file is corrupted: #ERR105"); - ERR_FAIL_COND_MSG(morphs_normals.size() != 0 && morphs_normals.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR106"); - - if (r_data.has(morph_name) == false) { - // This morph doesn't exist yet. - // Create it. - MorphVertexData md; - md.vertices.resize(vertex_count); - md.normals.resize(vertex_count); - r_data.set(morph_name, md); - } - - MorphVertexData *data = r_data.getptr(morph_name); - Vector3 *data_vertices_ptr = data->vertices.ptrw(); - Vector3 *data_normals_ptr = data->normals.ptrw(); - - for (int i = 0; i < (int)morphs_vertex_indices.size(); i += 1) { - const Vertex vertex = morphs_vertex_indices[i]; - - ERR_FAIL_INDEX_MSG(vertex, vertex_count, "The blend shapes of this FBX file are corrupted. It has a not valid vertex."); - - data_vertices_ptr[vertex] = morphs_vertices[i]; - - if (morphs_normals.size() != 0) { - data_normals_ptr[vertex] = morphs_normals[i]; - } - } - } - } - } -} diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h deleted file mode 100644 index eec7f38cd6..0000000000 --- a/modules/fbx/data/fbx_mesh_data.h +++ /dev/null @@ -1,200 +0,0 @@ -/*************************************************************************/ -/* fbx_mesh_data.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 FBX_MESH_DATA_H -#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 "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/resources/surface_tool.h" - -#include "fbx_bone.h" -#include "fbx_parser/FBXMeshGeometry.h" -#include "import_state.h" -#include "tools/import_utils.h" - -struct FBXNode; -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<float> weights; - Vector<int> bones; - // This extra vector is used because the bone id is computed in a second step. - // TODO Get rid of this extra step is a good idea. - Vector<Ref<FBXBone>> bones_ref; -}; - -template <class T> -struct VertexData { - int polygon_index; - T data; -}; - -// Caches mesh information and instantiates meshes for you using helper functions. -struct FBXMeshData : RefCounted { - struct MorphVertexData { - // TODO we have only these?? - /// Each element is a vertex. Not supposed to be void. - Vector<Vector3> vertices; - /// Each element is a vertex. Not supposed to be void. - Vector<Vector3> normals; - }; - - // FIXME: remove this is a hack for testing only - mutable const FBXDocParser::MeshGeometry *mesh_geometry = nullptr; - - Ref<FBXNode> mesh_node = nullptr; - /// vertex id, Weight Info - /// later: perf we can use array here - HashMap<int, VertexWeightMapping> vertex_weights; - - // translate fbx mesh data from document context to FBX Mesh Geometry Context - bool valid_weight_indexes = false; - - ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression); - - void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const; - - /* mesh maximum weight count */ - bool valid_weight_count = false; - int max_weight_count = 0; - uint64_t armature_id = 0; - bool valid_armature_id = false; - ImporterMeshInstance3D *godot_mesh_instance = nullptr; - -private: - void sanitize_vertex_weights(const ImportState &state); - - /// Make sure to reorganize the vertices so that the correct UV is taken. - /// This step is needed because differently from the normal, that can be - /// combined, the UV may need its own triangle because sometimes they have - /// really different UV for the same vertex but different polygon. - /// This function make sure to add another vertex for those UVS. - void reorganize_vertices( - std::vector<int> &r_polygon_indices, - std::vector<Vector3> &r_vertices, - HashMap<int, Vector3> &r_normals, - HashMap<int, Vector2> &r_uv_1, - HashMap<int, Vector2> &r_uv_2, - HashMap<int, Color> &r_color, - HashMap<String, MorphVertexData> &r_morphs, - HashMap<int, HashMap<int, Vector3>> &r_normals_raw, - HashMap<int, HashMap<int, Color>> &r_colors_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw); - - void add_vertex( - const ImportState &state, - Ref<SurfaceTool> p_surface_tool, - real_t p_scale, - int p_vertex, - const std::vector<Vector3> &p_vertices_position, - const HashMap<int, Vector3> &p_normals, - const HashMap<int, Vector2> &p_uvs_0, - const HashMap<int, Vector2> &p_uvs_1, - const HashMap<int, Color> &p_colors, - const Vector3 &p_morph_value = Vector3(), - const Vector3 &p_morph_normal = Vector3()); - - 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. - /// The polygon vertices are stored in an array with some negative - /// values. The negative values define the last face index. - /// For example the following `face_array` contains two faces, the former - /// with 3 vertices and the latter with a line: - /// [0,2,-2,3,-5] - /// Parsed as: - /// [0, 2, 1, 3, 4] - /// The negative values are computed using this formula: `(-value) - 1` - /// - /// 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; - - /// Returns true if this polygon_vertex_index is the end of a new polygon. - bool is_end_of_polygon(const std::vector<int> &p_face_indices, int p_index) const; - - /// Returns true if this polygon_vertex_index is the begin of a new polygon. - bool is_start_of_polygon(const std::vector<int> &p_face_indices, int p_index) const; - - /// Returns the number of polygons. - int count_polygons(const std::vector<int> &p_face_indices) const; - - /// Used to extract data from the `MappingData` aligned with vertex. - /// Useful to extract normal/uvs/colors/tangents/etc... - /// If the function fails somehow, it returns an hollow vector and print an error. - template <class R, class T> - HashMap<int, R> extract_per_vertex_data( - int p_vertex_count, - const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edges, - const std::vector<int> &p_mesh_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data, - R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back), - R p_fall_back) const; - - /// Used to extract data from the `MappingData` organized per polygon. - /// Useful to extract the material - /// If the function fails somehow, it returns an hollow vector and print an error. - template <class T> - HashMap<int, T> extract_per_polygon( - int p_vertex_count, - const std::vector<int> &p_face_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data, - T p_fallback_value) const; - - /// Extracts the morph data and organizes it per vertices. - /// The returned `MorphVertexData` arrays are never something different - /// then the `vertex_count`. - void extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data); -}; - -#endif // FBX_MESH_DATA_H diff --git a/modules/fbx/data/fbx_node.h b/modules/fbx/data/fbx_node.h deleted file mode 100644 index 75461e397d..0000000000 --- a/modules/fbx/data/fbx_node.h +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************/ -/* fbx_node.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 FBX_NODE_H -#define FBX_NODE_H - -#include "fbx_skeleton.h" -#include "model_abstraction.h" -#include "pivot_transform.h" - -#include "fbx_parser/FBXDocument.h" - -class Node3D; -struct PivotTransform; - -struct FBXNode : RefCounted, ModelAbstraction { - uint64_t current_node_id = 0; - String node_name = String(); - Node3D *godot_node = nullptr; - - // used to parent the skeleton once the tree is built. - Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>(); - - void set_parent(Ref<FBXNode> p_parent) { - fbx_parent = p_parent; - } - - void set_pivot_transform(Ref<PivotTransform> p_pivot_transform) { - pivot_transform = p_pivot_transform; - } - - Ref<PivotTransform> pivot_transform = Ref<PivotTransform>(); // local and global xform data - Ref<FBXNode> fbx_parent = Ref<FBXNode>(); // parent node -}; - -#endif // FBX_NODE_H diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp deleted file mode 100644 index 11eed2576f..0000000000 --- a/modules/fbx/data/fbx_skeleton.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************/ -/* fbx_skeleton.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 "fbx_skeleton.h" - -#include "import_state.h" - -#include "tools/import_utils.h" - -void FBXSkeleton::init_skeleton(const ImportState &state) { - int skeleton_bone_count = skeleton_bones.size(); - - if (skeleton == nullptr && skeleton_bone_count > 0) { - skeleton = memnew(Skeleton3D); - - if (fbx_node.is_valid()) { - // cache skeleton attachment for later during node creation - // can't be done until after node hierarchy is built - if (fbx_node->godot_node != state.root) { - fbx_node->skeleton_node = Ref<FBXSkeleton>(this); - print_verbose("cached armature skeleton attachment for node " + fbx_node->node_name); - } else { - // root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton) - fbx_node->godot_node->add_child(skeleton); - skeleton->set_owner(state.root_owner); - skeleton->set_name("Skeleton3D"); - print_verbose("created armature skeleton for root"); - } - } else { - memfree(skeleton); - skeleton = nullptr; - print_error("[doc] skeleton has no valid node to parent nodes to - erasing"); - skeleton_bones.clear(); - return; - } - } - - // Make the bone name uniques. - for (int x = 0; x < skeleton_bone_count; x++) { - Ref<FBXBone> bone = skeleton_bones[x]; - if (bone.is_valid()) { - // Make sure the bone name is unique. - const String bone_name = bone->bone_name; - int same_name_count = 0; - 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) { - same_name_count += 1; - other_bone->bone_name += "_" + itos(same_name_count); - } - } - } - } - } - - Map<int, Ref<FBXBone>> bone_map; - // implement fbx cluster skin logic here this is where it goes - int bone_count = 0; - for (int x = 0; x < skeleton_bone_count; x++) { - Ref<FBXBone> bone = skeleton_bones[x]; - if (bone.is_valid()) { - skeleton->add_bone(bone->bone_name); - bone->godot_bone_id = bone_count; - bone->fbx_skeleton = Ref<FBXSkeleton>(this); - bone_map.insert(bone_count, bone); - print_verbose("added bone " + itos(bone->bone_id) + " " + bone->bone_name); - bone_count++; - } - } - - ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?"); - - for (const KeyValue<int, Ref<FBXBone>> &bone_element : bone_map) { - const Ref<FBXBone> bone = bone_element.value; - int bone_index = bone_element.key; - print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name); - - skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale)); - { - Transform3D base_xform = bone->node->pivot_transform->LocalTransform; - - skeleton->set_bone_pose_position(bone_index, base_xform.origin); - skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion()); - skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale()); - } - - // lookup parent ID - if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) { - Ref<FBXBone> parent_bone = state.fbx_bone_map[bone->parent_bone_id]; - int bone_id = skeleton->find_bone(parent_bone->bone_name); - if (bone_id != -1) { - skeleton->set_bone_parent(bone_index, bone_id); - } else { - print_error("invalid bone parent: " + parent_bone->bone_name); - } - } else { - if (bone->godot_bone_id != -1) { - skeleton->set_bone_parent(bone_index, -1); // no parent for this bone - } - } - } -} diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h deleted file mode 100644 index b6103df949..0000000000 --- a/modules/fbx/data/fbx_skeleton.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************/ -/* fbx_skeleton.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 FBX_SKELETON_H -#define FBX_SKELETON_H - -#include "fbx_bone.h" -#include "fbx_node.h" -#include "model_abstraction.h" - -#include "core/object/ref_counted.h" -#include "scene/3d/skeleton_3d.h" - -struct FBXNode; -struct ImportState; -struct FBXBone; - -struct FBXSkeleton : RefCounted { - Ref<FBXNode> fbx_node = Ref<FBXNode>(); - Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>(); - Skeleton3D *skeleton = nullptr; - - void init_skeleton(const ImportState &state); -}; - -#endif // FBX_SKELETON_H diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h deleted file mode 100644 index 9ba60eaacf..0000000000 --- a/modules/fbx/data/import_state.h +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************/ -/* import_state.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 IMPORT_STATE_H -#define IMPORT_STATE_H - -#include "fbx_mesh_data.h" -#include "tools/import_utils.h" -#include "tools/validation_tools.h" - -#include "pivot_transform.h" - -#include "core/io/resource_importer.h" -#include "core/templates/vector.h" -#include "editor/import/resource_importer_scene.h" -#include "editor/project_settings_editor.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/animation.h" -#include "scene/resources/surface_tool.h" - -#include "modules/fbx/fbx_parser/FBXDocument.h" -#include "modules/fbx/fbx_parser/FBXImportSettings.h" -#include "modules/fbx/fbx_parser/FBXMeshGeometry.h" -#include "modules/fbx/fbx_parser/FBXParser.h" -#include "modules/fbx/fbx_parser/FBXTokenizer.h" -#include "modules/fbx/fbx_parser/FBXUtil.h" - -struct FBXBone; -struct FBXMeshData; -struct FBXNode; -struct FBXSkeleton; - -struct ImportState { - bool enable_material_import = true; - bool enable_animation_import = true; - bool is_blender_fbx = false; - - Map<StringName, Ref<Texture>> cached_image_searches; - Map<uint64_t, Ref<Material>> cached_materials; - - String path = String(); - Node3D *root_owner = nullptr; - Node3D *root = nullptr; - real_t scale = 0.01; - Ref<FBXNode> fbx_root_node = Ref<FBXNode>(); - // skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically. - Map<uint64_t, Ref<FBXSkeleton>> skeleton_map = Map<uint64_t, Ref<FBXSkeleton>>(); - - // nodes on the same level get merged automatically. - //Map<uint64_t, Skeleton3D *> armature_map; - AnimationPlayer *animation_player = nullptr; - - // Generation 4 - Raw document accessing for bone/skin/joint/kLocators - // joints are not necessarily bones but must be merged into the skeleton - // (bone id), bone - Map<uint64_t, Ref<FBXBone>> fbx_bone_map = Map<uint64_t, Ref<FBXBone>>(); // this is the bone name and setup information required for joints - // this will never contain joints only bones attached to a mesh. - - // Generation 4 - Raw document for creating the nodes transforms in the scene - // this is a list of the nodes in the scene - // (id, node) - List<Ref<FBXNode>> fbx_node_list = List<Ref<FBXNode>>(); - - // All nodes which have been created in the scene - // this will not contain the root node of the scene - Map<uint64_t, Ref<FBXNode>> fbx_target_map = Map<uint64_t, Ref<FBXNode>>(); - - // mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins - Map<uint64_t, Ref<FBXNode>> MeshNodes = Map<uint64_t, Ref<FBXNode>>(); - // mesh skin map - Map<uint64_t, Ref<Skin>> MeshSkins = Map<uint64_t, Ref<Skin>>(); - - // this is the container for the mesh weight information and eventually - // any mesh data - // but not the skin, just stuff important for rendering - // skin is applied to mesh instance so not really required to be in here yet. - // maybe later - // fbx mesh id, FBXMeshData - Map<uint64_t, Ref<FBXMeshData>> renderer_mesh_data = Map<uint64_t, Ref<FBXMeshData>>(); -}; - -#endif // IMPORT_STATE_H diff --git a/modules/fbx/data/model_abstraction.h b/modules/fbx/data/model_abstraction.h deleted file mode 100644 index 528960ab49..0000000000 --- a/modules/fbx/data/model_abstraction.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* model_abstraction.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 MODEL_ABSTRACTION_H -#define MODEL_ABSTRACTION_H - -#include "modules/fbx/fbx_parser/FBXDocument.h" - -struct ModelAbstraction { - mutable const FBXDocParser::Model *fbx_model = nullptr; - - void set_model(const FBXDocParser::Model *p_model) { - fbx_model = p_model; - } - - bool has_model() const { - return fbx_model != nullptr; - } - - const FBXDocParser::Model *get_model() const { - return fbx_model; - } -}; - -#endif // MODEL_ABSTRACTION_H diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp deleted file mode 100644 index 4cf42257a4..0000000000 --- a/modules/fbx/data/pivot_transform.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/*************************************************************************/ -/* pivot_transform.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 "pivot_transform.h" - -#include "tools/import_utils.h" - -void PivotTransform::ReadTransformChain() { - 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. - print_verbose("Model: " + String(fbx_model->Name().c_str()) + " Has inherit type: " + itos(fbx_model->InheritType())); - bool ok = false; - raw_pre_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", ok)); - if (ok) { - pre_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_pre_rotation)); - print_verbose("valid pre_rotation: " + raw_pre_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI))); - } - raw_post_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", ok)); - if (ok) { - post_rotation = ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder_EulerXYZ, ImportUtils::deg2rad(raw_post_rotation)); - print_verbose("valid post_rotation: " + raw_post_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI))); - } - const Vector3 &RotationPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationPivot", ok)); - if (ok) { - rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot); - } - const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationOffset", ok)); - if (ok) { - rotation_offset = ImportUtils::FixAxisConversions(RotationOffset); - } - const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingOffset", ok)); - if (ok) { - scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset); - } - const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingPivot", ok)); - if (ok) { - scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot); - } - const Vector3 &Translation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Translation", ok)); - if (ok) { - translation = ImportUtils::FixAxisConversions(Translation); - } - raw_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Rotation", ok)); - if (ok) { - rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation)); - } - const Vector3 &Scaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Scaling", ok)); - if (ok) { - scaling = Scaling; - } else { - scaling = Vector3(1, 1, 1); - } - const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricScaling", ok)); - if (ok) { - geometric_scaling = GeometricScaling; - } else { - geometric_scaling = Vector3(1, 1, 1); - } - - const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricRotation", ok)); - if (ok) { - geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation)); - } else { - geometric_rotation = Quaternion(); - } - - const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok)); - if (ok) { - geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation); - } else { - geometric_translation = Vector3(0, 0, 0); - } - - if (geometric_rotation != Quaternion()) { - print_error("geometric rotation is unsupported!"); - //CRASH_COND(true); - } - - if (!geometric_scaling.is_equal_approx(Vector3(1, 1, 1))) { - print_error("geometric scaling is unsupported!"); - //CRASH_COND(true); - } - - if (!geometric_translation.is_equal_approx(Vector3(0, 0, 0))) { - print_error("geometric translation is unsupported."); - //CRASH_COND(true); - } -} - -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 - - // Origin pivots - T.set_origin(p_translation); - Roff.set_origin(rotation_offset); - Rp.set_origin(rotation_pivot); - Soff.set_origin(scaling_offset); - Sp.set_origin(scaling_pivot); - - // Scaling node - S.scale(p_scaling); - // Rotation pivots - 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(); -} - -Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const { - Vector3 pos = t.origin; - Vector3 scale = t.basis.get_scale(); - Quaternion rot = t.basis.get_rotation_quaternion(); - return ComputeGlobalTransform(pos, rot, scale); -} - -Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const { - Vector3 pos = t.origin; - Vector3 scale = t.basis.get_scale(); - Quaternion rot = t.basis.get_rotation_quaternion(); - return ComputeLocalTransform(pos, rot, scale); -} - -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 - - // Origin pivots - T.set_origin(p_translation); - Roff.set_origin(rotation_offset); - Rp.set_origin(rotation_pivot); - Soff.set_origin(scaling_offset); - Sp.set_origin(scaling_pivot); - - // Scaling node - S.scale(p_scaling); - - // Rotation pivots - Transform3D Rpre = Transform3D(pre_rotation); - Transform3D R = Transform3D(p_rotation); - Transform3D Rpost = Transform3D(post_rotation); - - 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; - } - - 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_quaternion().normalized()); - - 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; - parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation; - local_shear_scaling = S; - - // Inherit type handler - we don't care about T here, just reordering RSrs etc. - 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) { - 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; - } - 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, 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() { - Transform3D T, Roff, Rp, Soff, Sp, S; - - // Here I assume this is the operation which needs done. - // Its WorldTransform * V - - // Origin pivots - T.set_origin(translation); - Roff.set_origin(rotation_offset); - Rp.set_origin(rotation_pivot); - Soff.set_origin(scaling_offset); - Sp.set_origin(scaling_pivot); - - // Scaling node - if (!scaling.is_equal_approx(Vector3())) { - S.scale(scaling); - } else { - S.scale(Vector3(1, 1, 1)); - } - Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this. - - // Rotation pivots - Transform3D Rpre = Transform3D(pre_rotation); - Transform3D R = Transform3D(rotation); - Transform3D Rpost = Transform3D(post_rotation); - - 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; - } - - 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_quaternion().normalized()); - - 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; - parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation; - local_shear_scaling = S; - - // Inherit type handler - we don't care about T here, just reordering RSrs etc. - 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) { - 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 = 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"); - - Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); - GlobalTransform = Transform3D(); - //GlobalTransform = parent_global_xform * LocalTransform; - Transform3D global_origin = Transform3D(Basis(), parent_translation); - GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale; - - ImportUtils::debug_xform("local xform calculation", LocalTransform); - print_verbose("scale of node: " + S.basis.get_scale_local()); - print_verbose("---------------------------------------------------------------"); -} - -void PivotTransform::Execute() { - ReadTransformChain(); - ComputePivotTransform(); - - ImportUtils::debug_xform("global xform: ", GlobalTransform); - - if (LocalTransform.basis.determinant() == 0) { - print_error("Serious det == 0!"); - } - - if (GlobalTransform.basis.determinant() == 0) { - print_error("Serious! node has det == 0!"); - } - - computed_global_xform = true; -} diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h deleted file mode 100644 index 099b268075..0000000000 --- a/modules/fbx/data/pivot_transform.h +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************/ -/* pivot_transform.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 PIVOT_TRANSFORM_H -#define PIVOT_TRANSFORM_H - -#include "core/math/transform_3d.h" -#include "core/object/ref_counted.h" - -#include "model_abstraction.h" - -#include "fbx_parser/FBXDocument.h" -#include "tools/import_utils.h" - -enum TransformationComp { - TransformationComp_Translation, - TransformationComp_Scaling, - TransformationComp_Rotation, - TransformationComp_RotationOffset, - TransformationComp_RotationPivot, - TransformationComp_PreRotation, - TransformationComp_PostRotation, - TransformationComp_ScalingOffset, - TransformationComp_ScalingPivot, - TransformationComp_GeometricTranslation, - TransformationComp_GeometricRotation, - TransformationComp_GeometricScaling, - TransformationComp_MAXIMUM -}; -// Abstract away pivot data so its simpler to handle -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. - 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); - Vector3 scaling_pivot = Vector3(1.0, 1.0, 1.0); - Vector3 translation = Vector3(); - Vector3 scaling = Vector3(1.0, 1.0, 1.0); - Vector3 geometric_scaling = Vector3(1.0, 1.0, 1.0); - Vector3 geometric_translation = Vector3(); - - Vector3 raw_rotation = Vector3(); - Vector3 raw_post_rotation = Vector3(); - Vector3 raw_pre_rotation = Vector3(); - - /* Read pivots from the document */ - void ReadTransformChain(); - - void debug_pivot_xform(String p_name) { - print_verbose("debugging node name: " + p_name); - print_verbose("raw rotation: " + raw_rotation * (180 / Math_PI)); - print_verbose("raw pre_rotation " + raw_pre_rotation * (180 / Math_PI)); - print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI)); - } - - 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(); - - /* Execute the command for the pivot generation */ - void Execute(); - - void set_parent(Ref<PivotTransform> p_parent) { - parent_transform = p_parent; - } - - bool computed_global_xform = false; - Ref<PivotTransform> parent_transform = Ref<PivotTransform>(); - //Transform chain[TransformationComp_MAXIMUM]; - - // cached for later use - 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 -}; - -#endif // PIVOT_TRANSFORM_H diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp deleted file mode 100644 index b11c145599..0000000000 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ /dev/null @@ -1,1470 +0,0 @@ -/*************************************************************************/ -/* editor_scene_importer_fbx.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 "editor_scene_importer_fbx.h" - -#include "data/fbx_anim_container.h" -#include "data/fbx_material.h" -#include "data/fbx_mesh_data.h" -#include "data/fbx_skeleton.h" -#include "tools/import_utils.h" - -#include "core/io/image_loader.h" -#include "editor/editor_log.h" -#include "editor/editor_node.h" -#include "editor/import/resource_importer_scene.h" -#include "scene/3d/bone_attachment_3d.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/light_3d.h" -#include "scene/main/node.h" -#include "scene/resources/material.h" - -#include "fbx_parser/FBXDocument.h" -#include "fbx_parser/FBXImportSettings.h" -#include "fbx_parser/FBXMeshGeometry.h" -#include "fbx_parser/FBXParser.h" -#include "fbx_parser/FBXProperties.h" -#include "fbx_parser/FBXTokenizer.h" - -#include <string> - -void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) const { - // register FBX as the one and only format for FBX importing - const String import_setting_string = "filesystem/import/fbx/"; - const String fbx_str = "fbx"; - Vector<String> exts; - exts.push_back(fbx_str); - _register_project_setting_import(fbx_str, import_setting_string, exts, r_extensions, true); -} - -void EditorSceneFormatImporterFBX::_register_project_setting_import(const String generic, - const String import_setting_string, - const Vector<String> &exts, - List<String> *r_extensions, - const bool p_enabled) const { - const String use_generic = "use_" + generic; - _GLOBAL_DEF(import_setting_string + use_generic, p_enabled, true); - if (ProjectSettings::get_singleton()->get(import_setting_string + use_generic)) { - for (int32_t i = 0; i < exts.size(); i++) { - r_extensions->push_back(exts[i]); - } - } -} - -uint32_t EditorSceneFormatImporterFBX::get_import_flags() const { - return IMPORT_SCENE; -} - -Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, - List<String> *r_missing_deps, Error *r_err) { - // done for performance when re-importing lots of files when testing importer in verbose only! - if (OS::get_singleton()->is_stdout_verbose()) { - EditorLog *log = EditorNode::get_log(); - log->clear(); - } - Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - - ERR_FAIL_COND_V(!f, nullptr); - - { - PackedByteArray data; - // broadphase tokenizing pass in which we identify the core - // syntax elements of FBX (brackets, commas, key:value mappings) - FBXDocParser::TokenList tokens; - - bool is_binary = false; - 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); - for (int32_t byte_i = 0; byte_i < 64; byte_i++) { - fbx_header.ptrw()[byte_i] = data.ptr()[byte_i]; - } - - String fbx_header_string; - if (fbx_header.size() >= 0) { - fbx_header_string.parse_utf8((const char *)fbx_header.ptr(), fbx_header.size()); - } - - 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(), corrupt); - - } else { - print_verbose("[doc] is ascii"); - 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: - // 1. Tokens are made, these are then taken into the 'parser' below - // 2. The parser constructs 'Elements' and all 'real' FBX Types. - // 3. This creates a problem: shared_ptr ownership, should Elements later 'take ownership' - // 4. No, it shouldn't so we should either a.) use weak ref for elements; but this is not correct. - - // 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; - - // this function leaks a lot - FBXDocParser::Document doc(parser, settings); - - // yeah so closing the file is a good idea (prevents readonly states) - f->close(); - - // safety for version handling - if (doc.IsSafeToImport()) { - bool is_blender_fbx = false; - 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); - if (app_name_string) { - print_verbose("FBX App Name: " + String(app_name_string->Value().c_str())); - } - } - - if (app_vendor) { - const FBXDocParser::TypedProperty<std::string> *app_vendor_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_vendor); - if (app_vendor_string) { - print_verbose("FBX App Vendor: " + String(app_vendor_string->Value().c_str())); - is_blender_fbx = app_vendor_string->Value().find("Blender") != std::string::npos; - } - } - - if (app_version) { - const FBXDocParser::TypedProperty<std::string> *app_version_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_version); - if (app_version_string) { - print_verbose("FBX App Version: " + String(app_version_string->Value().c_str())); - } - } - - if (is_blender_fbx) { - WARN_PRINT("We don't officially support Blender FBX animations yet, due to issues with upstream Blender,\n" - "so please wait for us to work around remaining issues. We will continue to import the file but it may be broken.\n" - "For minimal breakage, please export FBX from Blender with -Z forward, and Y up."); - } - - Node3D *spatial = _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8, is_blender_fbx); - // todo: move to document shutdown (will need to be validated after moving; this code has been validated already) - for (FBXDocParser::TokenPtr token : tokens) { - if (token) { - delete token; - token = nullptr; - } - } - - 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())); - } - } - - return memnew(Node3D); -} - -template <class T> -struct EditorSceneFormatImporterAssetImportInterpolate { - T lerp(const T &a, const T &b, float c) const { - return a + (b - a) * c; - } - - T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) { - const float t2 = t * t; - const float t3 = t2 * t; - - return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); - } - - T bezier(T start, T control_1, T control_2, T end, float t) { - /* Formula from Wikipedia article on Bezier curves. */ - const real_t omt = (1.0 - t); - const real_t omt2 = omt * omt; - const real_t omt3 = omt2 * omt; - const real_t t2 = t * t; - const real_t t3 = t2 * t; - - return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; - } -}; - -//thank you for existing, partial specialization -template <> -struct EditorSceneFormatImporterAssetImportInterpolate<Quaternion> { - Quaternion lerp(const Quaternion &a, const Quaternion &b, float c) const { - ERR_FAIL_COND_V(!a.is_normalized(), Quaternion()); - ERR_FAIL_COND_V(!b.is_normalized(), Quaternion()); - - return a.slerp(b, c).normalized(); - } - - 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(); - } - - 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(); - } -}; - -template <class T> -T EditorSceneFormatImporterFBX::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, - AssetImportAnimation::Interpolation p_interp) { - //could use binary search, worth it? - int idx = -1; - for (int i = 0; i < p_times.size(); i++) { - if (p_times[i] > p_time) { - break; - } - idx++; - } - - EditorSceneFormatImporterAssetImportInterpolate<T> interp; - - switch (p_interp) { - case AssetImportAnimation::INTERP_LINEAR: { - if (idx == -1) { - return p_values[0]; - } else if (idx >= p_times.size() - 1) { - return p_values[p_times.size() - 1]; - } - - float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - return interp.lerp(p_values[idx], p_values[idx + 1], c); - - } break; - case AssetImportAnimation::INTERP_STEP: { - if (idx == -1) { - return p_values[0]; - } else if (idx >= p_times.size() - 1) { - return p_values[p_times.size() - 1]; - } - - return p_values[idx]; - - } break; - case AssetImportAnimation::INTERP_CATMULLROMSPLINE: { - if (idx == -1) { - return p_values[1]; - } else if (idx >= p_times.size() - 1) { - return p_values[1 + p_times.size() - 1]; - } - - float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c); - - } break; - case AssetImportAnimation::INTERP_CUBIC_SPLINE: { - if (idx == -1) { - return p_values[1]; - } else if (idx >= p_times.size() - 1) { - return p_values[(p_times.size() - 1) * 3 + 1]; - } - - float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - T from = p_values[idx * 3 + 1]; - T c1 = from + p_values[idx * 3 + 2]; - T to = p_values[idx * 3 + 4]; - T c2 = to + p_values[idx * 3 + 3]; - - return interp.bezier(from, c1, c2, to, c); - - } break; - } - - ERR_FAIL_V(p_values[0]); -} - -Node3D *EditorSceneFormatImporterFBX::_generate_scene( - const String &p_path, - const FBXDocParser::Document *p_document, - const uint32_t p_flags, - int p_bake_fps, - const int32_t p_max_bone_weights, - bool p_is_blender_fbx) { - ImportState state; - state.is_blender_fbx = p_is_blender_fbx; - state.path = p_path; - state.animation_player = nullptr; - - // create new root node for scene - Node3D *scene_root = memnew(Node3D); - state.root = memnew(Node3D); - state.root_owner = scene_root; // the real scene root... sorry compatibility code is painful... - - state.root->set_name("RootNode"); - scene_root->add_child(state.root); - state.root->set_owner(scene_root); - - state.fbx_root_node.instantiate(); - state.fbx_root_node->godot_node = state.root; - - // Size relative to cm. - const real_t fbx_unit_scale = p_document->GlobalSettingsPtr()->UnitScaleFactor(); - - print_verbose("FBX unit scale import value: " + rtos(fbx_unit_scale)); - // Set FBX file scale is relative to CM must be converted to M - state.scale = fbx_unit_scale / 100.0; - print_verbose("FBX unit scale is: " + rtos(state.scale)); - - // Enabled by default. - state.enable_material_import = true; - // Enabled by default. - state.enable_animation_import = true; - Ref<FBXNode> root_node; - root_node.instantiate(); - - // make sure fake noFBXDocParser::PropertyPtr ptrde always has a transform too ;) - Ref<PivotTransform> pivot_transform; - pivot_transform.instantiate(); - root_node->pivot_transform = pivot_transform; - root_node->node_name = "root node"; - root_node->current_node_id = 0; - root_node->godot_node = state.root; - - // cache this node onto the fbx_target map. - state.fbx_target_map.insert(0, root_node); - - // cache basic node information from FBX document - // grabs all FBX bones - BuildDocumentBones(Ref<FBXBone>(), state, p_document, 0L); - BuildDocumentNodes(Ref<PivotTransform>(), state, p_document, 0L, nullptr); - - // Build document skinning information - - // Algorithm is this: - // Get Deformer: object with "Skin" class. - // Deformer:: has link to Geometry:: (correct mesh for skin) - // Deformer:: has Source which is the SubDeformer:: (e.g. the Cluster) - // Notes at the end it configures the vertex weight mapping. - - for (uint64_t skin_id : p_document->GetSkinIDs()) { - // Validate the parser - FBXDocParser::LazyObject *lazy_skin = p_document->GetObject(skin_id); - ERR_CONTINUE_MSG(lazy_skin == nullptr, "invalid lazy object [serious parser bug]"); - - // Validate the parser - const FBXDocParser::Skin *skin = lazy_skin->Get<FBXDocParser::Skin>(); - ERR_CONTINUE_MSG(skin == nullptr, "invalid skin added to skin list [parser bug]"); - - const std::vector<const FBXDocParser::Connection *> source_to_destination = p_document->GetConnectionsBySourceSequenced(skin_id); - FBXDocParser::MeshGeometry *mesh = nullptr; - uint64_t mesh_id = 0; - - // Most likely only contains the mesh link for the skin - // The mesh geometry. - for (const FBXDocParser::Connection *con : source_to_destination) { - // do something - print_verbose("src: " + itos(con->src)); - FBXDocParser::Object *ob = con->DestinationObject(); - mesh = dynamic_cast<FBXDocParser::MeshGeometry *>(ob); - - if (mesh) { - mesh_id = mesh->ID(); - break; - } - } - - // Validate the mesh exists and was retrieved - ERR_CONTINUE_MSG(mesh_id == 0, "mesh id is invalid"); - const std::vector<const FBXDocParser::Cluster *> clusters = skin->Clusters(); - - // NOTE: this will ONLY work on skinned bones (it is by design.) - // A cluster is a skinned bone so SKINS won't contain unskinned bones so we need to pre-add all bones and parent them in a step beforehand. - for (const FBXDocParser::Cluster *cluster : clusters) { - ERR_CONTINUE_MSG(cluster == nullptr, "invalid bone cluster"); - const uint64_t deformer_id = cluster->ID(); - std::vector<const FBXDocParser::Connection *> connections = p_document->GetConnectionsByDestinationSequenced(deformer_id); - - // Weight data always has a node in the scene lets grab the limb's node in the scene :) (reverse set to true since it's the opposite way around) - const FBXDocParser::ModelLimbNode *limb_node = ProcessDOMConnection<FBXDocParser::ModelLimbNode>(p_document, deformer_id, true); - - ERR_CONTINUE_MSG(limb_node == nullptr, "unable to resolve model for skinned bone"); - - const uint64_t model_id = limb_node->ID(); - - // This will never happen, so if it does you know you fucked up. - ERR_CONTINUE_MSG(!state.fbx_bone_map.has(model_id), "missing LimbNode detected"); - - // new bone instance - Ref<FBXBone> bone_element = state.fbx_bone_map[model_id]; - - // - // Bone Weight Information Configuration - // - - // Cache Weight Information into bone for later usage if you want the raw data. - const std::vector<unsigned int> &indexes = cluster->GetIndices(); - const std::vector<float> &weights = cluster->GetWeights(); - Ref<FBXMeshData> mesh_vertex_data; - - // this data will pre-exist if vertex weight information is found - if (state.renderer_mesh_data.has(mesh_id)) { - mesh_vertex_data = state.renderer_mesh_data[mesh_id]; - } else { - mesh_vertex_data.instantiate(); - state.renderer_mesh_data.insert(mesh_id, mesh_vertex_data); - } - - mesh_vertex_data->armature_id = bone_element->armature_id; - mesh_vertex_data->valid_armature_id = true; - - //print_verbose("storing mesh vertex data for mesh to use later"); - ERR_CONTINUE_MSG(indexes.size() != weights.size(), "[doc] error mismatch between weight info"); - - for (size_t idx = 0; idx < indexes.size(); idx++) { - const size_t vertex_index = indexes[idx]; - const real_t influence_weight = weights[idx]; - - VertexWeightMapping &vm = mesh_vertex_data->vertex_weights[vertex_index]; - vm.weights.push_back(influence_weight); - vm.bones.push_back(0); // bone id is pushed on here during sanitization phase - vm.bones_ref.push_back(bone_element); - } - - for (const int *vertex_index = mesh_vertex_data->vertex_weights.next(nullptr); - vertex_index != nullptr; - vertex_index = mesh_vertex_data->vertex_weights.next(vertex_index)) { - VertexWeightMapping *vm = mesh_vertex_data->vertex_weights.getptr(*vertex_index); - const int influence_count = vm->weights.size(); - if (influence_count > mesh_vertex_data->max_weight_count) { - mesh_vertex_data->max_weight_count = influence_count; - mesh_vertex_data->valid_weight_count = true; - } - } - - if (mesh_vertex_data->max_weight_count > 4) { - if (mesh_vertex_data->max_weight_count > 8) { - ERR_PRINT("[doc] Serious: maximum bone influences is 8 in this branch."); - } - // Clamp to 8 bone vertex influences. - mesh_vertex_data->max_weight_count = 8; - print_verbose("[doc] Using 8 vertex bone influences configuration."); - } else { - mesh_vertex_data->max_weight_count = 4; - print_verbose("[doc] Using 4 vertex bone influences configuration."); - } - } - } - - // do we globally allow for import of materials - // (prevents overwrite of materials; so you can handle them explicitly) - if (state.enable_material_import) { - const std::vector<uint64_t> &materials = p_document->GetMaterialIDs(); - - for (uint64_t material_id : materials) { - FBXDocParser::LazyObject *lazy_material = p_document->GetObject(material_id); - FBXDocParser::Material *mat = (FBXDocParser::Material *)lazy_material->Get<FBXDocParser::Material>(); - ERR_CONTINUE_MSG(!mat, "Could not convert fbx material by id: " + itos(material_id)); - - Ref<FBXMaterial> material; - material.instantiate(); - material->set_imported_material(mat); - - Ref<StandardMaterial3D> godot_material = material->import_material(state); - - state.cached_materials.insert(material_id, godot_material); - } - } - - // build skin and skeleton information - print_verbose("[doc] Skeleton3D Bone count: " + itos(state.fbx_bone_map.size())); - - // Importing bones using document based method from FBX directly - // We do not use the assimp bone format to determine this information anymore. - if (state.fbx_bone_map.size() > 0) { - // We are using a single skeleton only method here - // this is because we really have no concept of skeletons in FBX - // their are bones in a scene but they have no specific armature - // we can detect armatures but the issue lies in the complexity - // we opted to merge the entire scene onto one skeleton for now - // if we need to change this we have an archive of the old code. - - // bind pose normally only has 1 per mesh but can have more than one - // this is the point of skins - // in FBX first bind pose is the master for the first skin - - // In order to handle the FBX skeleton we must also inverse any parent transforms on the bones - // just to rule out any parent node transforms in the bone data - // this is trivial to do and allows us to use the single skeleton method and merge them - // this means that the nodes from maya kLocators will be preserved as bones - // in the same rig without having to match this across skeletons and merge by detection - // we can just merge and undo any parent transforms - for (KeyValue<uint64_t, Ref<FBXBone>> &bone_element : state.fbx_bone_map) { - Ref<FBXBone> bone = bone_element.value; - Ref<FBXSkeleton> fbx_skeleton_inst; - - uint64_t armature_id = bone->armature_id; - if (state.skeleton_map.has(armature_id)) { - fbx_skeleton_inst = state.skeleton_map[armature_id]; - } else { - fbx_skeleton_inst.instantiate(); - state.skeleton_map.insert(armature_id, fbx_skeleton_inst); - } - - print_verbose("populating skeleton with bone: " + bone->bone_name); - - //// populate bone skeleton - since fbx has no DOM for the skeleton just a node. - //bone->bone_skeleton = fbx_skeleton_inst; - - // now populate bone on the armature node list - fbx_skeleton_inst->skeleton_bones.push_back(bone); - - CRASH_COND_MSG(!state.fbx_target_map.has(armature_id), "invalid armature [serious]"); - - Ref<FBXNode> node = state.fbx_target_map[armature_id]; - - CRASH_COND_MSG(node.is_null(), "invalid node [serious]"); - CRASH_COND_MSG(node->pivot_transform.is_null(), "invalid pivot transform [serious]"); - fbx_skeleton_inst->fbx_node = node; - - ERR_CONTINUE_MSG(fbx_skeleton_inst->fbx_node.is_null(), "invalid skeleton node [serious]"); - - // we need to have a valid armature id and the model configured for the bone to be assigned fully. - // happens once per skeleton - - if (state.fbx_target_map.has(armature_id) && !fbx_skeleton_inst->fbx_node->has_model()) { - print_verbose("allocated fbx skeleton primary / armature node for the level: " + fbx_skeleton_inst->fbx_node->node_name); - } else if (!state.fbx_target_map.has(armature_id) && !fbx_skeleton_inst->fbx_node->has_model()) { - print_error("bones are not mapped to an armature node for armature id: " + itos(armature_id) + " bone: " + bone->bone_name); - // this means bone will be removed and not used, which is safe actually and no skeleton will be created. - } - } - - // setup skeleton instances if required :) - for (KeyValue<uint64_t, Ref<FBXSkeleton>> &skeleton_node : state.skeleton_map) { - Ref<FBXSkeleton> &skeleton = skeleton_node.value; - skeleton->init_skeleton(state); - - ERR_CONTINUE_MSG(skeleton->fbx_node.is_null(), "invalid fbx target map, missing skeleton"); - } - - // This list is not populated - for (Map<uint64_t, Ref<FBXNode>>::Element *skin_mesh = state.MeshNodes.front(); skin_mesh; skin_mesh = skin_mesh->next()) { - } - } - - // build godot node tree - if (state.fbx_node_list.size() > 0) { - for (List<Ref<FBXNode>>::Element *node_element = state.fbx_node_list.front(); - node_element; - node_element = node_element->next()) { - Ref<FBXNode> fbx_node = node_element->get(); - ImporterMeshInstance3D *mesh_node = nullptr; - Ref<FBXMeshData> mesh_data_precached; - - // check for valid geometry - if (fbx_node->fbx_model == nullptr) { - print_error("[doc] fundamental flaw, submit bug immediately with full import log with verbose logging on"); - } else { - const std::vector<const FBXDocParser::Geometry *> &geometry = fbx_node->fbx_model->GetGeometry(); - for (const FBXDocParser::Geometry *mesh : geometry) { - print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name); - - if (mesh == nullptr) { - continue; - } - - const FBXDocParser::MeshGeometry *mesh_geometry = dynamic_cast<const FBXDocParser::MeshGeometry *>(mesh); - if (mesh_geometry) { - uint64_t mesh_id = mesh_geometry->ID(); - - // this data will pre-exist if vertex weight information is found - if (state.renderer_mesh_data.has(mesh_id)) { - mesh_data_precached = state.renderer_mesh_data[mesh_id]; - } else { - 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, false); - if (!state.MeshNodes.has(mesh_id)) { - state.MeshNodes.insert(mesh_id, fbx_node); - } - } - - const FBXDocParser::ShapeGeometry *shape_geometry = dynamic_cast<const FBXDocParser::ShapeGeometry *>(mesh); - if (shape_geometry != nullptr) { - print_verbose("[doc] valid shape geometry converted"); - } - } - } - - Ref<FBXSkeleton> node_skeleton = fbx_node->skeleton_node; - - if (node_skeleton.is_valid()) { - Skeleton3D *skel = node_skeleton->skeleton; - fbx_node->godot_node = skel; - } else if (mesh_node == nullptr) { - fbx_node->godot_node = memnew(Node3D); - } else { - fbx_node->godot_node = mesh_node; - } - - fbx_node->godot_node->set_name(fbx_node->node_name); - - // assign parent if valid - if (fbx_node->fbx_parent.is_valid()) { - fbx_node->fbx_parent->godot_node->add_child(fbx_node->godot_node); - fbx_node->godot_node->set_owner(state.root_owner); - } - - // Node Transform debug, set local xform data. - fbx_node->godot_node->set_transform(get_unscaled_transform(fbx_node->pivot_transform->LocalTransform, state.scale)); - - // populate our mesh node reference - if (mesh_node != nullptr && mesh_data_precached.is_valid()) { - mesh_data_precached->godot_mesh_instance = mesh_node; - } - } - } - - for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) { - const uint64_t mesh_id = mesh_data.key; - Ref<FBXMeshData> mesh = mesh_data.value; - - const FBXDocParser::MeshGeometry *mesh_geometry = p_document->GetObject(mesh_id)->Get<FBXDocParser::MeshGeometry>(); - - ERR_CONTINUE_MSG(mesh->mesh_node.is_null(), "invalid mesh allocation"); - - const FBXDocParser::Skin *mesh_skin = mesh_geometry->DeformerSkin(); - - if (!mesh_skin) { - continue; // safe to continue - } - - // - // Skin bone configuration - // - - // - // Get Mesh Node Xform only - // - //ERR_CONTINUE_MSG(!state.fbx_target_map.has(mesh_id), "invalid xform for the skin pose: " + itos(mesh_id)); - //Ref<FBXNode> mesh_node_xform_data = state.fbx_target_map[mesh_id]; - - if (!mesh_skin) { - continue; // not a deformer. - } - - if (mesh_skin->Clusters().size() == 0) { - continue; // possibly buggy mesh - } - - // Lookup skin or create it if it's not found. - Ref<Skin> skin; - if (!state.MeshSkins.has(mesh_id)) { - print_verbose("Created new skin"); - skin.instantiate(); - state.MeshSkins.insert(mesh_id, skin); - } else { - print_verbose("Grabbed skin"); - skin = state.MeshSkins[mesh_id]; - } - - for (const FBXDocParser::Cluster *cluster : mesh_skin->Clusters()) { - // node or bone this cluster targets (in theory will only be a bone target) - uint64_t skin_target_id = cluster->TargetNode()->ID(); - - print_verbose("adding cluster [" + itos(cluster->ID()) + "] " + String(cluster->Name().c_str()) + " for target: [" + itos(skin_target_id) + "] " + String(cluster->TargetNode()->Name().c_str())); - ERR_CONTINUE_MSG(!state.fbx_bone_map.has(skin_target_id), "no bone found by that ID? locator"); - - const Ref<FBXBone> bone = state.fbx_bone_map[skin_target_id]; - const Ref<FBXSkeleton> skeleton = bone->fbx_skeleton; - const Ref<FBXNode> skeleton_node = skeleton->fbx_node; - - skin->add_named_bind( - bone->bone_name, - get_unscaled_transform( - skeleton_node->pivot_transform->GlobalTransform.affine_inverse() * cluster->TransformLink().affine_inverse(), state.scale)); - } - - print_verbose("cluster name / id: " + String(mesh_skin->Name().c_str()) + " [" + itos(mesh_skin->ID()) + "]"); - print_verbose("skeleton has " + itos(state.fbx_bone_map.size()) + " binds"); - print_verbose("fbx skin has " + itos(mesh_skin->Clusters().size()) + " binds"); - } - - // mesh data iteration for populating skeleton mapping - for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) { - Ref<FBXMeshData> mesh = mesh_data.value; - const uint64_t mesh_id = mesh_data.key; - ImporterMeshInstance3D *mesh_instance = mesh->godot_mesh_instance; - const int mesh_weights = mesh->max_weight_count; - Ref<FBXSkeleton> skeleton; - const bool valid_armature = mesh->valid_armature_id; - const uint64_t armature = mesh->armature_id; - - if (mesh_weights > 0) { - // this is a bug, it means the weights were found but the skeleton wasn't - ERR_CONTINUE_MSG(!valid_armature, "[doc] fbx armature is missing"); - } else { - continue; // safe to continue not a bug just a normal mesh - } - - if (state.skeleton_map.has(armature)) { - skeleton = state.skeleton_map[armature]; - print_verbose("[doc] armature mesh to skeleton mapping has been allocated"); - } else { - print_error("[doc] unable to find armature mapping"); - } - - ERR_CONTINUE_MSG(!mesh_instance, "[doc] invalid mesh mapping for skeleton assignment"); - ERR_CONTINUE_MSG(skeleton.is_null(), "[doc] unable to resolve the correct skeleton but we have weights!"); - - mesh_instance->set_skeleton_path(mesh_instance->get_path_to(skeleton->skeleton)); - print_verbose("[doc] allocated skeleton to mesh " + mesh_instance->get_name()); - - // do we have a mesh skin for this mesh - ERR_CONTINUE_MSG(!state.MeshSkins.has(mesh_id), "no skin found for mesh"); - - Ref<Skin> mesh_skin = state.MeshSkins[mesh_id]; - - ERR_CONTINUE_MSG(mesh_skin.is_null(), "invalid skin stored in map"); - print_verbose("[doc] allocated skin to mesh " + mesh_instance->get_name()); - mesh_instance->set_skin(mesh_skin); - } - - // build skin and skeleton information - print_verbose("[doc] Skeleton3D Bone count: " + itos(state.fbx_bone_map.size())); - const FBXDocParser::FileGlobalSettings *FBXSettings = p_document->GlobalSettingsPtr(); - - // Configure constraints - // NOTE: constraints won't be added quite yet, we don't have a real need for them *yet*. (they can be supported later on) - // const std::vector<uint64_t> fbx_constraints = p_document->GetConstraintStackIDs(); - - // get the animation FPS - float fps_setting = ImportUtils::get_fbx_fps(FBXSettings); - - // enable animation import, only if local animation is enabled - if (state.enable_animation_import && (p_flags & IMPORT_ANIMATION)) { - // document animation stack list - get by ID so we can unload any non used animation stack - const std::vector<uint64_t> animation_stack = p_document->GetAnimationStackIDs(); - - for (uint64_t anim_id : animation_stack) { - FBXDocParser::LazyObject *lazyObject = p_document->GetObject(anim_id); - const FBXDocParser::AnimationStack *stack = lazyObject->Get<FBXDocParser::AnimationStack>(); - - if (stack != nullptr) { - String animation_name = ImportUtils::FBXNodeToName(stack->Name()); - print_verbose("Valid animation stack has been found: " + animation_name); - // ReferenceTime is the same for some animations? - // LocalStop time is the start and end time - float r_start = CONVERT_FBX_TIME(stack->ReferenceStart()); - float r_stop = CONVERT_FBX_TIME(stack->ReferenceStop()); - float start_time = CONVERT_FBX_TIME(stack->LocalStart()); - float end_time = CONVERT_FBX_TIME(stack->LocalStop()); - float duration = end_time - start_time; - - print_verbose("r_start " + rtos(r_start) + ", r_stop " + rtos(r_stop)); - print_verbose("start_time" + rtos(start_time) + " end_time " + rtos(end_time)); - print_verbose("anim duration : " + rtos(duration)); - - // we can safely create the animation player - if (state.animation_player == nullptr) { - print_verbose("Creating animation player"); - state.animation_player = memnew(AnimationPlayer); - state.root->add_child(state.animation_player, true); - state.animation_player->set_owner(state.root_owner); - } - - Ref<Animation> animation; - animation.instantiate(); - animation->set_name(animation_name); - animation->set_length(duration); - - print_verbose("Animation length: " + rtos(animation->get_length()) + " seconds"); - - // i think assimp was duplicating things, this lets me know to just reference or ignore this to prevent duplicate information in tracks - // this would mean that we would be doing three times as much work per track if my theory is correct. - // this was not the case but this is a good sanity check for the animation handler from the document. - // it also lets us know if the FBX specification massively changes the animation system, in theory such a change would make this show - // an fbx specification error, so best keep it in - // the overhead is tiny. - Map<uint64_t, const FBXDocParser::AnimationCurve *> CheckForDuplication; - - const std::vector<const FBXDocParser::AnimationLayer *> &layers = stack->Layers(); - print_verbose("FBX Animation layers: " + itos(layers.size())); - for (const FBXDocParser::AnimationLayer *layer : layers) { - std::vector<const FBXDocParser::AnimationCurveNode *> node_list = layer->Nodes(); - print_verbose("Layer: " + ImportUtils::FBXNodeToName(layer->Name()) + ", " + " AnimCurveNode count " + itos(node_list.size())); - - // first thing to do here is that i need to first get the animcurvenode to a Vector3 - // we now need to put this into the track information for godot. - // to do this we need to know which track is what? - - // target id, [ track name, [time index, vector] ] - // new map needs to be [ track name, keyframe_data ] - Map<uint64_t, Map<StringName, FBXTrack>> AnimCurveNodes; - - // struct AnimTrack { - // // Animation track can be - // // visible, T, R, S - // Map<StringName, Map<uint64_t, Vector3> > animation_track; - // }; - - // Map<uint64_t, AnimTrack> AnimCurveNodes; - - // so really, what does this mean to make an animtion track. - // 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 quaternion_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ; - - // T:: R:: S:: Visible:: Custom:: - for (const FBXDocParser::AnimationCurveNode *curve_node : node_list) { - // when Curves() is called the curves are actually read, we could replace this with our own ProcessDomConnection code here if required. - // We may need to do this but ideally we use Curves - // note: when you call this there might be a delay in opening it - // uses mutable type to 'cache' the response until the AnimationCurveNode is cleaned up. - std::map<std::string, const FBXDocParser::AnimationCurve *> curves = curve_node->Curves(); - const FBXDocParser::Object *object = curve_node->Target(); - const FBXDocParser::Model *target = curve_node->TargetAsModel(); - if (target == nullptr) { - if (object != nullptr) { - print_error("[doc] warning failed to find a target Model for curve: " + String(object->Name().c_str())); - } else { - //print_error("[doc] failed to resolve object"); - continue; - } - - continue; - } else { - //print_verbose("[doc] applied rotation order: " + itos(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; - 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); - float offset_z = FBXDocParser::PropertyGet<float>(properties, "d|Z", got_z); - - String curve_node_name = ImportUtils::FBXNodeToName(curve_node->Name()); - - // Reduce all curves for this node into a single container - // T, R, S is what we expect, although other tracks are possible - // like for example visibility tracks. - - // We are not ordered here, we don't care about ordering, this happens automagically by godot when we insert with the - // key time :), so order is unimportant because the insertion will happen at a time index - // good to know: we do not need a list of these in another format :) - //Map<String, Vector<const Assimp::FBX::AnimationCurve *> > unordered_track; - - // T - // R - // S - // Map[String, List<VECTOR>] - - // So this is a reduction of the animation curve nodes - // We build this as a lookup, this is essentially our 'animation track' - //AnimCurveNodes.insert(curve_node_name, Map<uint64_t, Vector3>()); - - // create the animation curve information with the target id - // so the point of this makes a track with the name "T" for example - // the target ID is also set here, this means we don't need to do anything extra when we are in the 'create all animation tracks' step - FBXTrack &keyframe_map = AnimCurveNodes[target_id][StringName(curve_node_name)]; - - if (got_x && got_y && got_z) { - Vector3 default_value = Vector3(offset_x, offset_y, offset_z); - keyframe_map.default_value = default_value; - keyframe_map.has_default = true; - //print_verbose("track name: " + curve_node_name); - //print_verbose("xyz default: " + default_value); - } - // target id, [ track name, [time index, vector] ] - // Map<uint64_t, Map<StringName, Map<uint64_t, Vector3> > > AnimCurveNodes; - - // we probably need the target id here. - // so map[uint64_t map]... - // Map<uint64_t, Vector3D> translation_keys, rotation_keys, scale_keys; - - // extra const required by C++11 colon/Range operator - // note: do not use C++17 syntax here for dicts. - // this is banned in Godot. - for (std::pair<const std::string, const FBXDocParser::AnimationCurve *> &kvp : curves) { - const String curve_element = ImportUtils::FBXNodeToName(kvp.first); - const FBXDocParser::AnimationCurve *curve = kvp.second; - String curve_name = ImportUtils::FBXNodeToName(curve->Name()); - uint64_t curve_id = curve->ID(); - - if (CheckForDuplication.has(curve_id)) { - print_error("(FBX spec changed?) We found a duplicate curve being used for an alternative node - report to godot issue tracker"); - } else { - CheckForDuplication.insert(curve_id, curve); - } - - // FBX has no name for AnimCurveNode::, most of the time, not seen any with valid name here. - const std::map<int64_t, float> &track_time = curve->GetValueTimeTrack(); - - if (track_time.size() > 0) { - for (std::pair<int64_t, float> keyframe : track_time) { - if (curve_element == "d|X") { - keyframe_map.keyframes[keyframe.first].x = keyframe.second; - } else if (curve_element == "d|Y") { - keyframe_map.keyframes[keyframe.first].y = keyframe.second; - } else if (curve_element == "d|Z") { - keyframe_map.keyframes[keyframe.first].z = keyframe.second; - } else { - //print_error("FBX Unsupported element: " + curve_element); - } - - //print_verbose("[" + itos(target_id) + "] Keyframe added: " + itos(keyframe_map.size())); - - //print_verbose("Keyframe t:" + rtos(animation_track_time) + " v: " + rtos(keyframe.second)); - } - } - } - } - - // Map<uint64_t, Map<StringName, Map<uint64_t, Vector3> > > AnimCurveNodes; - // add this animation track here - - // target id, [ track name, [time index, vector] ] - //std::map<uint64_t, std::map<StringName, FBXTrack > > AnimCurveNodes; - for (KeyValue<uint64_t, Map<StringName, FBXTrack>> &track : AnimCurveNodes) { - // 5 tracks - // current track index - // track count is 5 - // track count is 5. - // next track id is 5. - const uint64_t target_id = track.key; - - 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. - // remember that state.fbx_bone_map[target_id] will create a new entry EVEN if you only read. - // this would break node animation targets, so if you change this be warned. :) - if (state.fbx_bone_map.has(target_id)) { - bone = state.fbx_bone_map[target_id]; - } - - Transform3D target_transform; - - if (state.fbx_target_map.has(target_id)) { - Ref<FBXNode> node_ref = state.fbx_target_map[target_id]; - target_transform = node_ref->pivot_transform->GlobalTransform; - //print_verbose("[doc] allocated animation node transform"); - } - - //int size_targets = state.fbx_target_map.size(); - //print_verbose("Target ID map: " + itos(size_targets)); - //print_verbose("[doc] debug bone map size: " + itos(state.fbx_bone_map.size())); - - // if this is a skeleton mapped track we can just set the path for the track. - // todo: implement node paths here at some - NodePath track_path; - if (state.fbx_bone_map.size() > 0 && state.fbx_bone_map.has(target_id)) { - if (bone->fbx_skeleton.is_valid() && bone.is_valid()) { - Ref<FBXSkeleton> fbx_skeleton = bone->fbx_skeleton; - String bone_path = state.root->get_path_to(fbx_skeleton->skeleton); - bone_path += ":" + fbx_skeleton->skeleton->get_bone_name(bone->godot_bone_id); - print_verbose("[doc] track bone path: " + bone_path); - track_path = bone_path; - } - } else if (state.fbx_target_map.has(target_id)) { - //print_verbose("[doc] we have a valid target for a node animation"); - Ref<FBXNode> target_node = state.fbx_target_map[target_id]; - if (target_node.is_valid() && target_node->godot_node != nullptr) { - String node_path = state.root->get_path_to(target_node->godot_node); - track_path = node_path; - //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 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; - } - - // everything in FBX and Maya is a node therefore if this happens something is seriously broken. - if (!state.fbx_target_map.has(target_id)) { - print_error("unable to resolve this to an FBX object."); - continue; - } - - Ref<FBXNode> target_node = state.fbx_target_map[target_id]; - const FBXDocParser::Model *model = target_node->fbx_model; - const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model); - - Map<StringName, FBXTrack> &track_data = track.value; - FBXTrack &translation_keys = track_data[StringName("T")]; - FBXTrack &rotation_keys = track_data[StringName("R")]; - FBXTrack &scale_keys = track_data[StringName("S")]; - - double increment = 1.0f / fps_setting; - double time = 0.0f; - - bool last = false; - - Vector<Vector3> pos_values; - Vector<float> pos_times; - Vector<Vector3> scale_values; - Vector<float> scale_times; - Vector<Quaternion> rot_values; - Vector<float> rot_times; - - double max_duration = 0; - double anim_length = animation->get_length(); - - for (std::pair<int64_t, Vector3> position_key : translation_keys.keyframes) { - pos_values.push_back(position_key.second * state.scale); - double animation_track_time = CONVERT_FBX_TIME(position_key.first); - - if (animation_track_time > max_duration) { - max_duration = animation_track_time; - } - - //print_verbose("pos keyframe: t:" + rtos(animation_track_time) + " value " + position_key.second); - pos_times.push_back(animation_track_time); - } - - for (std::pair<int64_t, Vector3> scale_key : scale_keys.keyframes) { - scale_values.push_back(scale_key.second); - double animation_track_time = CONVERT_FBX_TIME(scale_key.first); - - if (animation_track_time > max_duration) { - max_duration = animation_track_time; - } - //print_verbose("scale keyframe t:" + rtos(animation_track_time)); - scale_times.push_back(animation_track_time); - } - - // - // Pre and Post keyframe rotation handler - // -- Required because Maya and Autodesk <3 the pain when it comes to implementing animation code! enjoy <3 - - bool got_pre = false; - bool got_post = false; - - Quaternion post_rotation; - Quaternion pre_rotation; - - // Rotation matrix - const Vector3 &PreRotation = FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", got_pre); - const Vector3 &PostRotation = FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", got_post); - - FBXDocParser::Model::RotOrder rot_order = model->RotationOrder(); - if (got_pre) { - pre_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PreRotation)); - } - if (got_post) { - post_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PostRotation)); - } - - 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); - Quaternion rot_key_value = ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_key.second)); - - 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 - Quaternion final_rotation = pre_rotation * rot_key_value * post_rotation; - - lastQuaternion = final_rotation; - - if (animation_track_time > max_duration) { - max_duration = animation_track_time; - } - - rot_values.push_back(final_rotation.normalized()); - rot_times.push_back(animation_track_time); - } - - bool valid_rest = false; - Transform3D bone_rest; - int skeleton_bone = -1; - if (state.fbx_bone_map.has(target_id)) { - if (bone.is_valid() && bone->fbx_skeleton.is_valid()) { - skeleton_bone = bone->godot_bone_id; - if (skeleton_bone >= 0) { - bone_rest = bone->fbx_skeleton->skeleton->get_bone_rest(skeleton_bone); - valid_rest = true; - } - } - - if (!valid_rest) { - print_verbose("invalid rest!"); - } - } - - const Vector3 def_pos = translation_keys.has_default ? (translation_keys.default_value * state.scale) : bone_rest.origin; - 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 + ")"); - - int position_idx = -1; - if (pos_values.size()) { - position_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_POSITION_3D); - animation->track_set_path(position_idx, track_path); - animation->track_set_imported(position_idx, true); - } - - int rotation_idx = -1; - if (pos_values.size()) { - rotation_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_ROTATION_3D); - animation->track_set_path(rotation_idx, track_path); - animation->track_set_imported(rotation_idx, true); - } - - int scale_idx = -1; - if (pos_values.size()) { - scale_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_SCALE_3D); - animation->track_set_path(scale_idx, track_path); - animation->track_set_imported(scale_idx, true); - } - - while (true) { - Vector3 pos = def_pos; - Quaternion rot = def_rot; - Vector3 scale = def_scale; - - if (pos_values.size()) { - pos = _interpolate_track<Vector3>(pos_times, pos_values, time, - AssetImportAnimation::INTERP_LINEAR); - } - - if (rot_values.size()) { - rot = _interpolate_track<Quaternion>(rot_times, rot_values, time, - AssetImportAnimation::INTERP_LINEAR); - } - - if (scale_values.size()) { - scale = _interpolate_track<Vector3>(scale_times, scale_values, time, - AssetImportAnimation::INTERP_LINEAR); - } - - if (position_idx >= 0) { - animation->position_track_insert_key(position_idx, time, pos); - } - if (rotation_idx >= 0) { - animation->rotation_track_insert_key(rotation_idx, time, rot); - } - if (scale_idx >= 0) { - animation->scale_track_insert_key(scale_idx, time, scale); - } - - if (last) { - break; - } - - time += increment; - if (time > anim_length) { - last = true; - time = anim_length; - break; - } - } - } - } - state.animation_player->add_animation(animation_name, animation); - } - } - - // AnimStack elements contain start stop time and name of animation - // AnimLayer is the current active layer of the animation (multiple layers can be active we only support 1) - // AnimCurveNode has a OP link back to the model which is the real node. - // AnimCurveNode has a direct link to AnimationCurve (of which it may have more than one) - - // Store animation stack in list - // iterate over all AnimStacks like the cache node algorithm recursively - // this can then be used with ProcessDomConnection<> to link from - // AnimStack:: <-- (OO) --> AnimLayer:: <-- (OO) --> AnimCurveNode:: (which can OP resolve) to Model:: - } - - // - // Cleanup operations - explicit to prevent errors on shutdown - found that ref to ref does behave badly sometimes. - // - - state.renderer_mesh_data.clear(); - state.MeshSkins.clear(); - state.fbx_target_map.clear(); - state.fbx_node_list.clear(); - - for (KeyValue<uint64_t, Ref<FBXBone>> &element : state.fbx_bone_map) { - Ref<FBXBone> bone = element.value; - bone->parent_bone.unref(); - bone->node.unref(); - bone->fbx_skeleton.unref(); - } - - for (KeyValue<uint64_t, Ref<FBXSkeleton>> &element : state.skeleton_map) { - Ref<FBXSkeleton> skel = element.value; - skel->fbx_node.unref(); - skel->skeleton_bones.clear(); - } - - state.fbx_bone_map.clear(); - state.skeleton_map.clear(); - state.fbx_root_node.unref(); - - return scene_root; -} - -void EditorSceneFormatImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone, - ImportState &state, const FBXDocParser::Document *p_doc, - uint64_t p_id) { - const std::vector<const FBXDocParser::Connection *> &conns = p_doc->GetConnectionsByDestinationSequenced(p_id, "Model"); - // FBX can do an join like this - // Model -> SubDeformer (bone) -> Deformer (skin pose) - // This is important because we need to somehow link skin back to bone id in skeleton :) - // The rules are: - // A subdeformer will exist if 'limbnode' class tag present - // The subdeformer will not necessarily have a deformer as joints do not have one - for (const FBXDocParser::Connection *con : conns) { - // goto: bone creation - //print_verbose("con: " + String(con->PropertyName().c_str())); - - // ignore object-property links we want the object to object links nothing else - if (con->PropertyName().length()) { - continue; - } - - // convert connection source object into Object base class - const FBXDocParser::Object *const object = con->SourceObject(); - - if (nullptr == object) { - print_verbose("failed to convert source object for Model link"); - continue; - } - - // FBX Model::Cube, Model::Bone001, etc elements - // This detects if we can cast the object into this model structure. - const FBXDocParser::Model *const model = dynamic_cast<const FBXDocParser::Model *>(object); - - // 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 .instantiated() on the same line. - Ref<FBXBone> bone_element; - - if (model != nullptr) { - // model marked with limb node / casted. - const FBXDocParser::ModelLimbNode *const limb_node = dynamic_cast<const FBXDocParser::ModelLimbNode *>(model); - if (limb_node != nullptr) { - // Write bone into bone list for FBX - - 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.instantiate(); - - // used to build the bone hierarchy in the skeleton - bone_element->parent_bone_id = parent_is_bone ? p_id : 0; - bone_element->valid_parent = parent_is_bone; - bone_element->limb_node = limb_node; - - // parent is a node and this is the first bone - if (!parent_is_bone) { - uint64_t armature_id = p_id; - bone_element->valid_armature_id = true; - bone_element->armature_id = armature_id; - print_verbose("[doc] valid armature has been configured for first child: " + itos(armature_id)); - } else if (p_parent_bone.is_valid()) { - if (p_parent_bone->valid_armature_id) { - bone_element->valid_armature_id = true; - bone_element->armature_id = p_parent_bone->armature_id; - print_verbose("[doc] bone has valid armature id:" + itos(bone_element->armature_id)); - } else { - print_error("[doc] unassigned armature id: " + String(limb_node->Name().c_str())); - } - } else { - print_error("[doc] error is this a bone? " + String(limb_node->Name().c_str())); - } - - if (!parent_is_bone) { - print_verbose("[doc] Root bone: " + bone_element->bone_name); - } - - uint64_t limb_id = limb_node->ID(); - bone_element->bone_id = limb_id; - bone_element->bone_name = ImportUtils::FBXNodeToName(model->Name()); - bone_element->parent_bone = p_parent_bone; - - // insert limb by ID into list. - state.fbx_bone_map.insert(limb_node->ID(), bone_element); - } - - // recursion call - child nodes - BuildDocumentBones(bone_element, state, p_doc, model->ID()); - } - } -} - -void EditorSceneFormatImporterFBX::BuildDocumentNodes( - Ref<PivotTransform> parent_transform, - ImportState &state, - const FBXDocParser::Document *p_doc, - uint64_t id, - Ref<FBXNode> parent_node) { - // tree - // here we get the node 0 on the root by default - const std::vector<const FBXDocParser::Connection *> &conns = p_doc->GetConnectionsByDestinationSequenced(id, "Model"); - - // branch - for (const FBXDocParser::Connection *con : conns) { - // ignore object-property links - if (con->PropertyName().length()) { - // really important we document why this is ignored. - print_verbose("ignoring property link - no docs on why this is ignored"); - continue; - } - - // convert connection source object into Object base class - // Source objects can exist with 'null connections' this means that we only for sure know the source exists. - const FBXDocParser::Object *const source_object = con->SourceObject(); - - if (nullptr == source_object) { - print_verbose("failed to convert source object for Model link"); - continue; - } - - // FBX Model::Cube, Model::Bone001, etc elements - // This detects if we can cast the object into this model structure. - const FBXDocParser::Model *const model = dynamic_cast<const FBXDocParser::Model *>(source_object); - // model is the current node - if (nullptr != model) { - uint64_t current_node_id = model->ID(); - - Ref<FBXNode> new_node; - 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.instantiate(); - fbx_transform->set_parent(parent_transform); - fbx_transform->set_model(model); - fbx_transform->debug_pivot_xform("name: " + new_node->node_name); - fbx_transform->Execute(); - - new_node->set_pivot_transform(fbx_transform); - - // check if this node is a bone - if (state.fbx_bone_map.has(current_node_id)) { - Ref<FBXBone> bone = state.fbx_bone_map[current_node_id]; - if (bone.is_valid()) { - bone->set_node(new_node); - print_verbose("allocated bone data: " + bone->bone_name); - } - } - - // set the model, we can't just assign this safely - new_node->set_model(model); - - if (parent_node.is_valid()) { - new_node->set_parent(parent_node); - } else { - new_node->set_parent(state.fbx_root_node); - } - - CRASH_COND_MSG(new_node->pivot_transform.is_null(), "invalid fbx target map pivot transform [serious]"); - - // populate lookup tables with references - // [fbx_node_id, fbx_node] - - state.fbx_node_list.push_back(new_node); - if (!state.fbx_target_map.has(new_node->current_node_id)) { - state.fbx_target_map[new_node->current_node_id] = new_node; - } - - // print node name - print_verbose("[doc] new node " + new_node->node_name); - - // sub branches - BuildDocumentNodes(new_node->pivot_transform, state, p_doc, current_node_id, new_node); - } - } -} diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h deleted file mode 100644 index 7845e079c2..0000000000 --- a/modules/fbx/editor_scene_importer_fbx.h +++ /dev/null @@ -1,134 +0,0 @@ -/*************************************************************************/ -/* editor_scene_importer_fbx.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 EDITOR_SCENE_IMPORTER_FBX_H -#define EDITOR_SCENE_IMPORTER_FBX_H - -#ifdef TOOLS_ENABLED - -#include "data/import_state.h" -#include "tools/import_utils.h" - -#include "core/io/resource_importer.h" -#include "core/string/ustring.h" -#include "core/templates/local_vector.h" -#include "core/templates/vector.h" -#include "core/variant/dictionary.h" -#include "editor/import/resource_importer_scene.h" -#include "editor/project_settings_editor.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/animation.h" -#include "scene/resources/surface_tool.h" - -#include "fbx_parser/FBXDocument.h" -#include "fbx_parser/FBXImportSettings.h" -#include "fbx_parser/FBXMeshGeometry.h" -#include "fbx_parser/FBXUtil.h" - -#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL - -class EditorSceneFormatImporterFBX : public EditorSceneFormatImporter { -private: - GDCLASS(EditorSceneFormatImporterFBX, EditorSceneFormatImporter); - - struct AssetImportAnimation { - enum Interpolation { - INTERP_LINEAR, - INTERP_STEP, - INTERP_CATMULLROMSPLINE, - INTERP_CUBIC_SPLINE - }; - }; - - // ------------------------------------------------------------------------------------------------ - template <typename T> - const T *ProcessDOMConnection( - const FBXDocParser::Document *doc, - uint64_t current_element, - bool reverse_lookup = false) { - const std::vector<const FBXDocParser::Connection *> &conns = reverse_lookup ? doc->GetConnectionsByDestinationSequenced(current_element) : doc->GetConnectionsBySourceSequenced(current_element); - //print_verbose("[doc] looking for " + String(element_to_find)); - // using the temp pattern here so we can debug before it returns - // in some cases we return too early, with 'deformer object base class' in wrong place - // in assimp this means we can accidentally return too early... - const T *return_obj = nullptr; - - for (const FBXDocParser::Connection *con : conns) { - const FBXDocParser::Object *source_object = con->SourceObject(); - const FBXDocParser::Object *dest_object = con->DestinationObject(); - if (source_object && dest_object != nullptr) { - //print_verbose("[doc] connection name: " + String(source_object->Name().c_str()) + ", dest: " + String(dest_object->Name().c_str())); - const T *temp = dynamic_cast<const T *>(reverse_lookup ? source_object : dest_object); - if (temp) { - return_obj = temp; - } - } - } - - if (return_obj != nullptr) { - //print_verbose("[doc] returned valid element"); - //print_verbose("Found object for bone"); - return return_obj; - } - - // safe to return nothing, need to use nullptr here as nullptr is used internally for FBX document. - return nullptr; - } - - void BuildDocumentBones(Ref<FBXBone> p_parent_bone, - ImportState &state, const FBXDocParser::Document *p_doc, - uint64_t p_id); - - void BuildDocumentNodes(Ref<PivotTransform> parent_transform, ImportState &state, const FBXDocParser::Document *doc, uint64_t id, Ref<FBXNode> fbx_parent); - - Node3D *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document, - const uint32_t p_flags, - int p_bake_fps, - const int32_t p_max_bone_weights, - bool p_is_blender_fbx); - - template <class T> - T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp); - void _register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const; - -public: - EditorSceneFormatImporterFBX() {} - ~EditorSceneFormatImporterFBX() {} - - 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 = nullptr) override; -}; - -#endif // TOOLS_ENABLED -#endif // EDITOR_SCENE_IMPORTER_FBX_H diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h deleted file mode 100644 index 08d38147d5..0000000000 --- a/modules/fbx/fbx_parser/ByteSwapper.h +++ /dev/null @@ -1,283 +0,0 @@ -/*************************************************************************/ -/* ByteSwapper.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2020, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Helper class tp perform various byte order swappings - (e.g. little to big endian) */ -#ifndef BYTE_SWAPPER_H -#define BYTE_SWAPPER_H - -#include <stdint.h> -#include <algorithm> -#include <locale> - -namespace FBXDocParser { -// -------------------------------------------------------------------------------------- -/** Defines some useful byte order swap routines. - * - * This is required to read big-endian model formats on little-endian machines, - * and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */ -// -------------------------------------------------------------------------------------- -class ByteSwap { - ByteSwap() {} - -public: - // ---------------------------------------------------------------------- - /** Swap two bytes of data - * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap2(void *_szOut) { - uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut); - std::swap(szOut[0], szOut[1]); - } - - // ---------------------------------------------------------------------- - /** Swap four bytes of data - * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap4(void *_szOut) { - uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut); - std::swap(szOut[0], szOut[3]); - std::swap(szOut[1], szOut[2]); - } - - // ---------------------------------------------------------------------- - /** Swap eight bytes of data - * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap8(void *_szOut) { - uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut); - std::swap(szOut[0], szOut[7]); - std::swap(szOut[1], szOut[6]); - std::swap(szOut[2], szOut[5]); - std::swap(szOut[3], szOut[4]); - } - - // ---------------------------------------------------------------------- - /** ByteSwap a float. Not a joke. - * @param[inout] fOut ehm. .. */ - static inline void Swap(float *fOut) { - Swap4(fOut); - } - - // ---------------------------------------------------------------------- - /** ByteSwap a double. Not a joke. - * @param[inout] fOut ehm. .. */ - static inline void Swap(double *fOut) { - Swap8(fOut); - } - - // ---------------------------------------------------------------------- - /** ByteSwap an int16t. Not a joke. - * @param[inout] fOut ehm. .. */ - static inline void Swap(int16_t *fOut) { - Swap2(fOut); - } - - static inline void Swap(uint16_t *fOut) { - Swap2(fOut); - } - - // ---------------------------------------------------------------------- - /** ByteSwap an int32t. Not a joke. - * @param[inout] fOut ehm. .. */ - static inline void Swap(int32_t *fOut) { - Swap4(fOut); - } - - static inline void Swap(uint32_t *fOut) { - Swap4(fOut); - } - - // ---------------------------------------------------------------------- - /** ByteSwap an int64t. Not a joke. - * @param[inout] fOut ehm. .. */ - static inline void Swap(int64_t *fOut) { - Swap8(fOut); - } - - static inline void Swap(uint64_t *fOut) { - Swap8(fOut); - } - - // ---------------------------------------------------------------------- - //! Templatized ByteSwap - //! \returns param tOut as swapped - template <typename Type> - static inline Type Swapped(Type tOut) { - return _swapper<Type, sizeof(Type)>()(tOut); - } - -private: - template <typename T, size_t size> - struct _swapper; -}; - -template <typename T> -struct ByteSwap::_swapper<T, 2> { - T operator()(T tOut) { - Swap2(&tOut); - return tOut; - } -}; - -template <typename T> -struct ByteSwap::_swapper<T, 4> { - T operator()(T tOut) { - Swap4(&tOut); - return tOut; - } -}; - -template <typename T> -struct ByteSwap::_swapper<T, 8> { - T operator()(T tOut) { - Swap8(&tOut); - return tOut; - } -}; - -// -------------------------------------------------------------------------------------- -// ByteSwap macros for BigEndian/LittleEndian support -// -------------------------------------------------------------------------------------- -#if (defined AI_BUILD_BIG_ENDIAN) -#define AI_LE(t) (t) -#define AI_BE(t) ByteSwap::Swapped(t) -#define AI_LSWAP2(p) -#define AI_LSWAP4(p) -#define AI_LSWAP8(p) -#define AI_LSWAP2P(p) -#define AI_LSWAP4P(p) -#define AI_LSWAP8P(p) -#define LE_NCONST const -#define AI_SWAP2(p) ByteSwap::Swap2(&(p)) -#define AI_SWAP4(p) ByteSwap::Swap4(&(p)) -#define AI_SWAP8(p) ByteSwap::Swap8(&(p)) -#define AI_SWAP2P(p) ByteSwap::Swap2((p)) -#define AI_SWAP4P(p) ByteSwap::Swap4((p)) -#define AI_SWAP8P(p) ByteSwap::Swap8((p)) -#define BE_NCONST -#else -#define AI_BE(t) (t) -#define AI_LE(t) ByteSwap::Swapped(t) -#define AI_SWAP2(p) -#define AI_SWAP4(p) -#define AI_SWAP8(p) -#define AI_SWAP2P(p) -#define AI_SWAP4P(p) -#define AI_SWAP8P(p) -#define BE_NCONST const -#define AI_LSWAP2(p) ByteSwap::Swap2(&(p)) -#define AI_LSWAP4(p) ByteSwap::Swap4(&(p)) -#define AI_LSWAP8(p) ByteSwap::Swap8(&(p)) -#define AI_LSWAP2P(p) ByteSwap::Swap2((p)) -#define AI_LSWAP4P(p) ByteSwap::Swap4((p)) -#define AI_LSWAP8P(p) ByteSwap::Swap8((p)) -#define LE_NCONST -#endif - -namespace Intern { - -// -------------------------------------------------------------------------------------------- -template <typename T, bool doit> -struct ByteSwapper { - void operator()(T *inout) { - ByteSwap::Swap(inout); - } -}; - -template <typename T> -struct ByteSwapper<T, false> { - void operator()(T *) { - } -}; - -// -------------------------------------------------------------------------------------------- -template <bool SwapEndianess, typename T, bool RuntimeSwitch> -struct Getter { - void operator()(T *inout, bool le) { - le = !le; - if (le) { - ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout); - } else { - ByteSwapper<T, false>()(inout); - } - } -}; - -template <bool SwapEndianess, typename T> -struct Getter<SwapEndianess, T, false> { - void operator()(T *inout, bool /*le*/) { - // static branch - ByteSwapper<T, (SwapEndianess && sizeof(T) > 1)>()(inout); - } -}; -} // namespace Intern -} // namespace FBXDocParser - -#endif // BYTE_SWAPPER_H diff --git a/modules/fbx/fbx_parser/CREDITS b/modules/fbx/fbx_parser/CREDITS deleted file mode 100644 index 62b449614e..0000000000 --- a/modules/fbx/fbx_parser/CREDITS +++ /dev/null @@ -1,183 +0,0 @@ -=============================================================== -Open Asset Import Library (Assimp) -Developers and Contributors -=============================================================== - -The following is a non-exhaustive list of all constributors over the years. -If you think your name should be listed here, drop us a line and we'll add you. - -- Alexander Gessler, -3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design). - -- Thomas Schulze, -X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation. - -- Kim Kulling, -Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ). - -- R.Schmidt, -Linux build, eclipse support. - -- Matthias Gubisch, -Assimp.net -Visual Studio 9 support, bugfixes. - -- Mark Sibly -B3D-Loader, Assimp testing - -- Jonathan Klein -Ogre Loader, VC2010 fixes and CMake fixes. - -- Sebastian Hempel, -PyAssimp (first version) -Compile-Bugfixes for mingw, add environment for static library support in make. - -- Jonathan Pokrass -Supplied a bugfix concerning the scaling in the md3 loader. - -- Andrew Galante, -Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace. - -- Andreas Nagel -First Assimp testing & verification under Windows Vista 64 Bit. - -- Marius Schr�der -Allowed us to use many of his models for screenshots and testing. - -- Christian Schubert -Supplied various XFiles for testing purposes. - -- Tizian Wieland -Searched the web for hundreds of test models for internal use - -- John Connors -Supplied patches for linux and SCons. - -- T. R. -The GUY who performed some of the CSM mocaps. - -- Andy Maloney -Contributed fixes for the documentation and the doxygen markup - -- Zhao Lei -Contributed several bugfixes fixing memory leaks and improving float parsing - -- sueastside -Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date. - -- Tobias Rittig -Collada testing with Cinema 4D - -- Brad Grantham -Improvements in OpenGL-Sample. - -- Robert Ramirez -Add group loading feature to Obj-Loader. - -- Chris Maiwald -Many bugreports, improving Assimp's portability, regular testing & feedback. - -- Stepan Hrbek -Bugreport and fix for a obj-materialloader crash. - -- David Nadlinger -D bindings, CMake install support. - -- Dario Accornero -Contributed several patches regarding Mac OS/XCode targets, bug reports. - -- Martin Walser (Samhayne) -Contributed the 'SimpleTexturedOpenGl' sample. - -- Matthias Fauconneau -Contributed a fix for the Q3-BSP loader. - -- Jørgen P. Tjernø -Contributed updated and improved xcode workspaces - -- drparallax -Contributed the /samples/SimpleAssimpViewX sample - -- Carsten Fuchs -Contributed a fix for the Normalize method in aiQuaternion. - -- dbburgess -Contributes a Android-specific build issue: log the hardware architecture for ARM. - -- alfiereinre7 -Contributes a obj-fileparser fix: missing tokens in the obj-token list. - -- Roman Kharitonov -Contributes a fix for the configure script environment. - -- Ed Diana -Contributed AssimpDelphi (/port/AssimpDelphi). - -- rdb -Contributes a bundle of fixes and improvements for the bsp-importer. - -- Mick P -For contributing the De-bone postprocessing step and filing various bug reports. - -- Rosen Diankov -Contributed patches to build assimp debian packages using cmake. - -- Mark Page -Contributed a patch to fix the VertexTriangleAdjacency postprocessing step. - -- IOhannes -Contributed the Debian build fixes ( architecture macro ). - -- gellule -Several LWO and LWS fixes (pivoting). - -- Marcel Metz -GCC/Linux fixes for the SimpleOpenGL sample. - -- Brian Miller -Bugfix for a compiler fix for iOS on arm. - -- Séverin Lemaignan -Rewrite of PyAssimp, distutils and Python3 support - -- albert-wang -Bugfixes for the collada parser - -- Ya ping Jin -Bugfixes for uv-tanget calculation. - -- Jonne Nauha -Ogre Binary format support - -- Filip Wasil, Tieto Poland Sp. z o.o. -Android JNI asset extraction support - -- Richard Steffen -Contributed ExportProperties interface -Contributed X File exporter -Contributed Step (stp) exporter - -- Thomas Iorns (mesilliac) -Initial FBX Export support - -For a more detailed list just check: https://github.com/assimp/assimp/network/members - - -======== -Patreons -======== - -Huge thanks to our Patreons! - -- migenius -- Marcus -- Cort -- elect -- Steffen - - -=================== -Commercial Sponsors -=================== - -- MyDidimo (mydidimo.com): Sponsored development of FBX Export support diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp deleted file mode 100644 index 0fbff035fd..0000000000 --- a/modules/fbx/fbx_parser/FBXAnimation.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/*************************************************************************/ -/* FBXAnimation.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXAnimation.cpp - * @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode, - * Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack - */ - -#include "FBXCommon.h" -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXParser.h" - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -AnimationCurve::AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document & /*doc*/) : - Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - const ElementPtr KeyTime = GetRequiredElement(sc, "KeyTime"); - const ElementPtr KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat"); - - // note preserved keys and values for legacy FBXConverter.cpp - // we can remove this once the animation system is written - // and clean up this code so we do not have copies everywhere. - ParseVectorDataArray(keys, KeyTime); - ParseVectorDataArray(values, KeyValueFloat); - - if (keys.size() != values.size()) { - DOMError("the number of key times does not match the number of keyframe values", KeyTime); - } - - // put the two lists into the map, underlying container is really just a dictionary - // these will always match, if not an error will throw and the file will not import - // this is useful because we then can report something and fix this later if it becomes an issue - // at this point we do not need a different count of these elements so this makes the - // most sense to do. - for (size_t x = 0; x < keys.size(); x++) { - keyvalues[keys[x]] = values[x]; - } - - const ElementPtr KeyAttrDataFloat = sc->GetElement("KeyAttrDataFloat"); - if (KeyAttrDataFloat) { - ParseVectorDataArray(attributes, KeyAttrDataFloat); - } - - const ElementPtr KeyAttrFlags = sc->GetElement("KeyAttrFlags"); - if (KeyAttrFlags) { - ParseVectorDataArray(flags, KeyAttrFlags); - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurve::~AnimationCurve() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name, - const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/, - size_t whitelist_size /*= 0*/) : - Object(id, element, name), target(), doc(doc) { - // find target node - const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" }; - const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3); - - for (const Connection *con : conns) { - // link should go for a property - if (!con->PropertyName().length()) { - continue; - } - - Object *object = con->DestinationObject(); - - if (!object) { - DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", element); - continue; - } - - target = object; - prop = con->PropertyName(); - break; - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNode::~AnimationCurveNode() { - curves.clear(); -} - -// ------------------------------------------------------------------------------------------------ -const AnimationMap &AnimationCurveNode::Curves() const { - /* Lazy loaded animation curves, will only load if required */ - if (curves.empty()) { - // resolve attached animation curves - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve"); - - for (const Connection *con : conns) { - // So the advantage of having this STL boilerplate is that it's dead simple once you get it. - // The other advantage is casting is guaranteed to be safe and nullptr will be returned in the last step if it fails. - Object *ob = con->SourceObject(); - AnimationCurve *anim_curve = dynamic_cast<AnimationCurve *>(ob); - ERR_CONTINUE_MSG(!anim_curve, "Failed to convert animation curve from object"); - - curves.insert(std::make_pair(con->PropertyName(), anim_curve)); - } - } - - return curves; -} - -// ------------------------------------------------------------------------------------------------ -AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Object(id, element, name), doc(doc) { -} - -// ------------------------------------------------------------------------------------------------ -AnimationLayer::~AnimationLayer() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist, - size_t whitelist_size /*= 0*/) const { - AnimationCurveNodeList nodes; - - // resolve attached animation nodes - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode"); - nodes.reserve(conns.size()); - - for (const Connection *con : conns) { - // link should not go to a property - if (con->PropertyName().length()) { - continue; - } - - Object *ob = con->SourceObject(); - - if (!ob) { - DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", element); - continue; - } - - const AnimationCurveNode *anim = dynamic_cast<AnimationCurveNode *>(ob); - if (!anim) { - DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", element); - continue; - } - - if (target_prop_whitelist) { - const char *s = anim->TargetProperty().c_str(); - bool ok = false; - for (size_t i = 0; i < whitelist_size; ++i) { - if (!strcmp(s, target_prop_whitelist[i])) { - ok = true; - break; - } - } - if (!ok) { - continue; - } - } - nodes.push_back(anim); - } - - return nodes; -} - -// ------------------------------------------------------------------------------------------------ -AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Object(id, element, name) { - // resolve attached animation layers - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer"); - layers.reserve(conns.size()); - - for (const Connection *con : conns) { - // link should not go to a property - if (con->PropertyName().length()) { - continue; - } - - Object *ob = con->SourceObject(); - if (!ob) { - DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", element); - continue; - } - - const AnimationLayer *anim = dynamic_cast<const AnimationLayer *>(ob); - - if (!anim) { - DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", element); - continue; - } - - layers.push_back(anim); - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationStack::~AnimationStack() { -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp deleted file mode 100644 index d6abcbb00a..0000000000 --- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp +++ /dev/null @@ -1,442 +0,0 @@ -/*************************************************************************/ -/* FBXBinaryTokenizer.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -/** @file FBXBinaryTokenizer.cpp - * @brief Implementation of a fake lexer for binary fbx files - - * we emit tokens so the parser needs almost no special handling - * for binary files. - */ - -#include "ByteSwapper.h" -#include "FBXTokenizer.h" -#include "core/string/print_string.h" - -#include <stdint.h> - -namespace FBXDocParser { -// ------------------------------------------------------------------------------------------------ -Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset) : - sbegin(sbegin), - send(send), - type(type), - line(offset), - column(BINARY_MARKER) { -#ifdef DEBUG_ENABLED - // contents is bad.. :/ - contents = std::string(sbegin, static_cast<size_t>(send - sbegin)); -#endif - // calc length - // measure from sBegin to sEnd and validate? -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -// signal tokenization error -void TokenizeError(const std::string &message, size_t offset) { - print_error("[FBX-Tokenize] " + String(message.c_str()) + ", offset " + itos(offset)); -} - -// ------------------------------------------------------------------------------------------------ -size_t Offset(const char *begin, const char *cursor) { - //ai_assert(begin <= cursor); - - return cursor - begin; -} - -// ------------------------------------------------------------------------------------------------ -void TokenizeError(const std::string &message, const char *begin, const char *cursor) { - TokenizeError(message, Offset(begin, cursor)); -} - -// ------------------------------------------------------------------------------------------------ -uint32_t ReadWord(const char *input, const char *&cursor, const char *end) { - const size_t k_to_read = sizeof(uint32_t); - if (Offset(cursor, end) < k_to_read) { - TokenizeError("cannot ReadWord, out of bounds", input, cursor); - } - - uint32_t word; - ::memcpy(&word, cursor, 4); - AI_SWAP4(word); - - cursor += k_to_read; - - return word; -} - -// ------------------------------------------------------------------------------------------------ -uint64_t ReadDoubleWord(const char *input, const char *&cursor, const char *end) { - const size_t k_to_read = sizeof(uint64_t); - if (Offset(cursor, end) < k_to_read) { - TokenizeError("cannot ReadDoubleWord, out of bounds", input, cursor); - } - - uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/; - ::memcpy(&dword, cursor, sizeof(uint64_t)); - AI_SWAP8(dword); - - cursor += k_to_read; - - return dword; -} - -// ------------------------------------------------------------------------------------------------ -uint8_t ReadByte(const char *input, const char *&cursor, const char *end) { - if (Offset(cursor, end) < sizeof(uint8_t)) { - TokenizeError("cannot ReadByte, out of bounds", input, cursor); - } - - uint8_t word; /* = *reinterpret_cast< const uint8_t* >( cursor )*/ - ::memcpy(&word, cursor, sizeof(uint8_t)); - ++cursor; - - return word; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const char *input, - const char *&cursor, const char *end, bool long_length = false, bool allow_null = false) { - const uint32_t len_len = long_length ? 4 : 1; - if (Offset(cursor, end) < len_len) { - TokenizeError("cannot ReadString, out of bounds reading length", input, cursor); - } - - const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end); - - if (Offset(cursor, end) < length) { - TokenizeError("cannot ReadString, length is out of bounds", input, cursor); - } - - sbegin_out = cursor; - cursor += length; - - send_out = cursor; - - if (!allow_null) { - for (unsigned int i = 0; i < length; ++i) { - if (sbegin_out[i] == '\0') { - TokenizeError("failed ReadString, unexpected NUL character in string", input, cursor); - } - } - } - - return length; -} - -// ------------------------------------------------------------------------------------------------ -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; - sbegin_out = cursor++; - - switch (type) { - // 16 bit int - case 'Y': - cursor += 2; - break; - - // 1 bit bool flag (yes/no) - case 'C': - cursor += 1; - break; - - // 32 bit int - case 'I': - // <- fall through - - // float - case 'F': - cursor += 4; - break; - - // double - case 'D': - cursor += 8; - break; - - // 64 bit int - case 'L': - cursor += 8; - break; - - // note: do not write cursor += ReadWord(...cursor) as this would be UB - - // raw binary data - case 'R': { - const uint32_t length = ReadWord(input, cursor, end); - cursor += length; - break; - } - - case 'b': - // TODO: what is the 'b' type code? Right now we just skip over it / - // take the full range we could get - cursor = end; - break; - - // array of * - case 'f': - case 'd': - case 'l': - case 'i': - case 'c': { - const uint32_t length = ReadWord(input, cursor, end); - const uint32_t encoding = ReadWord(input, cursor, end); - - const uint32_t comp_len = ReadWord(input, cursor, end); - - // compute length based on type and check against the stored value - if (encoding == 0) { - uint32_t stride = 0; - switch (type) { - case 'f': - case 'i': - stride = 4; - break; - - case 'd': - case 'l': - stride = 8; - break; - - case 'c': - stride = 1; - break; - - default: - break; - }; - //ai_assert(stride > 0); - if (length * stride != comp_len) { - TokenizeError("cannot ReadData, calculated data stride differs from what the file claims", input, cursor); - } - } - // zip/deflate algorithm (encoding==1)? take given length. anything else? die - else if (encoding != 1) { - TokenizeError("cannot ReadData, unknown encoding", input, cursor); - } - cursor += comp_len; - break; - } // string - case 'S': { - const char *sb, *se; - // 0 characters can legally happen in such strings - ReadString(sb, se, input, cursor, end, true, true); - 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 - send_out = cursor; -} - -// ------------------------------------------------------------------------------------------------ -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); - - // we may get 0 if reading reached the end of the file - - // fbx files have a mysterious extra footer which I don't know - // how to extract any information from, but at least it always - // starts with a 0. - if (!end_offset) { - return false; - } - - 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 - const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); - - // the third data word contains the length of the property list - 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 = nullptr, *send = nullptr; - ReadString(sbeg, send, input, cursor, end); - - output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, 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, corrupt); - if (corrupt) { - return false; - } - - output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor))); - - if (i != prop_count - 1) { - output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, 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 - // that the sub-scope exists (i.e. to distinguish between P: and P : {}) - // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit. - const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t) * 3 + 1) : (sizeof(uint32_t) * 3 + 1); - - if (Offset(input, cursor) < end_offset) { - if (end_offset - Offset(input, cursor) < sentinel_block_length) { - TokenizeError("insufficient padding bytes at block end", input, cursor); - } - - output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, 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, 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; - } - - if (Offset(input, cursor) != end_offset) { - TokenizeError("scope length not reached, something is wrong", input, cursor); - corrupt = true; - return false; - } - - return true; -} -} // anonymous namespace - -// ------------------------------------------------------------------------------------------------ -// 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, bool &corrupt) { - if (length < 0x1b) { - //TokenizeError("file is too short",0); - } - - if (strncmp(input, "Kaydara FBX Binary", 18)) { - TokenizeError("magic bytes not found", 0); - } - - const char *cursor = input + 18; - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - const uint32_t version = ReadWord(input, cursor, input + length); - print_verbose("FBX Version: " + itos(version)); - //ASSIMP_LOG_DEBUG_F("FBX version: ", version); - const bool is64bits = version >= 7500; - const char *end = input + length; - while (cursor < end) { - if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) { - break; - } - } -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXCommon.h b/modules/fbx/fbx_parser/FBXCommon.h deleted file mode 100644 index 611bf22d3b..0000000000 --- a/modules/fbx/fbx_parser/FBXCommon.h +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************/ -/* FBXCommon.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXCommon.h - * Some useful constants and enums for dealing with FBX files. - */ -#ifndef FBX_COMMON_H -#define FBX_COMMON_H - -#include <string> - -namespace FBXDocParser { -const std::string NULL_RECORD = { // 13 null bytes - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' -}; // who knows why -const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings -const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import -const int64_t SECOND = 46186158000; // FBX's kTime unit - -// rotation order. We'll probably use EulerXYZ for everything -enum RotOrder { - RotOrder_EulerXYZ = 0, - RotOrder_EulerXZY, - RotOrder_EulerYZX, - RotOrder_EulerYXZ, - RotOrder_EulerZXY, - RotOrder_EulerZYX, - - RotOrder_SphericXYZ, - - RotOrder_MAX // end-of-enum sentinel -}; - -enum TransformInheritance { - Transform_RrSs = 0, - Transform_RSrs = 1, - Transform_Rrs = 2, - TransformInheritance_MAX // end-of-enum sentinel -}; -} // namespace FBXDocParser - -#endif // FBX_COMMON_H diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp deleted file mode 100644 index 4220ba62a7..0000000000 --- a/modules/fbx/fbx_parser/FBXDeformer.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/*************************************************************************/ -/* FBXDeformer.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXNoteAttribute.cpp - * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation - */ - -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXMeshGeometry.h" -#include "FBXParser.h" -#include "core/math/math_funcs.h" -#include "core/math/transform_3d.h" - -#include <iostream> - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name) { -} - -// ------------------------------------------------------------------------------------------------ -Deformer::~Deformer() { -} - -Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name) { -} - -Constraint::~Constraint() { -} - -// ------------------------------------------------------------------------------------------------ -Cluster::Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Deformer(id, element, doc, name), valid_transformAssociateModel(false) { - const ScopePtr sc = GetRequiredScope(element); - // for( auto element : sc.Elements()) - // { - // std::cout << "cluster element: " << element.first << std::endl; - // } - // - // element: Indexes - // element: Transform - // element: TransformAssociateModel - // element: TransformLink - // element: UserData - // element: Version - // element: Weights - - const ElementPtr Indexes = sc->GetElement("Indexes"); - const ElementPtr Weights = sc->GetElement("Weights"); - - const ElementPtr TransformAssociateModel = sc->GetElement("TransformAssociateModel"); - if (TransformAssociateModel != nullptr) { - //Transform t = ReadMatrix(*TransformAssociateModel); - link_mode = SkinLinkMode_Additive; - valid_transformAssociateModel = true; - } else { - link_mode = SkinLinkMode_Normalized; - valid_transformAssociateModel = false; - } - - const ElementPtr Transform = GetRequiredElement(sc, "Transform", element); - const ElementPtr TransformLink = GetRequiredElement(sc, "TransformLink", element); - - // todo: check if we need this - //const Element& TransformAssociateModel = GetRequiredElement(sc, "TransformAssociateModel", &element); - - transform = ReadMatrix(Transform); - transformLink = ReadMatrix(TransformLink); - - // it is actually possible that there be Deformer's with no weights - if (!!Indexes != !!Weights) { - DOMError("either Indexes or Weights are missing from Cluster", element); - } - - if (Indexes) { - ParseVectorDataArray(indices, Indexes); - ParseVectorDataArray(weights, Weights); - } - - if (indices.size() != weights.size()) { - DOMError("sizes of index and weight array don't match up", element); - } - - // read assigned node - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Model"); - for (const Connection *con : conns) { - const Model *mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element); - if (mod) { - node = mod; - break; - } - } - - if (!node) { - DOMError("failed to read target Node for Cluster", element); - node = nullptr; - } -} - -// ------------------------------------------------------------------------------------------------ -Cluster::~Cluster() { -} - -// ------------------------------------------------------------------------------------------------ -Skin::Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Deformer(id, element, doc, name), accuracy(0.0f) { - const ScopePtr sc = GetRequiredScope(element); - - // keep this it is used for debugging and any FBX format changes - // for (auto element : sc.Elements()) { - // std::cout << "skin element: " << element.first << std::endl; - // } - - const ElementPtr Link_DeformAcuracy = sc->GetElement("Link_DeformAcuracy"); - if (Link_DeformAcuracy) { - accuracy = ParseTokenAsFloat(GetRequiredToken(Link_DeformAcuracy, 0)); - } - - const ElementPtr SkinType = sc->GetElement("SkinningType"); - - if (SkinType) { - std::string skin_type = ParseTokenAsString(GetRequiredToken(SkinType, 0)); - - if (skin_type == "Linear") { - skinType = Skin_Linear; - } else if (skin_type == "Rigid") { - skinType = Skin_Rigid; - } else if (skin_type == "DualQuaternion") { - skinType = Skin_DualQuaternion; - } else if (skin_type == "Blend") { - skinType = Skin_Blend; - } else { - print_error("[doc:skin] could not find valid skin type: " + String(skin_type.c_str())); - } - } - - // resolve assigned clusters - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); - - // - - clusters.reserve(conns.size()); - for (const Connection *con : conns) { - const Cluster *cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element); - if (cluster) { - clusters.push_back(cluster); - continue; - } - } -} - -// ------------------------------------------------------------------------------------------------ -Skin::~Skin() { -} -// ------------------------------------------------------------------------------------------------ -BlendShape::BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Deformer(id, element, doc, name) { - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); - blendShapeChannels.reserve(conns.size()); - for (const Connection *con : conns) { - const BlendShapeChannel *bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element); - if (bspc) { - blendShapeChannels.push_back(bspc); - continue; - } - } -} -// ------------------------------------------------------------------------------------------------ -BlendShape::~BlendShape() { -} -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Deformer(id, element, doc, name) { - const ScopePtr sc = GetRequiredScope(element); - const ElementPtr DeformPercent = sc->GetElement("DeformPercent"); - if (DeformPercent) { - percent = ParseTokenAsFloat(GetRequiredToken(DeformPercent, 0)); - } - const ElementPtr FullWeights = sc->GetElement("FullWeights"); - if (FullWeights) { - ParseVectorDataArray(fullWeights, FullWeights); - } - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry"); - shapeGeometries.reserve(conns.size()); - for (const Connection *con : conns) { - const ShapeGeometry *const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element); - if (sg) { - shapeGeometries.push_back(sg); - continue; - } - } -} -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::~BlendShapeChannel() { -} -// ------------------------------------------------------------------------------------------------ -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp deleted file mode 100644 index 92c62e68b5..0000000000 --- a/modules/fbx/fbx_parser/FBXDocument.cpp +++ /dev/null @@ -1,636 +0,0 @@ -/*************************************************************************/ -/* FBXDocument.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the* - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocument.cpp - * @brief Implementation of the FBX DOM classes - */ - -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXImportSettings.h" -#include "FBXMeshGeometry.h" -#include "FBXParser.h" -#include "FBXProperties.h" -#include "FBXUtil.h" - -#include <algorithm> -#include <functional> -#include <iostream> -#include <map> -#include <memory> - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) : - doc(doc), element(element), id(id) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -LazyObject::~LazyObject() { - object.reset(); -} - -ObjectPtr LazyObject::LoadObject() { - if (IsBeingConstructed() || FailedToConstruct()) { - return nullptr; - } - - if (object) { - return object.get(); - } - - TokenPtr key = element->KeyToken(); - ERR_FAIL_COND_V(!key, nullptr); - const TokenList &tokens = element->Tokens(); - - if (tokens.size() < 3) { - //DOMError("expected at least 3 tokens: id, name and class tag",&element); - return nullptr; - } - - const char *err = nullptr; - std::string name = ParseTokenAsString(tokens[1], err); - if (err) { - DOMError(err, element); - } - - // small fix for binary reading: binary fbx files don't use - // prefixes such as Model:: in front of their names. The - // loading code expects this at many places, though! - // so convert the binary representation (a 0x0001) to the - // double colon notation. - if (tokens[1]->IsBinary()) { - for (size_t i = 0; i < name.length(); ++i) { - if (name[i] == 0x0 && name[i + 1] == 0x1) { - name = name.substr(i + 2) + "::" + name.substr(0, i); - } - } - } - - const std::string classtag = ParseTokenAsString(tokens[2], err); - if (err) { - DOMError(err, element); - } - - // prevent recursive calls - flags |= BEING_CONSTRUCTED; - - // this needs to be relatively fast since it happens a lot, - // so avoid constructing strings all the time. - const char *obtype = key->begin(); - const size_t length = static_cast<size_t>(key->end() - key->begin()); - - if (!strncmp(obtype, "Pose", length)) { - object.reset(new FbxPose(id, element, doc, name)); - } else if (!strncmp(obtype, "Geometry", length)) { - if (!strcmp(classtag.c_str(), "Mesh")) { - object.reset(new MeshGeometry(id, element, name, doc)); - } - if (!strcmp(classtag.c_str(), "Shape")) { - object.reset(new ShapeGeometry(id, element, name, doc)); - } - if (!strcmp(classtag.c_str(), "Line")) { - object.reset(new LineGeometry(id, element, name, doc)); - } - } else if (!strncmp(obtype, "NodeAttribute", length)) { - if (!strcmp(classtag.c_str(), "Camera")) { - object.reset(new Camera(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "CameraSwitcher")) { - object.reset(new CameraSwitcher(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "Light")) { - object.reset(new Light(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "Null")) { - object.reset(new Null(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "LimbNode")) { - // This is an older format for bones - // this is what blender uses I believe - object.reset(new LimbNode(id, element, doc, name)); - } - } else if (!strncmp(obtype, "Constraint", length)) { - object.reset(new Constraint(id, element, doc, name)); - } else if (!strncmp(obtype, "Deformer", length)) { - if (!strcmp(classtag.c_str(), "Cluster")) { - object.reset(new Cluster(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "Skin")) { - object.reset(new Skin(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "BlendShape")) { - object.reset(new BlendShape(id, element, doc, name)); - } else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) { - object.reset(new BlendShapeChannel(id, element, doc, name)); - } - } else if (!strncmp(obtype, "Model", length)) { - // Model is normal node - - // LimbNode model is a 'bone' node. - if (!strcmp(classtag.c_str(), "LimbNode")) { - object.reset(new ModelLimbNode(id, element, doc, name)); - - } else if (strcmp(classtag.c_str(), "IKEffector") && strcmp(classtag.c_str(), "FKEffector")) { - // FK and IK effectors are not supported. - object.reset(new Model(id, element, doc, name)); - } - } else if (!strncmp(obtype, "Material", length)) { - object.reset(new Material(id, element, doc, name)); - } else if (!strncmp(obtype, "Texture", length)) { - object.reset(new Texture(id, element, doc, name)); - } else if (!strncmp(obtype, "LayeredTexture", length)) { - object.reset(new LayeredTexture(id, element, doc, name)); - } else if (!strncmp(obtype, "Video", length)) { - object.reset(new Video(id, element, doc, name)); - } else if (!strncmp(obtype, "AnimationStack", length)) { - object.reset(new AnimationStack(id, element, name, doc)); - } else if (!strncmp(obtype, "AnimationLayer", length)) { - object.reset(new AnimationLayer(id, element, name, doc)); - } else if (!strncmp(obtype, "AnimationCurve", length)) { - object.reset(new AnimationCurve(id, element, name, doc)); - } else if (!strncmp(obtype, "AnimationCurveNode", length)) { - object.reset(new AnimationCurveNode(id, element, name, doc)); - } else { - ERR_FAIL_V_MSG(nullptr, "FBX contains unsupported object: " + String(obtype)); - } - - flags &= ~BEING_CONSTRUCTED; - - return object.get(); -} - -// ------------------------------------------------------------------------------------------------ -Object::Object(uint64_t id, const ElementPtr element, const std::string &name) : - PropertyTable(element), element(element), name(name), id(id) { -} - -// ------------------------------------------------------------------------------------------------ -Object::~Object() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -FileGlobalSettings::FileGlobalSettings(const Document &doc) : - PropertyTable(), doc(doc) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -FileGlobalSettings::~FileGlobalSettings() { -} - -// ------------------------------------------------------------------------------------------------ -Document::Document(const Parser &parser, const ImportSettings &settings) : - settings(settings), parser(parser) { - // Cannot use array default initialization syntax because vc8 fails on it - for (unsigned int &timeStamp : creationTimeStamp) { - timeStamp = 0; - } - - // we must check if we can read the header version safely, if its outdated then drop it. - if (ReadHeader()) { - SafeToImport = true; - ReadPropertyTemplates(); - - ReadGlobalSettings(); - - // This order is important, connections need parsed objects to check - // whether connections are ok or not. Objects may not be evaluated yet, - // though, since this may require valid connections. - ReadObjects(); - ReadConnections(); - } -} - -// ------------------------------------------------------------------------------------------------ -Document::~Document() { - for (PropertyTemplateMap::value_type v : templates) { - delete v.second; - } - - for (ObjectMap::value_type &v : objects) { - delete v.second; - } - - for (ConnectionMap::value_type &v : src_connections) { - delete v.second; - } - - // clear globals import pointer - globals.reset(); -} - -// ------------------------------------------------------------------------------------------------ -static const unsigned int LowerSupportedVersion = 7100; -static const unsigned int UpperSupportedVersion = 7700; - -bool Document::ReadHeader() { - // Read ID objects from "Objects" section - ScopePtr sc = parser.GetRootScope(); - ElementPtr ehead = sc->GetElement("FBXHeaderExtension"); - if (!ehead || !ehead->Compound()) { - 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)); - - // While we may have some success with newer files, we don't support - // the older 6.n fbx format - if (fbxVersion < LowerSupportedVersion) { - DOMWarning("unsupported, old format version, FBX 2015-2020, you must re-export in a more modern version of your original modelling application"); - return false; - } - if (fbxVersion > UpperSupportedVersion) { - DOMWarning("unsupported, newer format version, supported are only FBX 2015, up to FBX 2020" - " trying to read it nevertheless"); - } - - const ElementPtr ecreator = shead->GetElement("Creator"); - if (ecreator) { - creator = ParseTokenAsString(GetRequiredToken(ecreator, 0)); - } - - // Scene Info - const ElementPtr scene_info = shead->GetElement("SceneInfo"); - - if (scene_info) { - metadata_properties.Setup(scene_info); - } - - const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp"); - if (etimestamp && etimestamp->Compound()) { - const ScopePtr stimestamp = etimestamp->Compound(); - creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Year"), 0)); - creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Month"), 0)); - creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Day"), 0)); - creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Hour"), 0)); - creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Minute"), 0)); - creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Second"), 0)); - creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Millisecond"), 0)); - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadGlobalSettings() { - ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported"); - - globals = std::make_shared<FileGlobalSettings>(*this); -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadObjects() { - // read ID objects from "Objects" section - const ScopePtr sc = parser.GetRootScope(); - const ElementPtr eobjects = sc->GetElement("Objects"); - if (!eobjects || !eobjects->Compound()) { - DOMError("no Objects dictionary found"); - } - - // add a dummy entry to represent the Model::RootNode object (id 0), - // which is only indirectly defined in the input file - objects[0] = new LazyObject(0L, eobjects, *this); - - const ScopePtr sobjects = eobjects->Compound(); - for (const ElementMap::value_type &iter : sobjects->Elements()) { - // extract ID - const TokenList &tok = iter.second->Tokens(); - - if (tok.empty()) { - DOMError("expected ID after object key", iter.second); - } - - const char *err; - const uint64_t id = ParseTokenAsID(tok[0], err); - if (err) { - DOMError(err, iter.second); - } - - // id=0 is normally implicit - if (id == 0L) { - DOMError("encountered object with implicitly defined id 0", iter.second); - } - - if (objects.find(id) != objects.end()) { - DOMWarning("encountered duplicate object id, ignoring first occurrence", iter.second); - } - - objects[id] = new LazyObject(id, iter.second, *this); - - // grab all animation stacks upfront since there is no listing of them - if (!strcmp(iter.first.c_str(), "AnimationStack")) { - animationStacks.push_back(id); - } else if (!strcmp(iter.first.c_str(), "Constraint")) { - constraints.push_back(id); - } else if (!strcmp(iter.first.c_str(), "Pose")) { - bind_poses.push_back(id); - } else if (!strcmp(iter.first.c_str(), "Material")) { - materials.push_back(id); - } else if (!strcmp(iter.first.c_str(), "Deformer")) { - TokenPtr key = iter.second->KeyToken(); - ERR_CONTINUE_MSG(!key, "[parser bug] invalid token key for deformer"); - const TokenList &tokens = iter.second->Tokens(); - const std::string class_tag = ParseTokenAsString(tokens[2], err); - - if (err) { - DOMError(err, iter.second); - } - - if (class_tag == "Skin") { - //print_verbose("registered skin:" + itos(id)); - skins.push_back(id); - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadPropertyTemplates() { -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadConnections() { - const ScopePtr sc = parser.GetRootScope(); - - // read property templates from "Definitions" section - const ElementPtr econns = sc->GetElement("Connections"); - if (!econns || !econns->Compound()) { - DOMError("no Connections dictionary found"); - } - - uint64_t insertionOrder = 0l; - const ScopePtr sconns = econns->Compound(); - const ElementCollection conns = sconns->GetCollection("C"); - for (ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { - const ElementPtr el = (*it).second; - const std::string &type = ParseTokenAsString(GetRequiredToken(el, 0)); - - // PP = property-property connection, ignored for now - // (tokens: "PP", ID1, "Property1", ID2, "Property2") - if (type == "PP") { - continue; - } - - const uint64_t src = ParseTokenAsID(GetRequiredToken(el, 1)); - const uint64_t dest = ParseTokenAsID(GetRequiredToken(el, 2)); - - // OO = object-object connection - // OP = object-property connection, in which case the destination property follows the object ID - const std::string &prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el, 3)) : ""); - - if (objects.find(src) == objects.end()) { - DOMWarning("source object for connection does not exist", el); - continue; - } - - // dest may be 0 (root node) but we added a dummy object before - if (objects.find(dest) == objects.end()) { - DOMWarning("destination object for connection does not exist", el); - continue; - } - - // add new connection - const Connection *const c = new Connection(insertionOrder++, src, dest, prop, *this); - src_connections.insert(ConnectionMap::value_type(src, c)); - dest_connections.insert(ConnectionMap::value_type(dest, c)); - } -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<const AnimationStack *> &Document::AnimationStacks() const { - if (!animationStacksResolved.empty() || animationStacks.empty()) { - return animationStacksResolved; - } - - animationStacksResolved.reserve(animationStacks.size()); - for (uint64_t id : animationStacks) { - LazyObject *lazy = GetObject(id); - - // Two things happen here: - // We cast internally an Object PTR to an Animation Stack PTR - // We return invalid weak_ptrs for objects which are invalid - - 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 won't be cleaned up. - animationStacksResolved.push_back(stack); - } - - return animationStacksResolved; -} - -// ------------------------------------------------------------------------------------------------ -LazyObject *Document::GetObject(uint64_t id) const { - ObjectMap::const_iterator it = objects.find(id); - return it == objects.end() ? nullptr : (*it).second; -} - -#define MAX_CLASSNAMES 6 - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap &conns) const { - std::vector<const Connection *> temp; - - const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range = - conns.equal_range(id); - - temp.reserve(std::distance(range.first, range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - temp.push_back((*it).second); - } - - std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare)); - - return temp; // NRVO should handle this -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap &conns, - const char *const *classnames, - size_t count) const - -{ - size_t lengths[MAX_CLASSNAMES]; - - const size_t c = count; - for (size_t i = 0; i < c; ++i) { - lengths[i] = strlen(classnames[i]); - } - - std::vector<const Connection *> temp; - const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range = - conns.equal_range(id); - - temp.reserve(std::distance(range.first, range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - TokenPtr key = (is_src ? (*it).second->LazyDestinationObject() : (*it).second->LazySourceObject())->GetElement()->KeyToken(); - - const char *obtype = key->begin(); - - for (size_t i = 0; i < c; ++i) { - //ai_assert(classnames[i]); - if (static_cast<size_t>(std::distance(key->begin(), key->end())) == lengths[i] && !strncmp(classnames[i], obtype, lengths[i])) { - obtype = nullptr; - break; - } - } - - if (obtype) { - continue; - } - - temp.push_back((*it).second); - } - - std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare)); - return temp; // NRVO should handle this -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source) const { - return GetConnectionsSequenced(source, ConnectionsBySource()); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t src, const char *classname) const { - const char *arr[] = { classname }; - return GetConnectionsBySourceSequenced(src, arr, 1); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source, - const char *const *classnames, size_t count) const { - return GetConnectionsSequenced(source, true, ConnectionsBySource(), classnames, count); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char *classname) const { - const char *arr[] = { classname }; - return GetConnectionsByDestinationSequenced(dest, arr, 1); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const { - return GetConnectionsSequenced(dest, ConnectionsByDestination()); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char *const *classnames, size_t count) const { - return GetConnectionsSequenced(dest, false, ConnectionsByDestination(), classnames, count); -} - -// ------------------------------------------------------------------------------------------------ -Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop, - const Document &doc) : - insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) { -} - -// ------------------------------------------------------------------------------------------------ -Connection::~Connection() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -LazyObject *Connection::LazySourceObject() const { - LazyObject *const lazy = doc.GetObject(src); - return lazy; -} - -// ------------------------------------------------------------------------------------------------ -LazyObject *Connection::LazyDestinationObject() const { - LazyObject *const lazy = doc.GetObject(dest); - return lazy; -} - -// ------------------------------------------------------------------------------------------------ -Object *Connection::SourceObject() const { - LazyObject *lazy = doc.GetObject(src); - //ai_assert(lazy); - return lazy->LoadObject(); -} - -// ------------------------------------------------------------------------------------------------ -Object *Connection::DestinationObject() const { - LazyObject *lazy = doc.GetObject(dest); - //ai_assert(lazy); - return lazy->LoadObject(); -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h deleted file mode 100644 index 539d633331..0000000000 --- a/modules/fbx/fbx_parser/FBXDocument.h +++ /dev/null @@ -1,1252 +0,0 @@ -/*************************************************************************/ -/* FBXDocument.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. */ -/*************************************************************************/ - -/** @file FBXDocument.h - * @brief FBX DOM - */ -#ifndef FBX_DOCUMENT_H -#define FBX_DOCUMENT_H - -#include "FBXCommon.h" -#include "FBXParser.h" -#include "FBXProperties.h" -#include "core/math/transform_3d.h" -#include "core/math/vector2.h" -#include "core/math/vector3.h" -#include "core/string/print_string.h" -#include <stdint.h> -#include <numeric> - -#define _AI_CONCAT(a, b) a##b -#define AI_CONCAT(a, b) _AI_CONCAT(a, b) - -namespace FBXDocParser { - -class Parser; -class Object; -struct ImportSettings; -class Connection; - -class PropertyTable; -class Document; -class Material; -class ShapeGeometry; -class LineGeometry; -class Geometry; - -class Video; - -class AnimationCurve; -class AnimationCurveNode; -class AnimationLayer; -class AnimationStack; - -class BlendShapeChannel; -class BlendShape; -class Skin; -class Cluster; - -typedef Object *ObjectPtr; -#define new_Object new Object - -/** Represents a delay-parsed FBX objects. Many objects in the scene - * are not needed by assimp, so it makes no sense to parse them - * upfront. */ -class LazyObject { -public: - LazyObject(uint64_t id, const ElementPtr element, const Document &doc); - ~LazyObject(); - - ObjectPtr LoadObject(); - - /* Casting weak pointers to their templated type safely and preserving ref counting and safety - * with lock() keyword to prevent leaking memory - */ - template <typename T> - const T *Get() { - ObjectPtr ob = LoadObject(); - return dynamic_cast<const T *>(ob); - } - - uint64_t ID() const { - return id; - } - - bool IsBeingConstructed() const { - return (flags & BEING_CONSTRUCTED) != 0; - } - - bool FailedToConstruct() const { - return (flags & FAILED_TO_CONSTRUCT) != 0; - } - - ElementPtr GetElement() const { - return element; - } - - const Document &GetDocument() const { - return doc; - } - -private: - const Document &doc; - ElementPtr element = nullptr; - std::shared_ptr<Object> object = nullptr; - const uint64_t id = 0; - - enum Flags { - BEING_CONSTRUCTED = 0x1, - FAILED_TO_CONSTRUCT = 0x2 - }; - - unsigned int flags = 0; -}; - -/** Base class for in-memory (DOM) representations of FBX objects */ -class Object : public PropertyTable { -public: - Object(uint64_t id, const ElementPtr element, const std::string &name); - - virtual ~Object(); - - ElementPtr SourceElement() const { - return element; - } - - const std::string &Name() const { - return name; - } - - uint64_t ID() const { - return id; - } - -protected: - const ElementPtr element = nullptr; - const std::string name; - const uint64_t id; -}; - -/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, - * fixed members are added by deriving classes. */ -class NodeAttribute : public Object { -public: - NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~NodeAttribute(); -}; - -/** 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 { - return cameraId; - } - - const std::string &CameraName() const { - return cameraName; - } - - const std::string &CameraIndexName() const { - return cameraIndexName; - } - -private: - 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>(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>(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; -class FbxPose : public Object { -public: - FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - const std::vector<FbxPoseNode *> &GetBindPoses() const { - return pose_nodes; - } - - virtual ~FbxPose(); - -private: - std::vector<FbxPoseNode *> pose_nodes; -}; - -class FbxPoseNode { -public: - FbxPoseNode(const ElementPtr element, const Document &doc, const std::string &name) { - const ScopePtr sc = GetRequiredScope(element); - - // get pose node transform - const ElementPtr Transform = GetRequiredElement(sc, "Matrix", element); - transform = ReadMatrix(Transform); - - // get node id this pose node is for - const ElementPtr NodeId = sc->GetElement("Node3D"); - if (NodeId) { - target_id = ParseTokenAsInt64(GetRequiredToken(NodeId, 0)); - } - - print_verbose("added posenode " + itos(target_id) + " transform: " + transform); - } - virtual ~FbxPoseNode() { - } - - uint64_t GetNodeID() const { - return target_id; - } - - Transform3D GetBindPose() const { - return transform; - } - -private: - 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)); - fbx_simple_property(UpVector, Vector3, Vector3(0, 1, 0)); - fbx_simple_property(InterestPosition, Vector3, Vector3(0, 0, 0)); - - fbx_simple_property(AspectWidth, float, 1.0f); - fbx_simple_property(AspectHeight, float, 1.0f); - fbx_simple_property(FilmWidth, float, 1.0f); - fbx_simple_property(FilmHeight, float, 1.0f); - - fbx_simple_property(NearPlane, float, 0.1f); - fbx_simple_property(FarPlane, float, 100.0f); - - fbx_simple_property(FilmAspectRatio, float, 1.0f); - fbx_simple_property(ApertureMode, int, 0); - - fbx_simple_property(FieldOfView, float, 1.0f); - fbx_simple_property(FocalLength, float, 1.0f); -}; - -/** DOM base class for FBX null markers attached to a node */ -class Null : public NodeAttribute { -public: - Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Null(); -}; - -/** DOM base class for FBX limb node markers attached to a node */ -class LimbNode : public NodeAttribute { -public: - LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~LimbNode(); -}; - -/** DOM base class for FBX lights attached to a node */ -class Light : public NodeAttribute { -public: - Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Light(); - - enum Type { - Type_Point, - Type_Directional, - Type_Spot, - Type_Area, - Type_Volume, - - Type_MAX // end-of-enum sentinel - }; - - enum Decay { - Decay_None, - Decay_Linear, - Decay_Quadratic, - Decay_Cubic, - - Decay_MAX // end-of-enum sentinel - }; - - fbx_simple_property(Color, Vector3, Vector3(1, 1, 1)); - fbx_simple_enum_property(LightType, Type, 0); - fbx_simple_property(CastLightOnObject, bool, false); - fbx_simple_property(DrawVolumetricLight, bool, true); - fbx_simple_property(DrawGroundProjection, bool, true); - fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false); - fbx_simple_property(Intensity, float, 100.0f); - fbx_simple_property(InnerAngle, float, 0.0f); - fbx_simple_property(OuterAngle, float, 45.0f); - fbx_simple_property(Fog, int, 50); - fbx_simple_enum_property(DecayType, Decay, 2); - fbx_simple_property(DecayStart, float, 1.0f); - fbx_simple_property(FileName, std::string, ""); - - fbx_simple_property(EnableNearAttenuation, bool, false); - fbx_simple_property(NearAttenuationStart, float, 0.0f); - fbx_simple_property(NearAttenuationEnd, float, 0.0f); - fbx_simple_property(EnableFarAttenuation, bool, false); - fbx_simple_property(FarAttenuationStart, float, 0.0f); - fbx_simple_property(FarAttenuationEnd, float, 0.0f); - - fbx_simple_property(CastShadows, bool, true); - fbx_simple_property(ShadowColor, Vector3, Vector3(0, 0, 0)); - - fbx_simple_property(AreaLightShape, int, 0); - - fbx_simple_property(LeftBarnDoor, float, 20.0f); - fbx_simple_property(RightBarnDoor, float, 20.0f); - fbx_simple_property(TopBarnDoor, float, 20.0f); - fbx_simple_property(BottomBarnDoor, float, 20.0f); - fbx_simple_property(EnableBarnDoor, bool, true); -}; - -class Model; - -typedef Model *ModelPtr; -#define new_Model new Model - -/** DOM base class for FBX models (even though its semantics are more "node" than "model" */ -class Model : public Object { -public: - enum RotOrder { - RotOrder_EulerXYZ = 0, - RotOrder_EulerXZY, - RotOrder_EulerYZX, - RotOrder_EulerYXZ, - RotOrder_EulerZXY, - RotOrder_EulerZYX, - - RotOrder_SphericXYZ, - - RotOrder_MAX // end-of-enum sentinel - }; - - Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Model(); - - fbx_simple_property(QuaternionInterpolate, int, 0); - - fbx_simple_property(RotationOffset, Vector3, Vector3()); - fbx_simple_property(RotationPivot, Vector3, Vector3()); - fbx_simple_property(ScalingOffset, Vector3, Vector3()); - fbx_simple_property(ScalingPivot, Vector3, Vector3()); - fbx_simple_property(TranslationActive, bool, false); - fbx_simple_property(TranslationMin, Vector3, Vector3()); - fbx_simple_property(TranslationMax, Vector3, Vector3()); - - fbx_simple_property(TranslationMinX, bool, false); - fbx_simple_property(TranslationMaxX, bool, false); - fbx_simple_property(TranslationMinY, bool, false); - fbx_simple_property(TranslationMaxY, bool, false); - fbx_simple_property(TranslationMinZ, bool, false); - fbx_simple_property(TranslationMaxZ, bool, false); - - fbx_simple_enum_property(RotationOrder, RotOrder, 0); - fbx_simple_property(RotationSpaceForLimitOnly, bool, false); - fbx_simple_property(RotationStiffnessX, float, 0.0f); - fbx_simple_property(RotationStiffnessY, float, 0.0f); - fbx_simple_property(RotationStiffnessZ, float, 0.0f); - fbx_simple_property(AxisLen, float, 0.0f); - - fbx_simple_property(PreRotation, Vector3, Vector3()); - fbx_simple_property(PostRotation, Vector3, Vector3()); - fbx_simple_property(RotationActive, bool, false); - - fbx_simple_property(RotationMin, Vector3, Vector3()); - fbx_simple_property(RotationMax, Vector3, Vector3()); - - fbx_simple_property(RotationMinX, bool, false); - fbx_simple_property(RotationMaxX, bool, false); - fbx_simple_property(RotationMinY, bool, false); - fbx_simple_property(RotationMaxY, bool, false); - fbx_simple_property(RotationMinZ, bool, false); - fbx_simple_property(RotationMaxZ, bool, false); - fbx_simple_enum_property(InheritType, TransformInheritance, 0); - - fbx_simple_property(ScalingActive, bool, false); - fbx_simple_property(ScalingMin, Vector3, Vector3()); - fbx_simple_property(ScalingMax, Vector3, Vector3(1, 1, 1)); - fbx_simple_property(ScalingMinX, bool, false); - fbx_simple_property(ScalingMaxX, bool, false); - fbx_simple_property(ScalingMinY, bool, false); - fbx_simple_property(ScalingMaxY, bool, false); - fbx_simple_property(ScalingMinZ, bool, false); - fbx_simple_property(ScalingMaxZ, bool, false); - - fbx_simple_property(GeometricTranslation, Vector3, Vector3()); - fbx_simple_property(GeometricRotation, Vector3, Vector3()); - fbx_simple_property(GeometricScaling, Vector3, Vector3(1, 1, 1)); - - fbx_simple_property(MinDampRangeX, float, 0.0f); - fbx_simple_property(MinDampRangeY, float, 0.0f); - fbx_simple_property(MinDampRangeZ, float, 0.0f); - fbx_simple_property(MaxDampRangeX, float, 0.0f); - fbx_simple_property(MaxDampRangeY, float, 0.0f); - fbx_simple_property(MaxDampRangeZ, float, 0.0f); - - fbx_simple_property(MinDampStrengthX, float, 0.0f); - fbx_simple_property(MinDampStrengthY, float, 0.0f); - fbx_simple_property(MinDampStrengthZ, float, 0.0f); - fbx_simple_property(MaxDampStrengthX, float, 0.0f); - fbx_simple_property(MaxDampStrengthY, float, 0.0f); - fbx_simple_property(MaxDampStrengthZ, float, 0.0f); - - fbx_simple_property(PreferredAngleX, float, 0.0f); - fbx_simple_property(PreferredAngleY, float, 0.0f); - fbx_simple_property(PreferredAngleZ, float, 0.0f); - - fbx_simple_property(Show, bool, true); - fbx_simple_property(LODBox, bool, false); - fbx_simple_property(Freeze, bool, false); - - const std::string &Shading() const { - return shading; - } - - const std::string &Culling() const { - return culling; - } - - /** Get material links */ - const std::vector<const Material *> &GetMaterials() const { - return materials; - } - - /** Get geometry links */ - const std::vector<const Geometry *> &GetGeometry() const { - return geometry; - } - - /** Get node attachments */ - const std::vector<const NodeAttribute *> &GetAttributes() const { - return attributes; - } - - /** convenience method to check if the node has a Null node marker */ - bool IsNull() const; - -private: - void ResolveLinks(const ElementPtr element, const Document &doc); - -private: - std::vector<const Material *> materials; - std::vector<const Geometry *> geometry; - std::vector<const NodeAttribute *> attributes; - - std::string shading; - std::string culling; -}; - -class ModelLimbNode : public Model { -public: - ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~ModelLimbNode(); -}; - -/** DOM class for generic FBX textures */ -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 { - return type; - } - - const std::string &FileName() const { - return fileName; - } - - const std::string &RelativeFilename() const { - return relativeFileName; - } - - const std::string &AlphaSource() const { - return alphaSource; - } - - const Vector2 &UVTranslation() const { - return uvTrans; - } - - const Vector2 &UVScaling() const { - return uvScaling; - } - - // return a 4-tuple - const unsigned int *Crop() const { - return crop; - } - - const Video *Media() const { - return media; - } - -private: - Vector2 uvTrans; - Vector2 uvScaling; - - std::string type; - std::string relativeFileName; - std::string fileName; - std::string alphaSource; - - unsigned int crop[4] = { 0 }; - const Video *media = nullptr; -}; - -/** DOM class for layered FBX textures */ -class LayeredTexture : public Object { -public: - LayeredTexture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~LayeredTexture(); - - // Can only be called after construction of the layered texture object due to construction flag. - void fillTexture(const Document &doc); - - enum BlendMode { - BlendMode_Translucent, - BlendMode_Additive, - BlendMode_Modulate, - BlendMode_Modulate2, - BlendMode_Over, - BlendMode_Normal, - BlendMode_Dissolve, - BlendMode_Darken, - BlendMode_ColorBurn, - BlendMode_LinearBurn, - BlendMode_DarkerColor, - BlendMode_Lighten, - BlendMode_Screen, - BlendMode_ColorDodge, - BlendMode_LinearDodge, - BlendMode_LighterColor, - BlendMode_SoftLight, - BlendMode_HardLight, - BlendMode_VividLight, - BlendMode_LinearLight, - BlendMode_PinLight, - BlendMode_HardMix, - BlendMode_Difference, - BlendMode_Exclusion, - BlendMode_Subtract, - BlendMode_Divide, - BlendMode_Hue, - BlendMode_Saturation, - BlendMode_Color, - BlendMode_Luminosity, - BlendMode_Overlay, - BlendMode_BlendModeCount - }; - - const Texture *getTexture(int index = 0) const { - return textures[index]; - } - int textureCount() const { - return static_cast<int>(textures.size()); - } - BlendMode GetBlendMode() const { - return blendMode; - } - float Alpha() { - return alpha; - } - -private: - std::vector<const Texture *> textures; - BlendMode blendMode = BlendMode::BlendMode_Additive; - float alpha = 0; -}; - -typedef std::map<std::string, const Texture *> TextureMap; -typedef std::map<std::string, const LayeredTexture *> LayeredTextureMap; - -/** DOM class for generic FBX videos */ -class Video : public Object { -public: - Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - virtual ~Video(); - - const std::string &Type() const { - return type; - } - - bool IsEmbedded() const { - return contentLength > 0; - } - - const std::string &FileName() const { - return fileName; - } - - const std::string &RelativeFilename() const { - return relativeFileName; - } - - const uint8_t *Content() const { - return content; - } - - uint64_t ContentLength() const { - return contentLength; - } - - uint8_t *RelinquishContent() { - uint8_t *ptr = content; - content = nullptr; - return ptr; - } - - bool operator==(const Video &other) const { - return ( - type == other.type && relativeFileName == other.relativeFileName && fileName == other.fileName); - } - - bool operator<(const Video &other) const { - return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName); - } - -private: - std::string type; - std::string relativeFileName; - std::string fileName; - - uint64_t contentLength = 0; - uint8_t *content = nullptr; -}; - -/** DOM class for generic FBX materials */ -class Material : public Object { -public: - Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - virtual ~Material(); - - const std::string &GetShadingModel() const { - return shading; - } - - bool IsMultilayer() const { - return multilayer; - } - - const TextureMap &Textures() const { - return textures; - } - - const LayeredTextureMap &LayeredTextures() const { - return layeredTextures; - } - -private: - std::string shading; - bool multilayer = false; - - TextureMap textures; - LayeredTextureMap layeredTextures; -}; - -// signed int keys (this can happen!) -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 therefore) */ -class AnimationCurve : public Object { -public: - AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); - virtual ~AnimationCurve(); - - /** get list of keyframe positions (time). - * Invariant: |GetKeys()| > 0 */ - const KeyTimeList &GetKeys() const { - return keys; - } - - /** get list of keyframe values. - * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/ - const KeyValueList &GetValues() const { - return values; - } - - const std::map<int64_t, float> &GetValueTimeTrack() const { - return keyvalues; - } - - const std::vector<float> &GetAttributes() const { - return attributes; - } - - const std::vector<unsigned int> &GetFlags() const { - return flags; - } - -private: - KeyTimeList keys; - KeyValueList values; - std::vector<float> attributes; - std::map<int64_t, float> keyvalues; - std::vector<unsigned int> flags; -}; - -/* Typedef for pointers for the animation handler */ -typedef std::shared_ptr<AnimationCurve> AnimationCurvePtr; -typedef std::weak_ptr<AnimationCurve> AnimationCurveWeakPtr; -typedef std::map<std::string, const AnimationCurve *> AnimationMap; - -/* Animation Curve node ptr */ -typedef std::shared_ptr<AnimationCurveNode> AnimationCurveNodePtr; -typedef std::weak_ptr<AnimationCurveNode> AnimationCurveNodeWeakPtr; - -/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ -class AnimationCurveNode : public Object { -public: - /* the optional white list specifies a list of property names for which the caller - wants animations for. If the curve node does not match one of these, std::range_error - will be thrown. */ - AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc, - const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0); - - virtual ~AnimationCurveNode(); - - const AnimationMap &Curves() const; - - /** 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 { - return target; - } - - Model *TargetAsModel() const { - return dynamic_cast<Model *>(target); - } - - NodeAttribute *TargetAsNodeAttribute() const { - return dynamic_cast<NodeAttribute *>(target); - } - - /** Property of Target() that is being animated*/ - const std::string &TargetProperty() const { - return prop; - } - -private: - Object *target = nullptr; - mutable AnimationMap curves; - std::string prop; - const Document &doc; -}; - -typedef std::vector<const AnimationCurveNode *> AnimationCurveNodeList; - -typedef std::shared_ptr<AnimationLayer> AnimationLayerPtr; -typedef std::weak_ptr<AnimationLayer> AnimationLayerWeakPtr; -typedef std::vector<const AnimationLayer *> AnimationLayerList; - -/** Represents a FBX animation layer (i.e. a list of node animations) */ -class AnimationLayer : public Object { -public: - AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); - virtual ~AnimationLayer(); - - /* 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 Document &doc; -}; - -/** Represents a FBX animation stack (i.e. a list of animation layers) */ -class AnimationStack : public Object { -public: - AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); - virtual ~AnimationStack(); - - fbx_simple_property(LocalStart, int64_t, 0L); - fbx_simple_property(LocalStop, int64_t, 0L); - fbx_simple_property(ReferenceStart, int64_t, 0L); - fbx_simple_property(ReferenceStop, int64_t, 0L); - - const AnimationLayerList &Layers() const { - return layers; - } - -private: - AnimationLayerList layers; -}; - -/** DOM class for deformers */ -class Deformer : public Object { -public: - Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Deformer(); -}; - -/** Constraints are from Maya they can help us with BoneAttachments :) **/ -class Constraint : public Object { -public: - Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Constraint(); -}; - -typedef std::vector<float> WeightArray; -typedef std::vector<unsigned int> WeightIndexArray; - -/** DOM class for BlendShapeChannel deformers */ -class BlendShapeChannel : public Deformer { -public: - BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - virtual ~BlendShapeChannel(); - - float DeformPercent() const { - return percent; - } - - const WeightArray &GetFullWeights() const { - return fullWeights; - } - - const std::vector<const ShapeGeometry *> &GetShapeGeometries() const { - return shapeGeometries; - } - -private: - float percent = 0; - WeightArray fullWeights; - std::vector<const ShapeGeometry *> shapeGeometries; -}; - -/** DOM class for BlendShape deformers */ -class BlendShape : public Deformer { -public: - BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - virtual ~BlendShape(); - - const std::vector<const BlendShapeChannel *> &BlendShapeChannels() const { - return blendShapeChannels; - } - -private: - std::vector<const BlendShapeChannel *> blendShapeChannels; -}; - -/** DOM class for skin deformer clusters (aka sub-deformers) */ -class Cluster : public Deformer { -public: - Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - virtual ~Cluster(); - - /** get the list of deformer weights associated with this cluster. - * Use #GetIndices() to get the associated vertices. Both arrays - * have the same size (and may also be empty). */ - const std::vector<float> &GetWeights() const { - return weights; - } - - /** get indices into the vertex data of the geometry associated - * with this cluster. Use #GetWeights() to get the associated weights. - * Both arrays have the same size (and may also be empty). */ - const std::vector<unsigned int> &GetIndices() const { - return indices; - } - - /** */ - const Transform3D &GetTransform() const { - return transform; - } - - const Transform3D &TransformLink() const { - return transformLink; - } - - const Model *TargetNode() const { - return node; - } - - const Transform3D &TransformAssociateModel() const { - return transformAssociateModel; - } - - bool TransformAssociateModelValid() const { - return valid_transformAssociateModel; - } - - // property is not in the fbx file - // if the cluster has an associate model - // we then have an additive type - enum SkinLinkMode { - SkinLinkMode_Normalized = 0, - SkinLinkMode_Additive = 1 - }; - - SkinLinkMode GetLinkMode() { - return link_mode; - } - -private: - std::vector<float> weights; - std::vector<unsigned int> indices; - - Transform3D transform; - Transform3D transformLink; - Transform3D transformAssociateModel; - SkinLinkMode link_mode; - bool valid_transformAssociateModel = false; - const Model *node = nullptr; -}; - -/** DOM class for skin deformers */ -class Skin : public Deformer { -public: - Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - - virtual ~Skin(); - - float DeformAccuracy() const { - return accuracy; - } - - const std::vector<const Cluster *> &Clusters() const { - return clusters; - } - - enum SkinType { - Skin_Rigid = 0, - Skin_Linear, - Skin_DualQuaternion, - Skin_Blend - }; - - const SkinType &GetSkinType() const { - return skinType; - } - -private: - float accuracy = 0; - SkinType skinType = SkinType::Skin_Linear; - std::vector<const Cluster *> clusters; -}; - -/** Represents a link between two FBX objects. */ -class Connection { -public: - Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop, const Document &doc); - ~Connection(); - - // 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 nullptr. - Object *SourceObject() const; - Object *DestinationObject() const; - - // these, however, are always guaranteed to be valid - LazyObject *LazySourceObject() const; - LazyObject *LazyDestinationObject() const; - - /** return the name of the property the connection is attached to. - * this is an empty string for object to object (OO) connections. */ - const std::string &PropertyName() const { - return prop; - } - - uint64_t InsertionOrder() const { - return insertionOrder; - } - - int CompareTo(const Connection *c) const { - //ai_assert(nullptr != c); - - // note: can't subtract because this would overflow uint64_t - if (InsertionOrder() > c->InsertionOrder()) { - return 1; - } else if (InsertionOrder() < c->InsertionOrder()) { - return -1; - } - return 0; - } - - bool Compare(const Connection *c) const { - //ai_assert(nullptr != c); - - return InsertionOrder() < c->InsertionOrder(); - } - -public: - uint64_t insertionOrder = 0; - const std::string prop; - - uint64_t src = 0, dest = 0; - const Document &doc; -}; - -// XXX again, unique_ptr would be useful. shared_ptr is too -// bloated since the objects have a well-defined single owner -// during their entire lifetime (Document). FBX files have -// up to many thousands of objects (most of which we never use), -// so the memory overhead for them should be kept at a minimum. -typedef std::map<uint64_t, LazyObject *> ObjectMap; -typedef std::map<std::string, const PropertyTable *> PropertyTemplateMap; -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 : public PropertyTable { -public: - FileGlobalSettings(const Document &doc); - virtual ~FileGlobalSettings(); - - const Document &GetDocument() const { - return doc; - } - - fbx_simple_property(UpAxis, int, 1); - fbx_simple_property(UpAxisSign, int, 1); - fbx_simple_property(FrontAxis, int, 2); - fbx_simple_property(FrontAxisSign, int, 1); - fbx_simple_property(CoordAxis, int, 0); - fbx_simple_property(CoordAxisSign, int, 1); - fbx_simple_property(OriginalUpAxis, int, 0); - fbx_simple_property(OriginalUpAxisSign, int, 1); - fbx_simple_property(UnitScaleFactor, float, 1); - fbx_simple_property(OriginalUnitScaleFactor, float, 1); - fbx_simple_property(AmbientColor, Vector3, Vector3(0, 0, 0)); - fbx_simple_property(DefaultCamera, std::string, ""); - - enum FrameRate { - FrameRate_DEFAULT = 0, - FrameRate_120 = 1, - FrameRate_100 = 2, - FrameRate_60 = 3, - FrameRate_50 = 4, - FrameRate_48 = 5, - FrameRate_30 = 6, - FrameRate_30_DROP = 7, - FrameRate_NTSC_DROP_FRAME = 8, - FrameRate_NTSC_FULL_FRAME = 9, - FrameRate_PAL = 10, - FrameRate_CINEMA = 11, - FrameRate_1000 = 12, - FrameRate_CINEMA_ND = 13, - FrameRate_CUSTOM = 14, - - FrameRate_MAX // end-of-enum sentinel - }; - - fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT); - fbx_simple_property(TimeSpanStart, uint64_t, 0L); - fbx_simple_property(TimeSpanStop, uint64_t, 0L); - fbx_simple_property(CustomFrameRate, float, -1.0f); - -private: - const Document &doc; -}; - -/** DOM root for a FBX file */ -class Document { -public: - Document(const Parser &parser, const ImportSettings &settings); - - ~Document(); - - LazyObject *GetObject(uint64_t id) const; - - bool IsSafeToImport() const { - return SafeToImport; - } - - bool IsBinary() const { - return parser.IsBinary(); - } - - unsigned int FBXVersion() const { - return fbxVersion; - } - - const std::string &Creator() const { - return creator; - } - - // elements (in this order): Year, Month, Day, Hour, Second, Millisecond - const unsigned int *CreationTimeStamp() const { - return creationTimeStamp; - } - - const FileGlobalSettings *GlobalSettingsPtr() const { - return globals.get(); - } - - const PropertyTable &GetMetadataProperties() const { - return metadata_properties; - } - - const PropertyTemplateMap &Templates() const { - return templates; - } - - const ObjectMap &Objects() const { - return objects; - } - - const ImportSettings &Settings() const { - return settings; - } - - const ConnectionMap &ConnectionsBySource() const { - return src_connections; - } - - const ConnectionMap &ConnectionsByDestination() const { - return dest_connections; - } - - // note: the implicit rule in all DOM classes is to always resolve - // from destination to source (since the FBX object hierarchy is, - // with very few exceptions, a DAG, this avoids cycles). In all - // cases that may involve back-facing edges in the object graph, - // use LazyObject::IsBeingConstructed() to check. - - std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source) const; - std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest) const; - - std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source, const char *classname) const; - std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest, const char *classname) const; - - std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source, - const char *const *classnames, size_t count) const; - std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest, - const char *const *classnames, - size_t count) const; - - const std::vector<const AnimationStack *> &AnimationStacks() const; - const std::vector<uint64_t> &GetAnimationStackIDs() const { - return animationStacks; - } - - const std::vector<uint64_t> &GetConstraintStackIDs() const { - return constraints; - } - - const std::vector<uint64_t> &GetBindPoseIDs() const { - return bind_poses; - }; - - const std::vector<uint64_t> &GetMaterialIDs() const { - return materials; - }; - - const std::vector<uint64_t> &GetSkinIDs() const { - return skins; - } - -private: - std::vector<const Connection *> GetConnectionsSequenced(uint64_t id, const ConnectionMap &) const; - std::vector<const Connection *> GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap &, - const char *const *classnames, - size_t count) const; - bool ReadHeader(); - void ReadObjects(); - void ReadPropertyTemplates(); - void ReadConnections(); - void ReadGlobalSettings(); - -private: - const ImportSettings &settings; - - ObjectMap objects; - const Parser &parser; - bool SafeToImport = false; - - PropertyTemplateMap templates; - ConnectionMap src_connections; - ConnectionMap dest_connections; - - unsigned int fbxVersion = 0; - std::string creator; - unsigned int creationTimeStamp[7] = { 0 }; - - std::vector<uint64_t> animationStacks; - std::vector<uint64_t> bind_poses; - // constraints aren't in the tree / at least they are not easy to access. - std::vector<uint64_t> constraints; - std::vector<uint64_t> materials; - std::vector<uint64_t> skins; - mutable std::vector<const AnimationStack *> animationStacksResolved; - PropertyTable metadata_properties; - std::shared_ptr<FileGlobalSettings> globals = nullptr; -}; -} // namespace FBXDocParser - -namespace std { -template <> -struct hash<const FBXDocParser::Video> { - std::size_t operator()(const FBXDocParser::Video &video) const { - using std::hash; - using std::size_t; - using std::string; - - size_t res = 17; - res = res * 31 + hash<string>()(video.Name()); - res = res * 31 + hash<string>()(video.RelativeFilename()); - res = res * 31 + hash<string>()(video.Type()); - - return res; - } -}; -} // namespace std - -#endif // FBX_DOCUMENT_H diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp deleted file mode 100644 index 4a33024969..0000000000 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/*************************************************************************/ -/* FBXDocumentUtil.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocumentUtil.cpp - * @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h - */ - -#include "FBXDocumentUtil.h" -#include "FBXDocument.h" -#include "FBXParser.h" -#include "FBXProperties.h" -#include "FBXUtil.h" -#include "core/string/print_string.h" - -namespace FBXDocParser { -namespace Util { - -void DOMError(const std::string &message) { - print_error("[FBX-DOM]" + String(message.c_str())); -} - -void DOMError(const std::string &message, const Token *token) { - print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); -} - -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 /*= 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 /*= nullptr*/) { - if (element) { - DOMError(message, element->KeyToken()); - } - print_error("[FBX-DOM] " + String(message.c_str())); -} - -void DOMWarning(const std::string &message) { - print_verbose("[FBX-DOM] warning:" + String(message.c_str())); -} - -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 /*= nullptr*/) { - if (element) { - DOMWarning(message, element->KeyToken()); - return; - } - print_verbose("[FBX-DOM] warning:" + String(message.c_str())); -} - -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 /*= nullptr*/) { - if (element) { - DOMWarning(message, element->KeyToken()); - return; - } - print_verbose("[FBX-DOM] warning:" + String(message.c_str())); -} - -} // namespace Util -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h deleted file mode 100644 index 0489ce10ce..0000000000 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.h +++ /dev/null @@ -1,134 +0,0 @@ -/*************************************************************************/ -/* FBXDocumentUtil.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2012, assimp team -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocumentUtil.h - * @brief FBX internal utilities used by the DOM reading code - */ -#ifndef FBX_DOCUMENT_UTIL_H -#define FBX_DOCUMENT_UTIL_H - -#include "FBXDocument.h" -#include <memory> -#include <string> - -struct Token; -struct Element; - -namespace FBXDocParser { -namespace Util { - -// Parser errors -void DOMError(const std::string &message); -void DOMError(const std::string &message, const Token *token); -void DOMError(const std::string &message, const Element *element); -void DOMError(const std::string &message, const std::shared_ptr<Element> element); -void DOMError(const std::string &message, const std::shared_ptr<Token> token); - -// Parser warnings -void DOMWarning(const std::string &message); -void DOMWarning(const std::string &message, const Token *token); -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); - -// ------------------------------------------------------------------------------------------------ -template <typename T> -const T *ProcessSimpleConnection(const Connection &con, - bool is_object_property_conn, - const char *name, - const ElementPtr element, - const char **propNameOut = nullptr) { - if (is_object_property_conn && !con.PropertyName().length()) { - DOMWarning("expected incoming " + std::string(name) + - " link to be an object-object connection, ignoring", - element); - return nullptr; - } else if (!is_object_property_conn && con.PropertyName().length()) { - DOMWarning("expected incoming " + std::string(name) + - " link to be an object-property connection, ignoring", - element); - return nullptr; - } - - if (is_object_property_conn && propNameOut) { - // note: this is ok, the return value of PropertyValue() is guaranteed to - // remain valid and unchanged as long as the document exists. - *propNameOut = con.PropertyName().c_str(); - } - - // Cast Object to AnimationPlayer for example using safe functions, which return nullptr etc - Object *ob = con.SourceObject(); - ERR_FAIL_COND_V_MSG(!ob, nullptr, "Failed to load object from SourceObject ptr"); - return dynamic_cast<const T *>(ob); -} -} // namespace Util -} // namespace FBXDocParser - -#endif // FBX_DOCUMENT_UTIL_H diff --git a/modules/fbx/fbx_parser/FBXImportSettings.h b/modules/fbx/fbx_parser/FBXImportSettings.h deleted file mode 100644 index bc22386957..0000000000 --- a/modules/fbx/fbx_parser/FBXImportSettings.h +++ /dev/null @@ -1,162 +0,0 @@ -/*************************************************************************/ -/* FBXImportSettings.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXImportSettings.h - * @brief FBX importer runtime configuration - */ -#ifndef FBX_IMPORT_SETTINGS_H -#define FBX_IMPORT_SETTINGS_H - -namespace FBXDocParser { - -/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */ -struct ImportSettings { - /** 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.*/ - 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.*/ - 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 = true; - - /** import materials (true) or skip them and assign a default - * material.*/ - bool readMaterials = true; - - /** import embedded textures?*/ - bool readTextures = true; - - /** import cameras?*/ - bool readCameras = true; - - /** import light sources?*/ - bool readLights = true; - - /** import animations (i.e. animation curves, the node - * skeleton is always imported).*/ - bool readAnimations = true; - - /** 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 naming scheme for the generated nodes is: - * <OriginalName>_$AssimpFbx$_<TransformName> - * - * where <TransformName> is one of - * RotationPivot - * RotationOffset - * PreRotation - * PostRotation - * ScalingPivot - * ScalingOffset - * Translation - * Scaling - * Rotation - **/ - bool preservePivots = true; - - /** do not import animation curves that specify a constant - * values matching the corresponding node transformation.*/ - bool optimizeEmptyAnimationCurves = true; - - /** use legacy naming for embedded textures eg: (*0, *1, *2).*/ - bool useLegacyEmbeddedTextureNaming = false; - - /** Empty bones shall be removed.*/ - bool removeEmptyBones = true; - - /** Set to true to perform a conversion from cm to meter after - * the import.*/ - bool convertToMeters = false; -}; -} // namespace FBXDocParser - -#endif // FBX_IMPORT_SETTINGS_H diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp deleted file mode 100644 index bf8922267e..0000000000 --- a/modules/fbx/fbx_parser/FBXMaterial.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/*************************************************************************/ -/* FBXMaterial.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2020, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXMaterial.cpp - * @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation - */ - -#include "ByteSwapper.h" -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXImportSettings.h" -#include "FBXParser.h" -#include "FBXProperties.h" - -#include "FBXUtil.h" -#include <algorithm> // std::transform - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Material::Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - - const ElementPtr ShadingModel = sc->GetElement("ShadingModel"); - const ElementPtr MultiLayer = sc->GetElement("MultiLayer"); - - if (MultiLayer) { - multilayer = !!ParseTokenAsInt(GetRequiredToken(MultiLayer, 0)); - } - - if (ShadingModel) { - shading = ParseTokenAsString(GetRequiredToken(ShadingModel, 0)); - } else { - DOMWarning("shading mode not specified, assuming phong", element); - shading = "phong"; - } - - std::string templateName; - - if (shading == "phong") { - templateName = "Material.Phong"; - } else if (shading == "lambert") { - templateName = "Material.Lambert"; - } else if (shading == "unknown") { - templateName = "Material.StingRay"; - } else { - DOMWarning("shading mode not recognized: " + shading, element); - } - - // resolve texture links - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID()); - for (const Connection *con : conns) { - // texture link to properties, not objects - if (!con->PropertyName().length()) { - continue; - } - - Object *ob = con->SourceObject(); - if (!ob) { - DOMWarning("failed to read source object for texture link, ignoring", element); - continue; - } - - const Texture *tex = dynamic_cast<const Texture *>(ob); - if (!tex) { - LayeredTexture *layeredTexture = dynamic_cast<LayeredTexture *>(ob); - - if (!layeredTexture) { - DOMWarning("source object for texture link is not a texture or layered texture, ignoring", element); - continue; - } - - const std::string &prop = con->PropertyName(); - if (layeredTextures.find(prop) != layeredTextures.end()) { - DOMWarning("duplicate layered texture link: " + prop, element); - } - - layeredTextures[prop] = layeredTexture; - layeredTexture->fillTexture(doc); - } else { - const std::string &prop = con->PropertyName(); - if (textures.find(prop) != textures.end()) { - DOMWarning("duplicate texture link: " + prop, element); - } - - textures[prop] = tex; - } - } -} - -// ------------------------------------------------------------------------------------------------ -Material::~Material() { -} - -// ------------------------------------------------------------------------------------------------ -Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), uvScaling(1.0f, 1.0f) { - const ScopePtr sc = GetRequiredScope(element); - - const ElementPtr Type = sc->GetElement("Type"); - const ElementPtr FileName = sc->GetElement("FileName"); - const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename"); - const ElementPtr ModelUVTranslation = sc->GetElement("ModelUVTranslation"); - const ElementPtr ModelUVScaling = sc->GetElement("ModelUVScaling"); - const ElementPtr Texture_Alpha_Source = sc->GetElement("Texture_Alpha_Source"); - const ElementPtr Cropping = sc->GetElement("Cropping"); - - if (Type) { - type = ParseTokenAsString(GetRequiredToken(Type, 0)); - } - - if (FileName) { - fileName = ParseTokenAsString(GetRequiredToken(FileName, 0)); - } - - if (RelativeFilename) { - relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0)); - } - - if (ModelUVTranslation) { - uvTrans = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 0)), - ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 1))); - } - - if (ModelUVScaling) { - uvScaling = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 0)), - ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 1))); - } - - if (Cropping) { - crop[0] = ParseTokenAsInt(GetRequiredToken(Cropping, 0)); - crop[1] = ParseTokenAsInt(GetRequiredToken(Cropping, 1)); - crop[2] = ParseTokenAsInt(GetRequiredToken(Cropping, 2)); - crop[3] = ParseTokenAsInt(GetRequiredToken(Cropping, 3)); - } else { - // vc8 doesn't support the crop() syntax in initialization lists - // (and vc9 WARNS about the new (i.e. compliant) behaviour). - crop[0] = crop[1] = crop[2] = crop[3] = 0; - } - - if (Texture_Alpha_Source) { - alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0)); - } - - // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available. - 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>(this, "Translation", ok); - if (ok) { - uvTrans.x = trans.x; - uvTrans.y = trans.y; - } - - // resolve video links - if (doc.Settings().readTextures) { - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID()); - for (const Connection *con : conns) { - const Object *const ob = con->SourceObject(); - if (!ob) { - DOMWarning("failed to read source object for texture link, ignoring", element); - continue; - } - - const Video *const video = dynamic_cast<const Video *>(ob); - if (video) { - media = video; - } - } - } -} - -Texture::~Texture() { -} - -LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) : - Object(id, element, name), blendMode(BlendMode_Modulate), alpha(1) { - const ScopePtr sc = GetRequiredScope(element); - - ElementPtr BlendModes = sc->GetElement("BlendModes"); - ElementPtr Alphas = sc->GetElement("Alphas"); - - if (BlendModes != nullptr) { - blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0)); - } - if (Alphas != nullptr) { - alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0)); - } -} - -LayeredTexture::~LayeredTexture() { -} - -void LayeredTexture::fillTexture(const Document &doc) { - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID()); - for (size_t i = 0; i < conns.size(); ++i) { - const Connection *con = conns.at(i); - - const Object *const ob = con->SourceObject(); - if (!ob) { - DOMWarning("failed to read source object for texture link, ignoring", element); - continue; - } - - const Texture *const tex = dynamic_cast<const Texture *>(ob); - - textures.push_back(tex); - } -} - -// ------------------------------------------------------------------------------------------------ -Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - - const ElementPtr Type = sc->GetElement("Type"); - // File Version 7500 Crashes if this is not checked fully. - // As of writing this comment 7700 exists, in August 2020 - ElementPtr FileName = nullptr; - if (HasElement(sc, "Filename")) { - FileName = (ElementPtr)sc->GetElement("Filename"); - } else if (HasElement(sc, "FileName")) { - FileName = (ElementPtr)sc->GetElement("FileName"); - } else { - print_error("file has invalid video material returning..."); - return; - } - const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename"); - const ElementPtr Content = sc->GetElement("Content"); - - if (Type) { - type = ParseTokenAsString(GetRequiredToken(Type, 0)); - } - - if (FileName) { - fileName = ParseTokenAsString(GetRequiredToken(FileName, 0)); - } - - if (RelativeFilename) { - relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0)); - } - - if (Content && !Content->Tokens().empty()) { - //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found - try { - const Token *token = GetRequiredToken(Content, 0); - const char *data = token->begin(); - if (!token->IsBinary()) { - if (*data != '"') { - DOMError("embedded content is not surrounded by quotation marks", element); - } else { - size_t targetLength = 0; - 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); - size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes - const char *base64data = dataToken->begin() + 1; - const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength); - if (outLength == 0) { - DOMError("Corrupted embedded content found", element); - } - targetLength += outLength; - } - if (targetLength == 0) { - DOMError("Corrupted embedded content found", element); - } else { - content = new uint8_t[targetLength]; - contentLength = static_cast<uint64_t>(targetLength); - size_t dst_offset = 0; - for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) { - const Token *dataToken = GetRequiredToken(Content, tokenIdx); - ERR_FAIL_COND(!dataToken); - size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes - const char *base64data = dataToken->begin() + 1; - dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset); - } - if (targetLength != dst_offset) { - delete[] content; - contentLength = 0; - DOMError("Corrupted embedded content found", element); - } - } - } - } else if (static_cast<size_t>(token->end() - data) < 5) { - DOMError("binary data array is too short, need five (5) bytes for type signature and element count", element); - } else if (*data != 'R') { - DOMWarning("video content is not raw binary data, ignoring", element); - } else { - // read number of elements - uint32_t len = 0; - ::memcpy(&len, data + 1, sizeof(len)); - AI_SWAP4(len); - - contentLength = len; - - content = new uint8_t[len]; - ::memcpy(content, data + 5, len); - } - } catch (...) { - // //we don't need the content data for contents that has already been loaded - // ASSIMP_LOG_VERBOSE_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ", - // runtimeError.what()); - } - } -} - -Video::~Video() { - if (content) { - delete[] content; - } -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp deleted file mode 100644 index 2bb634ea56..0000000000 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/*************************************************************************/ -/* FBXMeshGeometry.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXMeshGeometry.cpp - * @brief Assimp::FBX::MeshGeometry implementation - */ - -#include <functional> - -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXImportSettings.h" -#include "FBXMeshGeometry.h" -#include "core/math/vector3.h" - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - 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); - if (sk) { - skin = sk; - } - const BlendShape *bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", - element); - if (bsp) { - blendShapes.push_back(bsp); - } - } -} - -// ------------------------------------------------------------------------------------------------ -Geometry::~Geometry() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<const BlendShape *> &Geometry::get_blend_shapes() const { - return blendShapes; -} - -// ------------------------------------------------------------------------------------------------ -const Skin *Geometry::DeformerSkin() const { - return skin; -} - -// ------------------------------------------------------------------------------------------------ -MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Geometry(id, element, name, doc) { - print_verbose("mesh name: " + String(name.c_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 vertices, didn't populate the mesh"); - - // must have Mesh elements: - const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element); - const ElementPtr PolygonVertexIndex = GetRequiredElement(sc, "PolygonVertexIndex", element); - - if (HasElement(sc, "Edges")) { - const ElementPtr element_edges = GetRequiredElement(sc, "Edges", element); - ParseVectorDataArray(m_edges, element_edges); - } - - // read mesh data into arrays - ParseVectorDataArray(m_vertices, Vertices); - ParseVectorDataArray(m_face_indices, PolygonVertexIndex); - - 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 - const ElementCollection &Layer = sc->GetCollection("Layer"); - - // Store all layers - std::vector<std::tuple<int, std::string>> valid_layers; - - // now read the sub mesh information from the geometry (normals, uvs, etc) - for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { - const ScopePtr layer = GetRequiredScope(it->second); - const ElementCollection &LayerElement = layer->GetCollection("LayerElement"); - for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { - std::string layer_name = eit->first; - ElementPtr element_layer = eit->second; - const ScopePtr layer_element = GetRequiredScope(element_layer); - - // Actual usable 'type' LayerElementUV, LayerElementNormal, etc - const ElementPtr Type = GetRequiredElement(layer_element, "Type"); - const ElementPtr TypedIndex = GetRequiredElement(layer_element, "TypedIndex"); - const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0)); - const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0)); - - // we only need the layer name and the typed index. - valid_layers.push_back(std::tuple<int, std::string>(typedIndex, type)); - } - } - - // get object / mesh directly from the FBX by the element ID. - const ScopePtr top = GetRequiredScope(element); - - // iterate over all layers for the mesh (uvs, normals, smoothing groups, colors, etc) - for (size_t x = 0; x < valid_layers.size(); x++) { - const int layer_id = std::get<0>(valid_layers[x]); - const std::string &layer_type_name = std::get<1>(valid_layers[x]); - - // Get collection of elements from the XLayerMap (example: LayerElementUV) - // this must contain our proper elements. - - // This is stupid, because it means we select them ALL not just the one we want. - // but it's fine we can match by id. - - const ElementCollection &candidates = top->GetCollection(layer_type_name); - - ElementMap::const_iterator iter; - for (iter = candidates.first; iter != candidates.second; ++iter) { - const ScopePtr layer_scope = GetRequiredScope(iter->second); - TokenPtr layer_token = GetRequiredToken(iter->second, 0); - const int index = ParseTokenAsInt(layer_token); - - ERR_FAIL_COND_MSG(layer_scope == nullptr, "prevented crash, layer scope is invalid"); - - if (index == layer_id) { - const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(layer_scope, "MappingInformationType"), 0)); - - const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(layer_scope, "ReferenceInformationType"), 0)); - - if (layer_type_name == "LayerElementUV") { - if (index == 0) { - m_uv_0 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV"); - } else if (index == 1) { - m_uv_1 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV"); - } - } else if (layer_type_name == "LayerElementMaterial") { - m_material_allocation_ids = resolve_vertex_data_array<int>(layer_scope, MappingInformationType, ReferenceInformationType, "Materials"); - } else if (layer_type_name == "LayerElementNormal") { - m_normals = resolve_vertex_data_array<Vector3>(layer_scope, MappingInformationType, ReferenceInformationType, "Normals"); - } else if (layer_type_name == "LayerElementColor") { - m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors", "ColorIndex"); - // NOTE: this is a useful sanity check to ensure you're getting any color data which is not default. - // const Color first_color_check = m_colors.data[0]; - // bool colors_are_all_the_same = true; - // size_t i = 1; - // for(i = 1; i < m_colors.data.size(); i++) - // { - // const Color current_color = m_colors.data[i]; - // if(current_color.is_equal_approx(first_color_check)) - // { - // continue; - // } - // else - // { - // colors_are_all_the_same = false; - // break; - // } - // } - // - // if(colors_are_all_the_same) - // { - // print_error("Color serialisation is not working for vertex colors some should be different in the test asset."); - // } - // else - // { - // print_verbose("Color array has unique colors at index: " + itos(i)); - // } - } - } - } - } - - print_verbose("Mesh statistics \nuv_0: " + m_uv_0.debug_info() + "\nuv_1: " + m_uv_1.debug_info() + "\nvertices: " + itos(m_vertices.size())); - - // Compose the edge of the mesh. - // You can see how the edges are stored into the FBX here: https://gist.github.com/AndreaCatania/da81840f5aa3b2feedf189e26c5a87e6 - for (size_t i = 0; i < m_edges.size(); i += 1) { - ERR_FAIL_INDEX_MSG((size_t)m_edges[i], m_face_indices.size(), "The edge is pointing to a weird location in the face indices. The FBX is corrupted."); - int polygon_vertex_0 = m_face_indices[m_edges[i]]; - int polygon_vertex_1; - if (polygon_vertex_0 < 0) { - // The polygon_vertex_0 points to the end of a polygon, so it's - // connected with the beginning of polygon in the edge list. - - // Fist invert the vertex. - polygon_vertex_0 = ~polygon_vertex_0; - - // Search the start vertex of the polygon. - // Iterate from the polygon_vertex_index backward till the start of - // the polygon is found. - ERR_FAIL_COND_MSG(m_edges[i] - 1 < 0, "The polygon is not yet started and we already need the final vertex. This FBX is corrupted."); - bool found_it = false; - for (int x = m_edges[i] - 1; x >= 0; x -= 1) { - if (x == 0) { - // This for sure is the start. - polygon_vertex_1 = m_face_indices[x]; - found_it = true; - break; - } else if (m_face_indices[x] < 0) { - // This is the end of the previous polygon, so the next is - // the start of the polygon we need. - polygon_vertex_1 = m_face_indices[x + 1]; - found_it = true; - break; - } - } - // As the algorithm above, this check is useless. Because the first - // 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 { - ERR_FAIL_INDEX_MSG((size_t)(m_edges[i] + 1), m_face_indices.size(), "FBX The other FBX edge seems to point to an invalid vertices. This FBX file is corrupted."); - // Take the next vertex - polygon_vertex_1 = m_face_indices[m_edges[i] + 1]; - } - - if (polygon_vertex_1 < 0) { - // We don't care if the `polygon_vertex_1` is the end of the polygon, - // for `polygon_vertex_1` so we can just invert it. - polygon_vertex_1 = ~polygon_vertex_1; - } - - ERR_FAIL_COND_MSG(polygon_vertex_0 == polygon_vertex_1, "The vertices of this edge can't be the same, Is this a point???. This FBX file is corrupted."); - - // Just create the edge. - edge_map.push_back({ polygon_vertex_0, polygon_vertex_1 }); - } -} - -MeshGeometry::~MeshGeometry() { - // empty -} - -const std::vector<Vector3> &MeshGeometry::get_vertices() const { - return m_vertices; -} - -const std::vector<MeshGeometry::Edge> &MeshGeometry::get_edge_map() const { - return edge_map; -} - -const std::vector<int> &MeshGeometry::get_polygon_indices() const { - return m_face_indices; -} - -const std::vector<int> &MeshGeometry::get_edges() const { - return m_edges; -} - -const MeshGeometry::MappingData<Vector3> &MeshGeometry::get_normals() const { - return m_normals; -} - -const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_0() const { - //print_verbose("get uv_0 " + m_uv_0.debug_info() ); - return m_uv_0; -} - -const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_1() const { - //print_verbose("get uv_1 " + m_uv_1.debug_info() ); - return m_uv_1; -} - -const MeshGeometry::MappingData<Color> &MeshGeometry::get_colors() const { - return m_colors; -} - -const MeshGeometry::MappingData<int> &MeshGeometry::get_material_allocation_id() const { - return m_material_allocation_ids; -} - -int MeshGeometry::get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b) { - for (size_t i = 0; i < p_map.size(); i += 1) { - if ((p_map[i].vertex_0 == p_vertex_a && p_map[i].vertex_1 == p_vertex_b) || (p_map[i].vertex_1 == p_vertex_a && p_map[i].vertex_0 == p_vertex_b)) { - return i; - } - } - return -1; -} - -MeshGeometry::Edge MeshGeometry::get_edge(const std::vector<Edge> &p_map, int p_id) { - ERR_FAIL_INDEX_V_MSG((size_t)p_id, p_map.size(), Edge({ -1, -1 }), "ID not found."); - return p_map[p_id]; -} - -template <class T> -MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array( - const ScopePtr source, - const std::string &MappingInformationType, - const std::string &ReferenceInformationType, - const std::string &dataElementName, - const std::string &indexOverride) { - ERR_FAIL_COND_V_MSG(source == nullptr, MappingData<T>(), "Invalid scope operator preventing memory corruption"); - - // UVIndex, MaterialIndex, NormalIndex, etc.. - std::string indexDataElementName; - - if (!indexOverride.empty()) { - // Colors should become ColorIndex - indexDataElementName = indexOverride; - } else { - // Some indexes will exist. - indexDataElementName = dataElementName + "Index"; - } - - // goal: expand everything to be per vertex - - ReferenceType l_ref_type = ReferenceType::direct; - - // Read the reference type into the enumeration - if (ReferenceInformationType == "IndexToDirect") { - l_ref_type = ReferenceType::index_to_direct; - } else if (ReferenceInformationType == "Index") { - // set non legacy index to direct mapping - l_ref_type = ReferenceType::index; - } else if (ReferenceInformationType == "Direct") { - l_ref_type = ReferenceType::direct; - } else { - ERR_FAIL_V_MSG(MappingData<T>(), "invalid reference type has the FBX format changed?"); - } - - MapType l_map_type = MapType::none; - - if (MappingInformationType == "None") { - l_map_type = MapType::none; - } else if (MappingInformationType == "ByVertice") { - l_map_type = MapType::vertex; - } else if (MappingInformationType == "ByPolygonVertex") { - l_map_type = MapType::polygon_vertex; - } else if (MappingInformationType == "ByPolygon") { - l_map_type = MapType::polygon; - } else if (MappingInformationType == "ByEdge") { - l_map_type = MapType::edge; - } else if (MappingInformationType == "AllSame") { - l_map_type = MapType::all_the_same; - } else { - print_error("invalid mapping type: " + String(MappingInformationType.c_str())); - } - - // create mapping data - MeshGeometry::MappingData<T> tempData; - tempData.map_type = l_map_type; - tempData.ref_type = l_ref_type; - - // parse data into array - ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName)); - - // index array won't always exist - const ElementPtr element = GetOptionalElement(source, indexDataElementName); - if (element) { - ParseVectorDataArray(tempData.index, element); - } - - return tempData; -} -// ------------------------------------------------------------------------------------------------ -ShapeGeometry::ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Geometry(id, element, name, doc) { - const ScopePtr sc = element->Compound(); - if (nullptr == sc) { - DOMError("failed to read Geometry object (class: Shape), no data scope found"); - } - const ElementPtr Indexes = GetRequiredElement(sc, "Indexes", element); - const ElementPtr Normals = GetRequiredElement(sc, "Normals", element); - const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element); - ParseVectorDataArray(m_indices, Indexes); - ParseVectorDataArray(m_vertices, Vertices); - ParseVectorDataArray(m_normals, Normals); -} - -// ------------------------------------------------------------------------------------------------ -ShapeGeometry::~ShapeGeometry() { - // empty -} -// ------------------------------------------------------------------------------------------------ -const std::vector<Vector3> &ShapeGeometry::GetVertices() const { - return m_vertices; -} -// ------------------------------------------------------------------------------------------------ -const std::vector<Vector3> &ShapeGeometry::GetNormals() const { - return m_normals; -} -// ------------------------------------------------------------------------------------------------ -const std::vector<unsigned int> &ShapeGeometry::GetIndices() const { - return m_indices; -} -// ------------------------------------------------------------------------------------------------ -LineGeometry::LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Geometry(id, element, name, doc) { - const ScopePtr sc = element->Compound(); - if (!sc) { - DOMError("failed to read Geometry object (class: Line), no data scope found"); - } - const ElementPtr Points = GetRequiredElement(sc, "Points", element); - const ElementPtr PointsIndex = GetRequiredElement(sc, "PointsIndex", element); - ParseVectorDataArray(m_vertices, Points); - ParseVectorDataArray(m_indices, PointsIndex); -} - -// ------------------------------------------------------------------------------------------------ -LineGeometry::~LineGeometry() { - // empty -} -// ------------------------------------------------------------------------------------------------ -const std::vector<Vector3> &LineGeometry::GetVertices() const { - return m_vertices; -} -// ------------------------------------------------------------------------------------------------ -const std::vector<int> &LineGeometry::GetIndices() const { - return m_indices; -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.h b/modules/fbx/fbx_parser/FBXMeshGeometry.h deleted file mode 100644 index 26fc1914d1..0000000000 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.h +++ /dev/null @@ -1,263 +0,0 @@ -/*************************************************************************/ -/* FBXMeshGeometry.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#ifndef FBX_MESH_GEOMETRY_H -#define FBX_MESH_GEOMETRY_H - -#include "core/math/color.h" -#include "core/math/vector2.h" -#include "core/math/vector3.h" -#include "core/templates/vector.h" - -#include "FBXDocument.h" -#include "FBXParser.h" - -#include <iostream> - -#define AI_MAX_NUMBER_OF_TEXTURECOORDS 4 -#define AI_MAX_NUMBER_OF_COLOR_SETS 8 - -namespace FBXDocParser { - -/* - * DOM base class for all kinds of FBX geometry - */ -class Geometry : public Object { -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 nullptr */ - const Skin *DeformerSkin() const; - - const std::vector<const BlendShape *> &get_blend_shapes() const; - - size_t get_blend_shape_count() const { - return blendShapes.size(); - } - -private: - const Skin *skin = nullptr; - std::vector<const BlendShape *> blendShapes; -}; - -typedef std::vector<int> MatIndexArray; - -/// Map Geometry stores the FBX file information. -/// -/// # FBX doc. -/// ## Reference type declared: -/// - Direct (directly related to the mapping information type) -/// - IndexToDirect (Map with key value, meaning depends on the MappingInformationType) -/// -/// ## 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 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. -/// * One mapping per polygon polygon x has this normal x -/// * For each vertex of the polygon then set the normal to x -/// * ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id) -/// * AllSame There can be only one mapping coordinate for the whole surface. -class MeshGeometry : public Geometry { -public: - enum class MapType { - none = 0, // No mapping type. Stored as "None". - vertex, // Maps per vertex. Stored as "ByVertice". - polygon_vertex, // Maps per polygon vertex. Stored as "ByPolygonVertex". - polygon, // Maps per polygon. Stored as "ByPolygon". - edge, // Maps per edge. Stored as "ByEdge". - all_the_same // Uaps to everything. Stored as "AllSame". - }; - - enum class ReferenceType { - direct = 0, - index = 1, - index_to_direct = 2 - }; - - template <class T> - struct MappingData { - MapType map_type = MapType::none; - ReferenceType ref_type = ReferenceType::direct; - std::vector<T> data; - /// The meaning of the indices depends from the `MapType`. - /// If `ref_type` is `direct` this map is hollow. - std::vector<int> index; - - String debug_info() const { - return "indexes: " + itos(index.size()) + " data: " + itos(data.size()); - } - }; - - struct Edge { - int vertex_0 = 0, vertex_1 = 0; - Edge(int v0, int v1) : - vertex_0(v0), vertex_1(v1) {} - Edge() {} - }; - -public: - MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); - - virtual ~MeshGeometry(); - - const std::vector<Vector3> &get_vertices() const; - const std::vector<Edge> &get_edge_map() const; - const std::vector<int> &get_polygon_indices() const; - const std::vector<int> &get_edges() const; - const MappingData<Vector3> &get_normals() const; - const MappingData<Vector2> &get_uv_0() const; - const MappingData<Vector2> &get_uv_1() const; - const MappingData<Color> &get_colors() const; - const MappingData<int> &get_material_allocation_id() const; - - /// 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); - // 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); - -private: - // Read directly from the FBX file. - std::vector<Vector3> m_vertices; - std::vector<Edge> edge_map; - std::vector<int> m_face_indices; - std::vector<int> m_edges; - MappingData<Vector3> m_normals; - MappingData<Vector2> m_uv_0; // first uv coordinates - MappingData<Vector2> m_uv_1; // second uv coordinates - MappingData<Color> m_colors; // colors for the mesh - MappingData<int> m_material_allocation_ids; // slot of material used - - template <class T> - MappingData<T> resolve_vertex_data_array( - const ScopePtr source, - const std::string &MappingInformationType, - const std::string &ReferenceInformationType, - const std::string &dataElementName, - const std::string &indexOverride = ""); -}; - -/* - * DOM class for FBX geometry of type "Shape" - */ -class ShapeGeometry : public Geometry { -public: - /** The class constructor */ - ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); - - /** The class destructor */ - virtual ~ShapeGeometry(); - - /** Get a list of all vertex points, non-unique*/ - const std::vector<Vector3> &GetVertices() const; - - /** Get a list of all vertex normals or an empty array if - * no normals are specified. */ - const std::vector<Vector3> &GetNormals() const; - - /** Return list of vertex indices. */ - const std::vector<unsigned int> &GetIndices() const; - -private: - std::vector<Vector3> m_vertices; - std::vector<Vector3> m_normals; - std::vector<unsigned int> m_indices; -}; -/** - * DOM class for FBX geometry of type "Line" - */ -class LineGeometry : public Geometry { -public: - /** The class constructor */ - LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); - - /** The class destructor */ - virtual ~LineGeometry(); - - /** Get a list of all vertex points, non-unique*/ - const std::vector<Vector3> &GetVertices() const; - - /** Return list of vertex indices. */ - const std::vector<int> &GetIndices() const; - -private: - std::vector<Vector3> m_vertices; - std::vector<int> m_indices; -}; -} // namespace FBXDocParser - -#endif // FBX_MESH_GEOMETRY_H diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp deleted file mode 100644 index 03c9de0c35..0000000000 --- a/modules/fbx/fbx_parser/FBXModel.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/*************************************************************************/ -/* FBXModel.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXModel.cpp - * @brief Assimp::FBX::Model implementation - */ - -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXMeshGeometry.h" -#include "FBXParser.h" - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), shading("Y") { - const ScopePtr sc = GetRequiredScope(element); - const ElementPtr Shading = sc->GetElement("Shading"); - const ElementPtr Culling = sc->GetElement("Culling"); - - if (Shading) { - shading = GetRequiredToken(Shading, 0)->StringContents(); - } - - if (Culling) { - culling = ParseTokenAsString(GetRequiredToken(Culling, 0)); - } - - ResolveLinks(element, doc); -} - -// ------------------------------------------------------------------------------------------------ -Model::~Model() { -} - -ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Model(id, element, doc, name){}; - -ModelLimbNode::~ModelLimbNode() { -} - -// ------------------------------------------------------------------------------------------------ -void Model::ResolveLinks(const ElementPtr element, const Document &doc) { - const char *const arr[] = { "Geometry", "Material", "NodeAttribute" }; - - // resolve material - const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), arr, 3); - - materials.reserve(conns.size()); - geometry.reserve(conns.size()); - attributes.reserve(conns.size()); - for (const Connection *con : conns) { - // material and geometry links should be Object-Object connections - if (con->PropertyName().length()) { - continue; - } - - const Object *const ob = con->SourceObject(); - if (!ob) { - //DOMWarning("failed to read source object for incoming Model link, ignoring",&element); - continue; - } - - const Material *const mat = dynamic_cast<const Material *>(ob); - if (mat) { - materials.push_back(mat); - continue; - } - - const Geometry *const geo = dynamic_cast<const Geometry *>(ob); - if (geo) { - geometry.push_back(geo); - continue; - } - - const NodeAttribute *const att = dynamic_cast<const NodeAttribute *>(ob); - if (att) { - attributes.push_back(att); - continue; - } - - DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring", element); - continue; - } -} - -// ------------------------------------------------------------------------------------------------ -bool Model::IsNull() const { - const std::vector<const NodeAttribute *> &attrs = GetAttributes(); - for (const NodeAttribute *att : attrs) { - const Null *null_tag = dynamic_cast<const Null *>(att); - if (null_tag) { - return true; - } - } - - return false; -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp deleted file mode 100644 index 15184a0f5d..0000000000 --- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************/ -/* FBXNodeAttribute.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXNoteAttribute.cpp - * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation - */ - -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXParser.h" -#include <iostream> - -namespace FBXDocParser { -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name) { -} - -// ------------------------------------------------------------------------------------------------ -NodeAttribute::~NodeAttribute() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -CameraSwitcher::CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - NodeAttribute(id, element, doc, name) { - const ScopePtr sc = GetRequiredScope(element); - const ElementPtr CameraId = sc->GetElement("CameraId"); - const ElementPtr CameraName = sc->GetElement("CameraName"); - const ElementPtr CameraIndexName = sc->GetElement("CameraIndexName"); - - if (CameraId) { - cameraId = ParseTokenAsInt(GetRequiredToken(CameraId, 0)); - } - - if (CameraName) { - cameraName = GetRequiredToken(CameraName, 0)->StringContents(); - } - - if (CameraIndexName && CameraIndexName->Tokens().size()) { - cameraIndexName = GetRequiredToken(CameraIndexName, 0)->StringContents(); - } -} - -// ------------------------------------------------------------------------------------------------ -CameraSwitcher::~CameraSwitcher() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -Camera::Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - NodeAttribute(id, element, doc, name) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -Camera::~Camera() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -Light::Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - NodeAttribute(id, element, doc, name) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -Light::~Light() { -} - -// ------------------------------------------------------------------------------------------------ -Null::Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - NodeAttribute(id, element, doc, name) { -} - -// ------------------------------------------------------------------------------------------------ -Null::~Null() { -} - -// ------------------------------------------------------------------------------------------------ -LimbNode::LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - NodeAttribute(id, element, doc, name) { - //std::cout << "limb node: " << name << std::endl; - //const Scope &sc = GetRequiredScope(element); - - //const ElementPtr const TypeFlag = sc["TypeFlags"]; - - // keep this it can dump new properties for you - // for( auto element : sc.Elements()) - // { - // std::cout << "limbnode element: " << element.first << std::endl; - // } - - // if(TypeFlag) - // { - // // std::cout << "type flag: " << GetRequiredToken(*TypeFlag, 0).StringContents() << std::endl; - // } -} - -// ------------------------------------------------------------------------------------------------ -LimbNode::~LimbNode() { -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXParseTools.h b/modules/fbx/fbx_parser/FBXParseTools.h deleted file mode 100644 index b4003bbec5..0000000000 --- a/modules/fbx/fbx_parser/FBXParseTools.h +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************/ -/* FBXParseTools.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 FBX_PARSE_TOOLS_H -#define FBX_PARSE_TOOLS_H - -#include "core/error/error_macros.h" -#include "core/string/ustring.h" - -#include <stdint.h> -#include <algorithm> -#include <locale> - -template <class char_t> -inline bool IsNewLine(char_t c) { - return c == '\n' || c == '\r'; -} -template <class char_t> -inline bool IsSpace(char_t c) { - return (c == (char_t)' ' || c == (char_t)'\t'); -} - -template <class char_t> -inline bool IsSpaceOrNewLine(char_t c) { - return IsNewLine(c) || IsSpace(c); -} - -template <class char_t> -inline bool IsLineEnd(char_t c) { - return (c == (char_t)'\r' || c == (char_t)'\n' || c == (char_t)'\0' || c == (char_t)'\f'); -} - -// ------------------------------------------------------------------------------------ -// 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 = nullptr, unsigned int *max_inout = nullptr) { - unsigned int cur = 0; - uint64_t value = 0; - - errored = *in < '0' || *in > '9'; - ERR_FAIL_COND_V_MSG(errored, 0, "The string cannot be converted parser error"); - - for (;;) { - if (*in < '0' || *in > '9') { - break; - } - - const uint64_t new_value = (value * (uint64_t)10) + ((uint64_t)(*in - '0')); - - // numeric overflow, we rely on you - if (new_value < value) { - //WARN_PRINT( "Converting the string \" " + in + " \" into a value resulted in overflow." ); - return 0; - } - - value = new_value; - - ++in; - ++cur; - - if (max_inout && *max_inout == cur) { - if (out) { /* skip to end */ - while (*in >= '0' && *in <= '9') { - ++in; - } - *out = in; - } - - return value; - } - } - if (out) { - *out = in; - } - - if (max_inout) { - *max_inout = cur; - } - - return value; -} - -#endif // FBX_PARSE_TOOLS_H diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp deleted file mode 100644 index dbc9a0e46d..0000000000 --- a/modules/fbx/fbx_parser/FBXParser.cpp +++ /dev/null @@ -1,1322 +0,0 @@ -/*************************************************************************/ -/* FBXParser.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXParser.cpp - * @brief Implementation of the FBX parser and the rudimentary DOM that we use - */ - -#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_3d.h" -#include "core/math/vector3.h" -#include "core/string/print_string.h" - -using namespace FBXDocParser; -namespace { - -// Initially, we did reinterpret_cast, breaking strict aliasing rules. -// This actually caused trouble on Android, so let's be safe this time. -// https://github.com/assimp/assimp/issues/24 -template <typename T> -T SafeParse(const char *data, const char *end) { - // Actual size validation happens during Tokenization so - // this is valid as an assertion. - (void)(end); - //ai_assert(static_cast<size_t>(end - data) >= sizeof(T)); - T result = static_cast<T>(0); - ::memcpy(&result, data, sizeof(T)); - return result; -} -} // namespace - -namespace FBXDocParser { - -// ------------------------------------------------------------------------------------------------ -Element::Element(const TokenPtr key_token, Parser &parser) : - key_token(key_token) { - TokenPtr n = nullptr; - do { - n = parser.AdvanceToNextToken(); - if (n == nullptr) { - continue; - } - - if (!n) { - print_error("unexpected end of file, expected closing bracket" + String(parser.LastToken()->StringContents().c_str())); - } - - if (n && n->Type() == TokenType_DATA) { - tokens.push_back(n); - TokenPtr prev = n; - n = parser.AdvanceToNextToken(); - - if (n == nullptr) { - break; - } - - 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(); - - // some exporters are missing a comma on the next line - if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) { - tokens.push_back(n); - continue; - } - - 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; - } - } - - if (n && n->Type() == TokenType_OPEN_BRACKET) { - 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(); - return; - } - } while (n && n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); -} - -// ------------------------------------------------------------------------------------------------ -Element::~Element() { -} - -// ------------------------------------------------------------------------------------------------ -Scope::Scope(Parser &parser, bool topLevel) { - if (!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))); - - // Element() should stop at the next Key token (or right after a Close token) - n = parser.CurrentToken(); - if (n == nullptr) { - if (topLevel) { - return; - } - - //print_error("unexpected end of file" + String(parser.LastToken()->StringContents().c_str())); - } - } -} - -// ------------------------------------------------------------------------------------------------ -Scope::~Scope() { - for (ElementMap::value_type &v : elements) { - delete v.second; - v.second = nullptr; - } - - elements.clear(); -} - -// ------------------------------------------------------------------------------------------------ -Parser::Parser(const TokenList &tokens, bool is_binary) : - corrupt(false), tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) { - root = new_Scope(*this, true); - scopes.push_back(root); -} - -// ------------------------------------------------------------------------------------------------ -Parser::~Parser() { - for (ScopePtr scope : scopes) { - delete scope; - scope = nullptr; - } -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::AdvanceToNextToken() { - last = current; - if (cursor == tokens.end()) { - current = nullptr; - } else { - current = *cursor++; - } - return current; -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::CurrentToken() const { - return current; -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::LastToken() const { - return last; -} - -// ------------------------------------------------------------------------------------------------ -uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out) { - ERR_FAIL_COND_V_MSG(t == nullptr, 0L, "Invalid token passed to ParseTokenAsID"); - err_out = nullptr; - - if (t->Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if (t->IsBinary()) { - const char *data = t->begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0L; - } - - uint64_t id = SafeParse<uint64_t>(data + 1, t->end()); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t->end() - t->begin()); - //ai_assert(length > 0); - - const char *out = nullptr; - bool errored = false; - - const uint64_t id = strtoul10_64(t->begin(), errored, &out, &length); - if (errored || out > t->end()) { - err_out = "failed to parse ID (text)"; - return 0L; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsID() with print_error handling -uint64_t ParseTokenAsID(const TokenPtr t) { - const char *err = nullptr; - const uint64_t i = ParseTokenAsID(t, err); - if (err) { - print_error(String(err) + " " + String(t->StringContents().c_str())); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out) { - // same as ID parsing, except there is a trailing asterisk - err_out = nullptr; - - if (t->Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if (t->IsBinary()) { - const char *data = t->begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0; - } - - uint64_t id = SafeParse<uint64_t>(data + 1, t->end()); - AI_SWAP8(id); - return static_cast<size_t>(id); - } - - if (*t->begin() != '*') { - err_out = "expected asterisk before array dimension"; - return 0; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t->end() - t->begin()); - if (length == 0) { - err_out = "expected valid integer number after asterisk"; - return 0; - } - - const char *out = nullptr; - bool errored = false; - const size_t id = static_cast<size_t>(strtoul10_64(t->begin() + 1, errored, &out, &length)); - if (errored || out > t->end()) { - print_error("failed to parse id"); - err_out = "failed to parse ID"; - return 0; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -float ParseTokenAsFloat(const TokenPtr t, const char *&err_out) { - err_out = nullptr; - - if (t->Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0.0f; - } - - if (t->IsBinary()) { - const char *data = t->begin(); - if (data[0] != 'F' && data[0] != 'D') { - err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)"; - return 0.0f; - } - - if (data[0] == 'F') { - return SafeParse<float>(data + 1, t->end()); - } else { - return static_cast<float>(SafeParse<double>(data + 1, t->end())); - } - } - -// need to copy the input string to a temporary buffer -// first - next in the fbx token stream comes ',', -// which fast_atof could interpret as decimal point. -#define MAX_FLOAT_LENGTH 31 - char temp[MAX_FLOAT_LENGTH + 1]; - const size_t length = static_cast<size_t>(t->end() - t->begin()); - std::copy(t->begin(), t->end(), temp); - temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH), length)] = '\0'; - - return atof(temp); -} - -// ------------------------------------------------------------------------------------------------ -int ParseTokenAsInt(const TokenPtr t, const char *&err_out) { - err_out = nullptr; - - if (t->Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - // binary files are simple to parse - if (t->IsBinary()) { - const char *data = t->begin(); - if (data[0] != 'I') { - err_out = "failed to parse I(nt), unexpected data type (binary)"; - return 0; - } - - int32_t ival = SafeParse<int32_t>(data + 1, t->end()); - AI_SWAP4(ival); - return static_cast<int>(ival); - } - - // ASCII files are unsafe. - const size_t length = static_cast<size_t>(t->end() - t->begin()); - if (length == 0) { - err_out = "expected valid integer number after asterisk"; - ERR_FAIL_V_MSG(0, "expected valid integer number after asterisk"); - } - - // must not be null for strtol to work - char *out = (char *)t->end(); - // string begin, end ptr ref, base 10 - const int value = strtol(t->begin(), &out, 10); - if (out == nullptr || out != t->end()) { - err_out = "failed to parse ID"; - ERR_FAIL_V_MSG(0, "failed to parse ID"); - } - - return value; -} - -// ------------------------------------------------------------------------------------------------ -int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out) { - err_out = nullptr; - - if (t->Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if (t->IsBinary()) { - const char *data = t->begin(); - if (data[0] != 'L') { - err_out = "failed to parse Int64, unexpected data type"; - return 0L; - } - - int64_t id = SafeParse<int64_t>(data + 1, t->end()); - AI_SWAP8(id); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t->end() - t->begin()); - //ai_assert(length > 0); - - char *out = nullptr; - const int64_t id = strtol(t->begin(), &out, length); - if (out > t->end()) { - err_out = "failed to parse Int64 (text)"; - return 0L; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -std::string ParseTokenAsString(const TokenPtr t, const char *&err_out) { - err_out = nullptr; - - if (t->Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return ""; - } - - if (t->IsBinary()) { - const char *data = t->begin(); - if (data[0] != 'S') { - err_out = "failed to parse String, unexpected data type (binary)"; - return ""; - } - - // read string length - int32_t len = SafeParse<int32_t>(data + 1, t->end()); - AI_SWAP4(len); - - //ai_assert(t.end() - data == 5 + len); - return std::string(data + 5, len); - } - - const size_t length = static_cast<size_t>(t->end() - t->begin()); - if (length < 2) { - err_out = "token is too short to hold a string"; - return ""; - } - - const char *s = t->begin(), *e = t->end() - 1; - if (*s != '\"' || *e != '\"') { - err_out = "expected double quoted string"; - return ""; - } - - return std::string(s + 1, length - 2); -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -// read the type code and element count of a binary data array and stop there -void ReadBinaryDataArrayHead(const char *&data, const char *end, char &type, uint32_t &count, - const ElementPtr el) { - TokenPtr token = el->KeyToken(); - if (static_cast<size_t>(end - data) < 5) { - print_error("binary data array is too short, need five (5) bytes for type signature and element count: " + String(token->StringContents().c_str())); - } - - // data type - type = *data; - - // read number of elements - uint32_t len = SafeParse<uint32_t>(data + 1, end); - AI_SWAP4(len); - - count = len; - data += 5; -} - -// ------------------------------------------------------------------------------------------------ -// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header) -void ReadBinaryDataArray(char type, uint32_t count, const char *&data, const char *end, - std::vector<char> &buff, - const ElementPtr /*el*/) { - uint32_t encmode = SafeParse<uint32_t>(data, end); - AI_SWAP4(encmode); - data += 4; - - // next comes the compressed length - uint32_t comp_len = SafeParse<uint32_t>(data, end); - AI_SWAP4(comp_len); - data += 4; - - //ai_assert(data + comp_len == end); - - // determine the length of the uncompressed data by looking at the type signature - uint32_t stride = 0; - switch (type) { - case 'f': - case 'i': - stride = 4; - break; - - case 'd': - case 'l': - stride = 8; - break; - } - - const uint32_t full_length = stride * count; - buff.resize(full_length); - - if (encmode == 0) { - //ai_assert(full_length == comp_len); - - // plain data, no compression - std::copy(data, end, buff.begin()); - } else if (encmode == 1) { - // zlib/deflate, next comes ZIP head (0x78 0x01) - // see https://www.ietf.org/rfc/rfc1950.txt - - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.data_type = Z_BINARY; - - // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib - if (Z_OK != inflateInit(&zstream)) { - print_error("failure initializing zlib"); - } - - zstream.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(data)); - zstream.avail_in = comp_len; - - zstream.avail_out = static_cast<uInt>(buff.size()); - zstream.next_out = reinterpret_cast<Bytef *>(&*buff.begin()); - const int ret = inflate(&zstream, Z_FINISH); - - if (ret != Z_STREAM_END && ret != Z_OK) { - print_error("failure decompressing compressed data section"); - } - - // terminate zlib - inflateEnd(&zstream); - } -#ifdef ASSIMP_BUILD_DEBUG - else { - // runtime check for this happens at tokenization stage - //ai_assert(false); - } -#endif - - data += comp_len; - //ai_assert(data == end); -} -} // namespace - -// ------------------------------------------------------------------------------------------------ -// read an array of float3 tuples -void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el) { - out.resize(0); - - const TokenList &tok = el->Tokens(); - TokenPtr token = el->KeyToken(); - if (tok.empty()) { - print_error("unexpected empty element" + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (count % 3 != 0) { - print_error("number of floats is not a multiple of three (3) (binary)" + String(token->StringContents().c_str())); - } - - if (!count) { - return; - } - - if (type != 'd' && type != 'f') { - print_error("expected float or double array (binary)" + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count3 = count / 3; - out.reserve(count3); - - if (type == 'd') { - const double *d = reinterpret_cast<const double *>(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, d += 3) { - out.push_back(Vector3(static_cast<real_t>(d[0]), - static_cast<real_t>(d[1]), - static_cast<real_t>(d[2]))); - } - } else if (type == 'f') { - const float *f = reinterpret_cast<const float *>(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, f += 3) { - out.push_back(Vector3(f[0], f[1], f[2])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // may throw bad_alloc if the input is rubbish, but this need - // not to be prevented - importing would fail but we wouldn't - // crash since assimp handles this case properly. - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - if (a->Tokens().size() % 3 != 0) { - print_error("number of floats is not a multiple of three (3)" + String(token->StringContents().c_str())); - } else { - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - Vector3 v; - v.x = ParseTokenAsFloat(*it++); - v.y = ParseTokenAsFloat(*it++); - v.z = ParseTokenAsFloat(*it++); - - out.push_back(v); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of color4 tuples -void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el) { - out.resize(0); - const TokenList &tok = el->Tokens(); - - TokenPtr token = el->KeyToken(); - - if (tok.empty()) { - print_error("unexpected empty element" + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (count % 4 != 0) { - print_error("number of floats is not a multiple of four (4) (binary)" + String(token->StringContents().c_str())); - } - - if (!count) { - return; - } - - if (type != 'd' && type != 'f') { - print_error("expected float or double array (binary)" + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count4 = count / 4; - out.reserve(count4); - - if (type == 'd') { - const double *d = reinterpret_cast<const double *>(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, d += 4) { - out.push_back(Color(static_cast<float>(d[0]), - static_cast<float>(d[1]), - static_cast<float>(d[2]), - static_cast<float>(d[3]))); - } - } else if (type == 'f') { - const float *f = reinterpret_cast<const float *>(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, f += 4) { - out.push_back(Color(f[0], f[1], f[2], f[3])); - } - } - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - if (a->Tokens().size() % 4 != 0) { - print_error("number of floats is not a multiple of four (4)" + String(token->StringContents().c_str())); - } - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - Color v; - v.r = ParseTokenAsFloat(*it++); - v.g = ParseTokenAsFloat(*it++); - v.b = ParseTokenAsFloat(*it++); - v.a = ParseTokenAsFloat(*it++); - - out.push_back(v); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of float2 tuples -void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el) { - out.resize(0); - const TokenList &tok = el->Tokens(); - TokenPtr token = el->KeyToken(); - if (tok.empty()) { - print_error("unexpected empty element" + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (count % 2 != 0) { - print_error("number of floats is not a multiple of two (2) (binary)" + String(token->StringContents().c_str())); - } - - if (!count) { - return; - } - - if (type != 'd' && type != 'f') { - print_error("expected float or double array (binary)" + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count2 = count / 2; - out.reserve(count2); - - if (type == 'd') { - const double *d = reinterpret_cast<const double *>(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, d += 2) { - out.push_back(Vector2(static_cast<float>(d[0]), - static_cast<float>(d[1]))); - } - } else if (type == 'f') { - const float *f = reinterpret_cast<const float *>(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, f += 2) { - out.push_back(Vector2(f[0], f[1])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - if (a->Tokens().size() % 2 != 0) { - print_error("number of floats is not a multiple of two (2)" + String(token->StringContents().c_str())); - } else { - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - Vector2 v; - v.x = ParseTokenAsFloat(*it++); - v.y = ParseTokenAsFloat(*it++); - out.push_back(v); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of ints -void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el) { - out.resize(0); - const TokenList &tok = el->Tokens(); - TokenPtr token = el->KeyToken(); - if (tok.empty()) { - print_error("unexpected empty element" + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'i') { - print_error("expected int array (binary)" + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * 4); - - out.reserve(count); - - const int32_t *ip = reinterpret_cast<const int32_t *>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - int32_t val = *ip; - AI_SWAP4(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - const int ival = ParseTokenAsInt(*it++); - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of floats -void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el) { - out.resize(0); - const TokenList &tok = el->Tokens(); - TokenPtr token = el->KeyToken(); - if (tok.empty()) { - print_error("unexpected empty element: " + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'd' && type != 'f') { - print_error("expected float or double array (binary) " + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - if (type == 'd') { - const double *d = reinterpret_cast<const double *>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++d) { - out.push_back(static_cast<float>(*d)); - } - } else if (type == 'f') { - const float *f = reinterpret_cast<const float *>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++f) { - out.push_back(*f); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - const float ival = ParseTokenAsFloat(*it++); - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of uints -void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el) { - out.resize(0); - const TokenList &tok = el->Tokens(); - const TokenPtr token = el->KeyToken(); - - ERR_FAIL_COND_MSG(!token, "invalid ParseVectorDataArrat token invalid"); - - if (tok.empty()) { - print_error("unexpected empty element: " + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'i') { - print_error("expected (u)int array (binary)" + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * 4); - - out.reserve(count); - - const int32_t *ip = reinterpret_cast<const int32_t *>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - int32_t val = *ip; - if (val < 0) { - print_error("encountered negative integer index (binary)"); - } - - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - const int ival = ParseTokenAsInt(*it++); - if (ival < 0) { - print_error("encountered negative integer index"); - } - out.push_back(static_cast<unsigned int>(ival)); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of uint64_ts -void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr el) { - out.resize(0); - - const TokenList &tok = el->Tokens(); - TokenPtr token = el->KeyToken(); - ERR_FAIL_COND(!token); - - if (tok.empty()) { - print_error("unexpected empty element " + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'l') { - print_error("expected long array (binary): " + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * 8); - - out.reserve(count); - - const uint64_t *ip = reinterpret_cast<const uint64_t *>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - uint64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - const uint64_t ival = ParseTokenAsID(*it++); - - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of int64_ts -void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el) { - out.resize(0); - const TokenList &tok = el->Tokens(); - TokenPtr token = el->KeyToken(); - ERR_FAIL_COND(!token); - if (tok.empty()) { - print_error("unexpected empty element: " + String(token->StringContents().c_str())); - } - - if (tok[0]->IsBinary()) { - const char *data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'l') { - print_error("expected long array (binary) " + String(token->StringContents().c_str())); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - //ai_assert(data == end); - //ai_assert(buff.size() == count * 8); - - out.reserve(count); - - const int64_t *ip = reinterpret_cast<const int64_t *>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - int64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const ScopePtr scope = GetRequiredScope(el); - const ElementPtr a = GetRequiredElement(scope, "a", el); - - for (TokenList::const_iterator it = a->Tokens().begin(), end = a->Tokens().end(); it != end;) { - const int64_t val = ParseTokenAsInt64(*it++); - out.push_back(val); - } -} - -// ------------------------------------------------------------------------------------------------ -Transform3D ReadMatrix(const ElementPtr element) { - std::vector<float> values; - ParseVectorDataArray(values, element); - - if (values.size() != 16) { - print_error("expected 16 matrix elements"); - } - - // clean values to prevent any IBM damage on inverse() / affine_inverse() - for (float &value : values) { - if (::Math::is_zero_approx(value)) { - value = 0; - } - } - - Transform3D xform; - Basis basis; - - basis.set( - Vector3(values[0], values[1], values[2]), - Vector3(values[4], values[5], values[6]), - Vector3(values[8], values[9], values[10])); - - xform.basis = basis; - xform.origin = Vector3(values[12], values[13], values[14]); - // determine if we need to think about this with dynamic rotation order? - // for example: - // xform.basis = z_axis * y_axis * x_axis; - //xform.basis.transpose(); - - print_verbose("xform verbose basis: " + (xform.basis.get_euler() * (180 / Math_PI)) + " xform origin:" + xform.origin); - - return xform; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsString() with print_error handling -std::string ParseTokenAsString(const TokenPtr t) { - ERR_FAIL_COND_V(!t, ""); - const char *err; - const std::string &i = ParseTokenAsString(t, err); - if (err) { - print_error(String(err) + ", " + String(t->StringContents().c_str())); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// 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*/) { - const ElementPtr el = sc->GetElement(index); - TokenPtr token = el->KeyToken(); - ERR_FAIL_COND_V(!token, nullptr); - if (!el) { - print_error("did not find required element \"" + String(index.c_str()) + "\" " + String(token->StringContents().c_str())); - } - return el; -} - -bool HasElement(const ScopePtr sc, const std::string &index) { - const ElementPtr el = sc->GetElement(index); - if (nullptr == el) { - return false; - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -// 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 /*= nullptr*/) { - const ElementPtr el = sc->GetElement(index); - return el; -} - -// ------------------------------------------------------------------------------------------------ -// extract required compound scope -ScopePtr GetRequiredScope(const ElementPtr el) { - if (el) { - ScopePtr s = el->Compound(); - TokenPtr token = el->KeyToken(); - ERR_FAIL_COND_V(!token, nullptr); - if (s) { - return s; - } - - ERR_FAIL_V_MSG(nullptr, "expected compound scope " + String(token->StringContents().c_str())); - } - - ERR_FAIL_V_MSG(nullptr, "Invalid element supplied to parser"); -} - -// ------------------------------------------------------------------------------------------------ -// 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) { - const TokenList &x = el->Tokens(); - TokenPtr token = el->KeyToken(); - - ERR_FAIL_COND_V(!token, nullptr); - - if (index >= x.size()) { - ERR_FAIL_V_MSG(nullptr, "missing token at index: " + itos(index) + " " + String(token->StringContents().c_str())); - } - - return x[index]; - } - - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsDim() with print_error handling -size_t ParseTokenAsDim(const TokenPtr t) { - const char *err; - const size_t i = ParseTokenAsDim(t, err); - if (err) { - print_error(String(err) + " " + String(t->StringContents().c_str())); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsFloat() with print_error handling -float ParseTokenAsFloat(const TokenPtr t) { - const char *err; - const float i = ParseTokenAsFloat(t, err); - if (err) { - print_error(String(err) + " " + String(t->StringContents().c_str())); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsInt() with print_error handling -int ParseTokenAsInt(const TokenPtr t) { - const char *err; - const int i = ParseTokenAsInt(t, err); - if (err) { - print_error(String(err) + " " + String(t->StringContents().c_str())); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsInt64() with print_error handling -int64_t ParseTokenAsInt64(const TokenPtr t) { - const char *err; - const int64_t i = ParseTokenAsInt64(t, err); - if (err) { - print_error(String(err) + " " + String(t->StringContents().c_str())); - } - return i; -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h deleted file mode 100644 index 27db18bf8a..0000000000 --- a/modules/fbx/fbx_parser/FBXParser.h +++ /dev/null @@ -1,270 +0,0 @@ -/*************************************************************************/ -/* FBXParser.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXParser.h - * @brief FBX parsing code - */ -#ifndef FBX_PARSER_H -#define FBX_PARSER_H - -#include <stdint.h> -#include <map> -#include <memory> - -#include "core/math/color.h" -#include "core/math/transform_3d.h" -#include "core/math/vector2.h" -#include "core/math/vector3.h" - -#include "FBXTokenizer.h" - -namespace FBXDocParser { - -class Scope; -class Parser; -class Element; - -typedef Element *ElementPtr; -typedef Scope *ScopePtr; - -typedef std::vector<ScopePtr> ScopeList; -typedef std::multimap<std::string, ElementPtr> ElementMap; -typedef std::pair<ElementMap::const_iterator, ElementMap::const_iterator> ElementCollection; - -#define new_Scope new Scope -#define new_Element new Element - -/** FBX data entity that consists of a key:value tuple. - * - * Example: - * @verbatim - * AnimationCurve: 23, "AnimCurve::", "" { - * [..] - * } - * @endverbatim - * - * As can be seen in this sample, elements can contain nested #Scope - * as their trailing member. **/ -class Element { -public: - Element(TokenPtr key_token, Parser &parser); - ~Element(); - - ScopePtr Compound() const { - return compound; - } - - TokenPtr KeyToken() const { - return key_token; - } - - const TokenList &Tokens() const { - return tokens; - } - -private: - TokenList tokens; - ScopePtr compound = nullptr; - std::vector<ScopePtr> compound_scope; - TokenPtr key_token = nullptr; -}; - -/** FBX data entity that consists of a 'scope', a collection - * of not necessarily unique #Element instances. - * - * Example: - * @verbatim - * GlobalSettings: { - * Version: 1000 - * Properties70: - * [...] - * } - * @endverbatim */ -class Scope { -public: - Scope(Parser &parser, bool topLevel = false); - ~Scope(); - - ElementPtr GetElement(const std::string &index) const { - ElementMap::const_iterator it = elements.find(index); - return it == elements.end() ? nullptr : (*it).second; - } - - ElementPtr FindElementCaseInsensitive(const std::string &elementName) const { - for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) { - if (element->first.compare(elementName)) { - return element->second; - } - } - - // nothing to reference / expired. - return nullptr; - } - - ElementCollection GetCollection(const std::string &index) const { - return elements.equal_range(index); - } - - const ElementMap &Elements() const { - return elements; - } - -private: - ElementMap elements; -}; - -/** FBX parsing class, takes a list of input tokens and generates a hierarchy - * of nested #Scope instances, representing the fbx DOM.*/ -class Parser { -public: - /** Parse given a token list. Does not take ownership of the tokens - - * the objects must persist during the entire parser lifetime */ - Parser(const TokenList &tokens, bool is_binary); - ~Parser(); - - ScopePtr GetRootScope() const { - return root; - } - - bool IsBinary() const { - return is_binary; - } - - bool IsCorrupt() const { - return corrupt; - } - -private: - friend class Scope; - friend class Element; - - TokenPtr AdvanceToNextToken(); - TokenPtr LastToken() const; - TokenPtr CurrentToken() const; - -private: - bool corrupt = false; - ScopeList scopes; - const TokenList &tokens; - - TokenPtr last = nullptr, current = nullptr; - TokenList::const_iterator cursor; - ScopePtr root = nullptr; - - const bool is_binary; -}; - -/* token parsing - this happens when building the DOM out of the parse-tree*/ -uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out); -size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out); -float ParseTokenAsFloat(const TokenPtr t, const char *&err_out); -int ParseTokenAsInt(const TokenPtr t, const char *&err_out); -int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out); -std::string ParseTokenAsString(const TokenPtr t, const char *&err_out); - -/* wrapper around ParseTokenAsXXX() with DOMError handling */ -uint64_t ParseTokenAsID(const TokenPtr t); -size_t ParseTokenAsDim(const TokenPtr t); -float ParseTokenAsFloat(const TokenPtr t); -int ParseTokenAsInt(const TokenPtr t); -int64_t ParseTokenAsInt64(const TokenPtr t); -std::string ParseTokenAsString(const TokenPtr t); - -/* read data arrays */ -void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el); -void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr ep); -void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el); -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); -// get token at a particular index -TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index); - -// ------------------------------------------------------------------------------------------------ -// read a 4x4 matrix from an array of 16 floats -Transform3D ReadMatrix(const ElementPtr element); -} // namespace FBXDocParser - -#endif // FBX_PARSER_H diff --git a/modules/fbx/fbx_parser/FBXPose.cpp b/modules/fbx/fbx_parser/FBXPose.cpp deleted file mode 100644 index 6d80b85e38..0000000000 --- a/modules/fbx/fbx_parser/FBXPose.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*************************************************************************/ -/* FBXPose.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXNoteAttribute.cpp - * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation - */ - -#include "FBXDocument.h" -#include "FBXParser.h" -#include <iostream> - -namespace FBXDocParser { - -class FbxPoseNode; -// ------------------------------------------------------------------------------------------------ -FbxPose::FbxPose(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)); - - const ElementCollection &PoseNodes = sc->GetCollection("PoseNode"); - for (ElementMap::const_iterator it = PoseNodes.first; it != PoseNodes.second; ++it) { - std::string entry_name = (*it).first; - ElementPtr some_element = (*it).second; - FbxPoseNode *pose_node = new FbxPoseNode(some_element, doc, entry_name); - pose_nodes.push_back(pose_node); - } -} - -// ------------------------------------------------------------------------------------------------ -FbxPose::~FbxPose() { - pose_nodes.clear(); - // empty -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp deleted file mode 100644 index b8c0f685ac..0000000000 --- a/modules/fbx/fbx_parser/FBXProperties.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/*************************************************************************/ -/* FBXProperties.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXProperties.cpp - * @brief Implementation of the FBX dynamic properties system - */ - -#include "FBXProperties.h" -#include "FBXDocumentUtil.h" -#include "FBXParser.h" -#include "FBXTokenizer.h" - -namespace FBXDocParser { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Property::Property() { -} - -// ------------------------------------------------------------------------------------------------ -Property::~Property() { -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -// 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"); - - const TokenList &tok = element->Tokens(); - //ai_assert(tok.size() >= 5); - - const std::string &s = ParseTokenAsString(tok[1]); - const char *const cs = s.c_str(); - if (!strcmp(cs, "KString")) { - return new TypedProperty<std::string>(ParseTokenAsString(tok[4])); - } else if (!strcmp(cs, "bool") || !strcmp(cs, "Bool")) { - return new TypedProperty<bool>(ParseTokenAsInt(tok[4]) != 0); - } else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) { - return new TypedProperty<int>(ParseTokenAsInt(tok[4])); - } else if (!strcmp(cs, "ULongLong")) { - return new TypedProperty<uint64_t>(ParseTokenAsID(tok[4])); - } else if (!strcmp(cs, "KTime")) { - return new TypedProperty<int64_t>(ParseTokenAsInt64(tok[4])); - } else if (!strcmp(cs, "Vector3D") || - !strcmp(cs, "ColorRGB") || - !strcmp(cs, "Vector") || - !strcmp(cs, "Color") || - !strcmp(cs, "Lcl Translation") || - !strcmp(cs, "Lcl Rotation") || - !strcmp(cs, "Lcl Scaling")) { - return new TypedProperty<Vector3>(Vector3( - ParseTokenAsFloat(tok[4]), - ParseTokenAsFloat(tok[5]), - ParseTokenAsFloat(tok[6]))); - } else if (!strcmp(cs, "double") || !strcmp(cs, "Number") || !strcmp(cs, "Float") || !strcmp(cs, "float") || !strcmp(cs, "FieldOfView") || !strcmp(cs, "UnitScaleFactor")) { - return new TypedProperty<float>(ParseTokenAsFloat(tok[4])); - } - - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -// peek into an element and check if it contains a FBX property, if so return its name. -std::string PeekPropertyName(const Element &element) { - //ai_assert(element.KeyToken().StringContents() == "P"); - const TokenList &tok = element.Tokens(); - if (tok.size() < 4) { - return ""; - } - - return ParseTokenAsString(tok[0]); -} -} // namespace - -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable() : - element(nullptr) { -} - -// Is used when dealing with FBX Objects not metadata. -PropertyTable::PropertyTable(const ElementPtr element) : - element(element) { - Setup(element); -} - -// ------------------------------------------------------------------------------------------------ -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); - continue; - } - - const std::string &name = PeekPropertyName(*v.second); - if (!name.length()) { - DOMWarning("could not read property name", v.second); - continue; - } - - LazyPropertyMap::const_iterator it = lazyProps.find(name); - if (it != lazyProps.end()) { - DOMWarning("duplicate property name, will hide previous value: " + name, v.second); - continue; - } - - // since the above checks for duplicates we can be sure to insert the only match here. - lazyProps[name] = v.second; - } -} - -// ------------------------------------------------------------------------------------------------ -PropertyPtr PropertyTable::Get(const std::string &name) const { - PropertyMap::const_iterator it = props.find(name); - if (it == props.end()) { - // hasn't been parsed yet? - LazyPropertyMap::const_iterator lit = lazyProps.find(name); - if (lit != lazyProps.end()) { - props[name] = ReadTypedProperty(lit->second); - it = props.find(name); - - //ai_assert(it != props.end()); - } - - if (it == props.end()) { - // check property template - return nullptr; - } - } - - return (*it).second; -} - -DirectPropertyMap PropertyTable::GetUnparsedProperties() const { - DirectPropertyMap result; - - // 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)) { - continue; - } - - // Read the element's value. - // Wrap the naked pointer (since the call site is required to acquire ownership) - // std::unique_ptr from C++11 would be preferred both as a wrapper and a return value. - Property *prop = ReadTypedProperty(element.second); - - // Element could not be read. Skip it. - if (!prop) { - continue; - } - - // Add to result - result[element.first] = prop; - } - - return result; -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h deleted file mode 100644 index bfd27ac94e..0000000000 --- a/modules/fbx/fbx_parser/FBXProperties.h +++ /dev/null @@ -1,212 +0,0 @@ -/*************************************************************************/ -/* FBXProperties.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXProperties.h - * @brief FBX dynamic properties - */ -#ifndef FBX_PROPERTIES_H -#define FBX_PROPERTIES_H - -#include "FBXParser.h" -#include <map> -#include <memory> -#include <string> -#include <vector> - -namespace FBXDocParser { - -// Forward declarations -class Element; - -/** Represents a dynamic property. Type info added by deriving classes, - * see #TypedProperty. - Example: - @verbatim - P: "ShininessExponent", "double", "Number", "",0.5 - @endvebatim -*/ -class Property { -protected: - Property(); - -public: - virtual ~Property(); - -public: - template <typename T> - const T *As() const { - return dynamic_cast<const T *>(this); - } -}; - -template <typename T> -class TypedProperty : public Property { -public: - explicit TypedProperty(const T &value) : - value(value) { - // empty - } - - const T &Value() const { - return value; - } - -private: - T value; -}; - -#define new_Property new Property -typedef Property *PropertyPtr; -typedef std::map<std::string, PropertyPtr> DirectPropertyMap; -typedef std::map<std::string, PropertyPtr> PropertyMap; -typedef std::map<std::string, ElementPtr> LazyPropertyMap; - -/** - * Represents a property table as can be found in the newer FBX files (Properties60, Properties70) - */ -class PropertyTable { -public: - // in-memory property table with no source element - 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() { - return element; - } - - PropertyMap &GetProperties() { - return props; - } - - const LazyPropertyMap &GetLazyProperties() { - return lazyProps; - } - - DirectPropertyMap GetUnparsedProperties() const; - -private: - LazyPropertyMap lazyProps; - mutable PropertyMap props; - ElementPtr element = nullptr; -}; - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline T PropertyGet(const PropertyTable *in, const std::string &name, const T &defaultValue) { - PropertyPtr prop = in->Get(name); - if (nullptr == prop) { - return defaultValue; - } - - // strong typing, no need to be lenient - const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>(); - if (nullptr == tprop) { - return defaultValue; - } - - return tprop->Value(); -} - -// ------------------------------------------------------------------------------------------------ -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 (nullptr == in) { - result = false; - return T(); - } - prop = in->Get(name); - if (nullptr == prop) { - result = false; - return T(); - } - } - - // strong typing, no need to be lenient - const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>(); - if (nullptr == tprop) { - result = false; - return T(); - } - - result = true; - return tprop->Value(); -} -} // namespace FBXDocParser - -#endif // FBX_PROPERTIES_H diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp deleted file mode 100644 index 81c5b128e8..0000000000 --- a/modules/fbx/fbx_parser/FBXTokenizer.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/*************************************************************************/ -/* FBXTokenizer.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXTokenizer.cpp - * @brief Implementation of the FBX broadphase lexer - */ - -// tab width for logging columns -#define ASSIMP_FBX_TAB_WIDTH 4 - -#include "FBXTokenizer.h" -#include "core/string/print_string.h" - -namespace FBXDocParser { - -// ------------------------------------------------------------------------------------------------ -Token::Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column) : - sbegin(p_sbegin), - send(p_send), - type(p_type), - line(p_line), - column(p_column) { -#ifdef DEBUG_ENABLED - contents = std::string(sbegin, static_cast<size_t>(send - sbegin)); -#endif -} - -// ------------------------------------------------------------------------------------------------ -Token::~Token() { -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -void TokenizeError(const std::string &message, unsigned int line, unsigned int column) { - print_error("[FBX-Tokenize]" + String(message.c_str()) + " " + itos(line) + ":" + itos(column)); -} - -// process a potential data token up to 'cur', adding it to 'output_tokens'. -// ------------------------------------------------------------------------------------------------ -void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *&end, - unsigned int line, - unsigned int column, - TokenType type = TokenType_DATA, - bool must_have_token = false) { - if (start && end) { - // sanity check: - // tokens should have no whitespace outside quoted text and [start,end] should - // properly delimit the valid range. - bool in_double_quotes = false; - for (const char *c = start; c != end + 1; ++c) { - if (*c == '\"') { - in_double_quotes = !in_double_quotes; - } - - if (!in_double_quotes && IsSpaceOrNewLine(*c)) { - TokenizeError("unexpected whitespace in token", line, column); - } - } - - if (in_double_quotes) { - TokenizeError("non-terminated double quotes", line, column); - } - - output_tokens.push_back(new_Token(start, end + 1, type, line, column)); - } else if (must_have_token) { - TokenizeError("unexpected character, expected data token", line, column); - } - - start = end = nullptr; -} -} // namespace - -// ------------------------------------------------------------------------------------------------ -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; - - bool comment = false; - bool in_double_quotes = false; - bool pending_data_token = false; - - const char *token_begin = nullptr, *token_end = nullptr; - - // input (starting string), *cur the current string, column += - // modified to fix strlen() and stop buffer overflow - for (size_t x = 0; x < length; x++) { - const char c = input[x]; - const char *cur = &input[x]; - column += (c == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1); - - if (IsLineEnd(c)) { - comment = false; - - column = 0; - ++line; - } - - if (comment) { - continue; - } - - if (in_double_quotes) { - if (c == '\"') { - in_double_quotes = false; - token_end = cur; - - ProcessDataToken(output_tokens, token_begin, token_end, line, column); - pending_data_token = false; - } - continue; - } - - switch (c) { - case '\"': - if (token_begin) { - TokenizeError("unexpected double-quote", line, column); - corrupt = true; - return; - } - token_begin = cur; - in_double_quotes = true; - continue; - - case ';': - ProcessDataToken(output_tokens, token_begin, token_end, line, column); - comment = true; - continue; - - case '{': - ProcessDataToken(output_tokens, token_begin, token_end, line, column); - output_tokens.push_back(new_Token(cur, cur + 1, TokenType_OPEN_BRACKET, line, column)); - continue; - - case '}': - ProcessDataToken(output_tokens, token_begin, token_end, line, column); - output_tokens.push_back(new_Token(cur, cur + 1, TokenType_CLOSE_BRACKET, line, column)); - continue; - - case ',': - if (pending_data_token) { - ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_DATA, true); - } - output_tokens.push_back(new_Token(cur, cur + 1, TokenType_COMMA, line, column)); - continue; - - case ':': - if (pending_data_token) { - ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_KEY, true); - } else { - TokenizeError("unexpected colon", line, column); - } - continue; - } - - if (IsSpaceOrNewLine(c)) { - if (token_begin) { - // peek ahead and check if the next token is a colon in which - // case this counts as KEY token. - TokenType type = TokenType_DATA; - for (const char *peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) { - if (*peek == ':') { - type = TokenType_KEY; - cur = peek; - break; - } - } - - ProcessDataToken(output_tokens, token_begin, token_end, line, column, type); - } - - pending_data_token = false; - } else { - token_end = cur; - if (!token_begin) { - token_begin = cur; - } - - pending_data_token = true; - } - } -} -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h deleted file mode 100644 index 184d0fd894..0000000000 --- a/modules/fbx/fbx_parser/FBXTokenizer.h +++ /dev/null @@ -1,203 +0,0 @@ -/*************************************************************************/ -/* FBXTokenizer.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXTokenizer.h - * @brief FBX lexer - */ -#ifndef FBX_TOKENIZER_H -#define FBX_TOKENIZER_H - -#include "FBXParseTools.h" -#include "core/string/ustring.h" -#include <iostream> -#include <memory> -#include <string> -#include <vector> - -namespace FBXDocParser { -/** Rough classification for text FBX tokens used for constructing the - * basic scope hierarchy. */ -enum TokenType { - // { - TokenType_OPEN_BRACKET = 0, - - // } - TokenType_CLOSE_BRACKET, - - // '"blablubb"', '2', '*14' - very general token class, - // further processing happens at a later stage. - TokenType_DATA, - - // - TokenType_BINARY_DATA, - - // , - TokenType_COMMA, - - // blubb: - TokenType_KEY -}; - -/** Represents a single token in a FBX file. Tokens are - * classified by the #TokenType enumerated types. - * - * Offers iterator protocol. Tokens are immutable. */ -class Token { -private: - static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1); - -public: - /** construct a textual token */ - Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column); - - /** construct a binary token */ - Token(const char *p_sbegin, const char *p_send, TokenType p_type, size_t p_offset); - ~Token(); - -public: - std::string StringContents() const { - return std::string(begin(), end()); - } - - bool IsBinary() const { - return column == BINARY_MARKER; - } - - const char *begin() const { - return sbegin; - } - - const char *end() const { - return send; - } - - TokenType Type() const { - return type; - } - - size_t Offset() const { - return offset; - } - - unsigned int Line() const { - return static_cast<unsigned int>(line); - } - - unsigned int Column() const { - return column; - } - -private: -#ifdef DEBUG_ENABLED - // full string copy for the sole purpose that it nicely appears - // in msvc's debugger window. - std::string contents; -#endif - - const char *sbegin = nullptr; - const char *send = nullptr; - const TokenType type; - - union { - size_t line; - size_t offset; - }; - const unsigned int column = 0; -}; - -// Fixed leak by using shared_ptr for tokens -typedef Token *TokenPtr; -typedef std::vector<TokenPtr> TokenList; - -#define new_Token new Token - -/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens. - * - * Skips over comments and generates line and column numbers. - * - * @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, bool &corrupt); - -/** Tokenizer function for binary FBX files. - * - * Emits a token list suitable for direct parsing. - * - * @param output_tokens Receives a list of all tokens in the input data. - * @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, bool &corrupt); -} // namespace FBXDocParser - -#endif // FBX_TOKENIZER_H diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp deleted file mode 100644 index df46bd85c7..0000000000 --- a/modules/fbx/fbx_parser/FBXUtil.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/*************************************************************************/ -/* FBXUtil.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXUtil.cpp - * @brief Implementation of internal FBX utility functions - */ - -#include "FBXUtil.h" -#include "FBXTokenizer.h" -#include <cstring> -#include <string> - -namespace FBXDocParser { -namespace Util { - -// ------------------------------------------------------------------------------------------------ -const char *TokenTypeString(TokenType t) { - switch (t) { - case TokenType_OPEN_BRACKET: - return "TOK_OPEN_BRACKET"; - - case TokenType_CLOSE_BRACKET: - return "TOK_CLOSE_BRACKET"; - - case TokenType_DATA: - return "TOK_DATA"; - - case TokenType_COMMA: - return "TOK_COMMA"; - - case TokenType_KEY: - return "TOK_KEY"; - - case TokenType_BINARY_DATA: - return "TOK_BINARY_DATA"; - } - - //ai_assert(false); - return ""; -} - -// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; -static const uint8_t base64DecodeTable[128] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, - 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 -}; - -uint8_t DecodeBase64(char ch) { - const uint8_t idx = static_cast<uint8_t>(ch); - if (idx > 127) { - return 255; - } - return base64DecodeTable[idx]; -} - -size_t ComputeDecodedSizeBase64(const char *in, size_t inLength) { - if (inLength < 2) { - return 0; - } - const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '='); - const size_t full_length = (inLength * 3) >> 2; // div by 4 - if (full_length < equals) { - return 0; - } - return full_length - equals; -} - -size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength) { - if (maxOutLength == 0 || inLength < 2) { - return 0; - } - const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '='); - size_t dst_offset = 0; - int val = 0, valb = -8; - for (size_t src_offset = 0; src_offset < realLength; ++src_offset) { - const uint8_t table_value = Util::DecodeBase64(in[src_offset]); - if (table_value == 255) { - return 0; - } - val = (val << 6) + table_value; - valb += 6; - if (valb >= 0) { - out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF); - valb -= 8; - val &= 0xFFF; - } - } - return dst_offset; -} - -static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -char EncodeBase64(char byte) { - return to_base64_string[(size_t)byte]; -} - -/** Encodes a block of 4 bytes to base64 encoding - * @param bytes Bytes to encode. - * @param out_string String to write encoded values to. - * @param string_pos Position in out_string. - */ -void EncodeByteBlock(const char *bytes, std::string &out_string, size_t string_pos) { - char b0 = (bytes[0] & 0xFC) >> 2; - char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4); - char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6); - char b3 = (bytes[2] & 0x3F); - - out_string[string_pos + 0] = EncodeBase64(b0); - out_string[string_pos + 1] = EncodeBase64(b1); - out_string[string_pos + 2] = EncodeBase64(b2); - out_string[string_pos + 3] = EncodeBase64(b3); -} - -std::string EncodeBase64(const char *data, size_t length) { - // calculate extra bytes needed to get a multiple of 3 - size_t extraBytes = 3 - length % 3; - - // number of base64 bytes - size_t encodedBytes = 4 * (length + extraBytes) / 3; - - std::string encoded_string(encodedBytes, '='); - - // read blocks of 3 bytes - for (size_t ib3 = 0; ib3 < length / 3; ib3++) { - const size_t iByte = ib3 * 3; - const size_t iEncodedByte = ib3 * 4; - const char *currData = &data[iByte]; - - EncodeByteBlock(currData, encoded_string, iEncodedByte); - } - - // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed) - if (extraBytes > 0) { - char finalBytes[4] = { 0, 0, 0, 0 }; - memcpy(&finalBytes[0], &data[length - length % 3], length % 3); - - const size_t iEncodedByte = encodedBytes - 4; - EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); - - // add '=' at the end - for (size_t i = 0; i < 4 * extraBytes / 3; i++) { - encoded_string[encodedBytes - i - 1] = '='; - } - } - return encoded_string; -} -} // namespace Util -} // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXUtil.h b/modules/fbx/fbx_parser/FBXUtil.h deleted file mode 100644 index dab2a4201e..0000000000 --- a/modules/fbx/fbx_parser/FBXUtil.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************/ -/* FBXUtil.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. */ -/*************************************************************************/ - -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXUtil.h - * @brief FBX utility functions for internal use - */ -#ifndef FBX_UTIL_H -#define FBX_UTIL_H - -#include "FBXTokenizer.h" -#include <stdint.h> - -namespace FBXDocParser { - -namespace Util { - -/** Get a string representation for a #TokenType. */ -const char *TokenTypeString(TokenType t); - -/** Decode a single Base64-encoded character. - * - * @param ch Character to decode (from base64 to binary). - * @return decoded byte value*/ -uint8_t DecodeBase64(char ch); - -/** Compute decoded size of a Base64-encoded string - * - * @param in Characters to decode. - * @param inLength Number of characters to decode. - * @return size of the decoded data (number of bytes)*/ -size_t ComputeDecodedSizeBase64(const char *in, size_t inLength); - -/** Decode a Base64-encoded string - * - * @param in Characters to decode. - * @param inLength Number of characters to decode. - * @param out Pointer where we will store the decoded data. - * @param maxOutLength Size of output buffer. - * @return size of the decoded data (number of bytes)*/ -size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength); - -char EncodeBase64(char byte); - -/** Encode bytes in base64-encoding - * - * @param data Binary data to encode. - * @param inLength Number of bytes to encode. - * @return base64-encoded string*/ -std::string EncodeBase64(const char *data, size_t length); -} // namespace Util -} // namespace FBXDocParser - -#endif // FBX_UTIL_H diff --git a/modules/fbx/fbx_parser/LICENSE b/modules/fbx/fbx_parser/LICENSE deleted file mode 100644 index b42fc6efe6..0000000000 --- a/modules/fbx/fbx_parser/LICENSE +++ /dev/null @@ -1,39 +0,0 @@ -The files in this folder were originally from ASSIMP, but have been heavily modified to fix bugs and match coding -conventions of the Godot Engine project. We have kept a copy of the applicable licenses in the folder as required by -the license. - -Open Asset Import Library (assimp) - -Copyright (c) 2006-2020, assimp team -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp deleted file mode 100644 index bb95d120af..0000000000 --- a/modules/fbx/tools/import_utils.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/*************************************************************************/ -/* import_utils.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 "import_utils.h" - -Vector3 ImportUtils::deg2rad(const Vector3 &p_rotation) { - return p_rotation / 180.0 * Math_PI; -} - -Vector3 ImportUtils::rad2deg(const Vector3 &p_rotation) { - return p_rotation / Math_PI * 180.0; -} - -Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) { - Basis ret; - - // FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot - // by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf - switch (mode) { - case FBXDocParser::Model::RotOrder_EulerXYZ: - ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ); - break; - - case FBXDocParser::Model::RotOrder_EulerXZY: - ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY); - break; - - case FBXDocParser::Model::RotOrder_EulerYZX: - ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX); - break; - - case FBXDocParser::Model::RotOrder_EulerYXZ: - ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ); - break; - - case FBXDocParser::Model::RotOrder_EulerZXY: - ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY); - break; - - case FBXDocParser::Model::RotOrder_EulerZYX: - ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX); - break; - - case FBXDocParser::Model::RotOrder_SphericXYZ: - // TODO do this. - break; - - default: - // If you land here, Please integrate all enums. - CRASH_NOW_MSG("This is not unreachable."); - } - - return ret; -} - -Quaternion ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) { - return ImportUtils::EulerToBasis(mode, p_rotation); -} - -Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation) { - // FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot - // by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf - switch (mode) { - case FBXDocParser::Model::RotOrder_EulerXYZ: - return p_rotation.get_euler(Basis::EULER_ORDER_XYZ); - - case FBXDocParser::Model::RotOrder_EulerXZY: - return p_rotation.get_euler(Basis::EULER_ORDER_XZY); - - case FBXDocParser::Model::RotOrder_EulerYZX: - return p_rotation.get_euler(Basis::EULER_ORDER_YZX); - - case FBXDocParser::Model::RotOrder_EulerYXZ: - return p_rotation.get_euler(Basis::EULER_ORDER_YXZ); - - case FBXDocParser::Model::RotOrder_EulerZXY: - return p_rotation.get_euler(Basis::EULER_ORDER_ZXY); - - case FBXDocParser::Model::RotOrder_EulerZYX: - return p_rotation.get_euler(Basis::EULER_ORDER_ZYX); - - case FBXDocParser::Model::RotOrder_SphericXYZ: - // TODO - return Vector3(); - - default: - // If you land here, Please integrate all enums. - CRASH_NOW_MSG("This is not unreachable."); - return Vector3(); - } -} - -Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation) { - return BasisToEuler(mode, p_rotation); -} - -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 necessary"); - // Using long double to make sure that normal is computed for even really tiny objects. - typedef long double ldouble; - ldouble x = 0.0; - ldouble y = 0.0; - ldouble z = 0.0; - for (size_t i = 0; i < p_vertices.size(); i += 1) { - const Vector3 current = p_vertices[i]; - const Vector3 next = p_vertices[(i + 1) % p_vertices.size()]; - x += (ldouble(current.y) - ldouble(next.y)) * (ldouble(current.z) + ldouble(next.z)); - y += (ldouble(current.z) - ldouble(next.z)) * (ldouble(current.x) + ldouble(next.x)); - z += (ldouble(current.x) - ldouble(next.x)) * (ldouble(current.y) + ldouble(next.y)); - } - const ldouble l2 = x * x + y * y + z * z; - if (l2 == 0.0) { - return (p_vertices[0] - p_vertices[1]).normalized().cross((p_vertices[0] - p_vertices[2]).normalized()).normalized(); - } else { - const double l = Math::sqrt(double(l2)); - return Vector3(x / l, y / l, z / l); - } -} diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h deleted file mode 100644 index 88c71fb87e..0000000000 --- a/modules/fbx/tools/import_utils.h +++ /dev/null @@ -1,400 +0,0 @@ -/*************************************************************************/ -/* import_utils.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 IMPORT_UTILS_FBX_IMPORTER_H -#define IMPORT_UTILS_FBX_IMPORTER_H - -#include "core/io/image_loader.h" - -#include "data/import_state.h" -#include "fbx_parser/FBXDocument.h" - -#include <string> - -#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL - -/** - * Import Utils - * Conversion tools / glue code to convert from FBX to Godot - */ -class ImportUtils { -public: - /// Convert a vector from degrees to radians. - static Vector3 deg2rad(const Vector3 &p_rotation); - - /// Convert a vector from radians to degrees. - static Vector3 rad2deg(const Vector3 &p_rotation); - - /// Converts rotation order vector (in rad) to quaternion. - static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); - - /// Converts rotation order vector (in rad) to quaternion. - 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 Quaternion &p_rotation); - - static void debug_xform(String name, const Transform3D &t) { - print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI))); - } - - static String FBXNodeToName(const std::string &name) { - // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if - // this causes ambiguities, well possible between empty identifiers, - // such as "Model::" and ""). Make sure the behaviour is consistent - // across multiple calls to FixNodeName(). - - // We must remove this from the name - // Some bones have this - // SubDeformer:: - // Meshes, Joints have this, some other IK elements too. - // Model:: - - String node_name = String(name.c_str()); - - if (node_name.substr(0, 7) == "Model::") { - node_name = node_name.substr(7, node_name.length() - 7); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 13) == "SubDeformer::") { - node_name = node_name.substr(13, node_name.length() - 13); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 11) == "AnimStack::") { - node_name = node_name.substr(11, node_name.length() - 11); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 15) == "AnimCurveNode::") { - node_name = node_name.substr(15, node_name.length() - 15); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 11) == "AnimCurve::") { - node_name = node_name.substr(11, node_name.length() - 11); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 10) == "Geometry::") { - node_name = node_name.substr(10, node_name.length() - 10); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 10) == "Material::") { - node_name = node_name.substr(10, node_name.length() - 10); - return node_name.replace(":", ""); - } - - if (node_name.substr(0, 9) == "Texture::") { - node_name = node_name.substr(9, node_name.length() - 9); - return node_name.replace(":", ""); - } - - return node_name.replace(":", ""); - } - - static std::string FBXAnimMeshName(const std::string &name) { - if (name.length()) { - size_t indexOf = name.find_first_of("::"); - if (indexOf != std::string::npos && indexOf < name.size() - 2) { - return name.substr(indexOf + 2); - } - } - return name.length() ? name : "AnimMesh"; - } - - static Vector3 safe_import_vector3(const Vector3 &p_vec) { - Vector3 vector = p_vec; - if (Math::is_zero_approx(vector.x)) { - vector.x = 0; - } - - if (Math::is_zero_approx(vector.y)) { - vector.y = 0; - } - - if (Math::is_zero_approx(vector.z)) { - vector.z = 0; - } - return vector; - } - - static void debug_xform(String name, const Basis &t) { - //print_verbose(name + " rotation: " + (t.get_euler() * (180 / Math_PI))); - } - - static Vector3 FixAxisConversions(Vector3 input) { - return Vector3(input.x, input.y, input.z); - } - - static void AlignMeshAxes(std::vector<Vector3> &vertex_data) { - for (size_t x = 0; x < vertex_data.size(); x++) { - vertex_data[x] = FixAxisConversions(vertex_data[x]); - } - } - - struct AssetImportFbx { - enum ETimeMode { - TIME_MODE_DEFAULT = 0, - TIME_MODE_120 = 1, - TIME_MODE_100 = 2, - TIME_MODE_60 = 3, - TIME_MODE_50 = 4, - TIME_MODE_48 = 5, - TIME_MODE_30 = 6, - TIME_MODE_30_DROP = 7, - TIME_MODE_NTSC_DROP_FRAME = 8, - TIME_MODE_NTSC_FULL_FRAME = 9, - TIME_MODE_PAL = 10, - TIME_MODE_CINEMA = 11, - TIME_MODE_1000 = 12, - TIME_MODE_CINEMA_ND = 13, - TIME_MODE_CUSTOM = 14, - TIME_MODE_TIME_MODE_COUNT = 15 - }; - enum UpAxis { - UP_VECTOR_AXIS_X = 1, - UP_VECTOR_AXIS_Y = 2, - UP_VECTOR_AXIS_Z = 3 - }; - enum FrontAxis { - FRONT_PARITY_EVEN = 1, - FRONT_PARITY_ODD = 2, - }; - - enum CoordAxis { - COORD_RIGHT = 0, - COORD_LEFT = 1 - }; - }; - - /** Get fbx fps for time mode meta data - */ - static float get_fbx_fps(int32_t time_mode) { - switch (time_mode) { - case AssetImportFbx::TIME_MODE_DEFAULT: - return 24; - case AssetImportFbx::TIME_MODE_120: - return 120; - case AssetImportFbx::TIME_MODE_100: - return 100; - case AssetImportFbx::TIME_MODE_60: - return 60; - case AssetImportFbx::TIME_MODE_50: - return 50; - case AssetImportFbx::TIME_MODE_48: - return 48; - case AssetImportFbx::TIME_MODE_30: - return 30; - case AssetImportFbx::TIME_MODE_30_DROP: - return 30; - case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME: - return 29.9700262f; - case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME: - return 29.9700262f; - case AssetImportFbx::TIME_MODE_PAL: - return 25; - case AssetImportFbx::TIME_MODE_CINEMA: - return 24; - case AssetImportFbx::TIME_MODE_1000: - return 1000; - case AssetImportFbx::TIME_MODE_CINEMA_ND: - return 23.976f; - case AssetImportFbx::TIME_MODE_CUSTOM: - return -1; - } - return 0; - } - - static float get_fbx_fps(const FBXDocParser::FileGlobalSettings *FBXSettings) { - int time_mode = FBXSettings->TimeMode(); - - // get the animation FPS - float frames_per_second = get_fbx_fps(time_mode); - - // handle animation custom FPS time. - if (time_mode == ImportUtils::AssetImportFbx::TIME_MODE_CUSTOM) { - print_verbose("FBX Animation has custom FPS setting"); - frames_per_second = FBXSettings->CustomFrameRate(); - - // not our problem this is the modeller, we can print as an error so they can fix the source. - if (frames_per_second == 0) { - print_error("Custom animation time in file is set to 0 value, animation won't play, please edit your file to correct the FPS value"); - } - } - return frames_per_second; - } - - /** - * Find hardcoded textures from assimp which could be in many different directories - */ - - /** - * set_texture_mapping_mode - * Helper to check the mapping mode of the texture (repeat, clamp and mirror) - */ - // static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) { - // ERR_FAIL_COND(texture.is_null()); - // ERR_FAIL_COND(map_mode == nullptr); - // aiTextureMapMode tex_mode = map_mode[0]; - - // int32_t flags = Texture::FLAGS_DEFAULT; - // if (tex_mode == aiTextureMapMode_Wrap) { - // //Default - // } else if (tex_mode == aiTextureMapMode_Clamp) { - // flags = flags & ~Texture::FLAG_REPEAT; - // } else if (tex_mode == aiTextureMapMode_Mirror) { - // flags = flags | Texture::FLAG_MIRRORED_REPEAT; - // } - // texture->set_flags(flags); - // } - - /** - * Load or load from cache image :) - * We need to upgrade this in the later version :) should not be hard - */ - //static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path){ - // Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path); - - // // if our cache contains this image then don't bother - // if (match) { - // return match->get(); - // } - - // Vector<String> split_path = p_path.get_basename().split("*"); - // if (split_path.size() == 2) { - // size_t texture_idx = split_path[1].to_int(); - // ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>()); - // aiTexture *tex = p_scene->mTextures[texture_idx]; - // String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename); - // filename = filename.get_file(); - // print_verbose("Open Asset Import: Loading embedded texture " + filename); - // if (tex->mHeight == 0) { - // if (tex->CheckFormat("png")) { - // Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); - // ERR_FAIL_COND_V(img.is_null(), Ref<Image>()); - // state.path_to_image_cache.insert(p_path, img); - // return img; - // } else if (tex->CheckFormat("jpg")) { - // Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); - // ERR_FAIL_COND_V(img.is_null(), Ref<Image>()); - // state.path_to_image_cache.insert(p_path, img); - // return img; - // } else if (tex->CheckFormat("dds")) { - // ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented"); - // } - // } else { - // Ref<Image> img; - // img.instantiate(); - // PoolByteArray arr; - // uint32_t size = tex->mWidth * tex->mHeight; - // arr.resize(size); - // memcpy(arr.write().ptr(), tex->pcData, size); - // ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>()); - // //ARGB8888 to RGBA8888 - // for (int32_t i = 0; i < arr.size() / 4; i++) { - // arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0]; - // arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1]; - // arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2]; - // arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3]; - // } - // img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr); - // ERR_FAIL_COND_V(img.is_null(), Ref<Image>()); - // state.path_to_image_cache.insert(p_path, img); - // return img; - // } - // return Ref<Image>(); - // } else { - // Ref<Texture> texture = ResourceLoader::load(p_path); - // ERR_FAIL_COND_V(texture.is_null(), Ref<Image>()); - // 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; - // } - - // return Ref<Image>(); - //} - - // /* create texture from assimp data, if found in path */ - // static bool CreateAssimpTexture( - // AssimpImporter::ImportState &state, - // aiString texture_path, - // String &filename, - // String &path, - // AssimpImageData &image_state) { - // filename = get_raw_string_from_assimp(texture_path); - // path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); - // bool found = false; - // find_texture_path(state.path, path, found); - // if (found) { - // image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path); - // if (image_state.raw_image.is_valid()) { - // 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; - // } - // } - - // return false; - // } - // /** GetAssimpTexture - // * Designed to retrieve textures for you - // */ - // static bool GetAssimpTexture( - // AssimpImporter::ImportState &state, - // aiMaterial *ai_material, - // aiTextureType texture_type, - // String &filename, - // String &path, - // AssimpImageData &image_state) { - // aiString ai_filename = aiString(); - // 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); - // } - - // return false; - // } -}; - -// Apply the transforms so the basis will have scale 1. -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. -Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices); - -#endif // IMPORT_UTILS_FBX_IMPORTER_H diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h deleted file mode 100644 index 12d644ee94..0000000000 --- a/modules/fbx/tools/validation_tools.h +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************/ -/* validation_tools.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 FBX_VALIDATION_TOOLS_H -#define FBX_VALIDATION_TOOLS_H - -#ifdef TOOLS_ENABLED - -#include "core/io/file_access.h" -#include "core/string/print_string.h" -#include "core/templates/local_vector.h" -#include "core/templates/map.h" - -class ValidationTracker { -protected: - struct Entries { - Map<String, LocalVector<String>> validation_entries = Map<String, LocalVector<String>>(); - - // for printing our CSV to dump validation problems of files - // later we can make some agnostic tooling for this but this is fine for the time being. - void add_validation_error(String asset_path, String message); - void print_to_csv() { - print_verbose("Exporting assset validation log please wait"); - String massive_log_file; - - String csv_header = "file_path, error message, extra data\n"; - massive_log_file += csv_header; - - for (const KeyValue<String, LocalVector<String>> &element : validation_entries) { - for (unsigned int x = 0; x < element.value.size(); x++) { - const String &line_entry = element.key + ", " + element.value[x].c_escape() + "\n"; - massive_log_file += line_entry; - } - } - - String path = "asset_validation_errors.csv"; - Error err; - FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err); - if (!file || err) { - if (file) { - memdelete(file); - } - print_error("ValidationTracker Error - failed to create file - path: %s\n" + path); - return; - } - - file->store_string(massive_log_file); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - print_error("ValidationTracker Error - failed to write to file - path: %s\n" + path); - } - file->close(); - memdelete(file); - } - }; - // asset path, error messages - static Entries *entries_singleton; - -public: - static Entries *get_singleton() { - return entries_singleton; - } -}; - -#endif // TOOLS_ENABLED -#endif // FBX_VALIDATION_TOOLS_H diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index 476cb9cf2a..d23c4b637c 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -48,6 +48,7 @@ if env["builtin_freetype"]: "src/pshinter/pshinter.c", "src/psnames/psnames.c", "src/raster/raster.c", + "src/sdf/sdf.c", "src/smooth/smooth.c", "src/truetype/truetype.c", "src/type1/type1.c", @@ -56,6 +57,26 @@ if env["builtin_freetype"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + thirdparty_brotli_dir = "#thirdparty/brotli/" + thirdparty_brotli_sources = [ + "common/constants.c", + "common/context.c", + "common/dictionary.c", + "common/platform.c", + "common/shared_dictionary.c", + "common/transform.c", + "dec/bit_reader.c", + "dec/decode.c", + "dec/huffman.c", + "dec/state.c", + ] + thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] + env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) + + if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"): + env_freetype.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"]) + if env["platform"] == "uwp": # Include header for UWP to fix build issues env_freetype.Append(CCFLAGS=["/FI", '"modules/freetype/uwpdef.h"']) diff --git a/modules/freetype/register_types.cpp b/modules/freetype/register_types.cpp index e4e6a4c146..a5a60c0368 100644 --- a/modules/freetype/register_types.cpp +++ b/modules/freetype/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,6 +30,14 @@ #include "register_types.h" -void register_freetype_types() {} +void initialize_freetype_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} -void unregister_freetype_types() {} +void uninitialize_freetype_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/freetype/register_types.h b/modules/freetype/register_types.h index 7a4f64b54b..3399c0b3bc 100644 --- a/modules/freetype/register_types.h +++ b/modules/freetype/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef FREETYPE_REGISTER_TYPES_H #define FREETYPE_REGISTER_TYPES_H -void register_freetype_types(); -void unregister_freetype_types(); +#include "modules/register_module_types.h" + +void initialize_freetype_module(ModuleInitializationLevel p_level); +void uninitialize_freetype_module(ModuleInitializationLevel p_level); #endif // FREETYPE_REGISTER_TYPES_H diff --git a/modules/freetype/uwpdef.h b/modules/freetype/uwpdef.h index f829edea67..05aaae61b5 100644 --- a/modules/freetype/uwpdef.h +++ b/modules/freetype/uwpdef.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub deleted file mode 100644 index f7f21a433e..0000000000 --- a/modules/gdnative/SCsub +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_gdnative = env_modules.Clone() -env_gdnative.add_source_files(env.modules_sources, "gdnative.cpp") -env_gdnative.add_source_files(env.modules_sources, "register_types.cpp") -env_gdnative.add_source_files(env.modules_sources, "android/*.cpp") -env_gdnative.add_source_files(env.modules_sources, "gdnative/*.cpp") -env_gdnative.add_source_files(env.modules_sources, "nativescript/*.cpp") -env_gdnative.add_source_files(env.modules_sources, "gdnative_library_singleton_editor.cpp") -env_gdnative.add_source_files(env.modules_sources, "gdnative_library_editor_plugin.cpp") - -env_gdnative.Prepend(CPPPATH=["#modules/gdnative/include/"]) - -Export("env_gdnative") - -SConscript("pluginscript/SCsub") -SConscript("videodecoder/SCsub") - - -import gdnative_builders - -_, gensource = env_gdnative.CommandNoCache( - ["include/gdnative_api_struct.gen.h", "gdnative_api_struct.gen.cpp"], - "gdnative_api.json", - env.Run(gdnative_builders.build_gdnative_api_struct, "Generating GDNative API."), -) -env_gdnative.add_source_files(env.modules_sources, [gensource]) diff --git a/modules/gdnative/android/android_gdn.cpp b/modules/gdnative/android/android_gdn.cpp deleted file mode 100644 index fe3b3e7e12..0000000000 --- a/modules/gdnative/android/android_gdn.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/*************************************************************************/ -/* android_gdn.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 "modules/gdnative/gdnative.h" - -// Code by Paritosh97 with minor tweaks by Mux213 -// These entry points are only for the android platform and are simple stubs in all others. - -#ifdef __ANDROID__ -#include "platform/android/java_godot_wrapper.h" -#include "platform/android/os_android.h" -#include "platform/android/thread_jandroid.h" -#else -#define JNIEnv void -#define jobject void * -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -JNIEnv *GDAPI godot_android_get_env() { -#ifdef __ANDROID__ - return get_jni_env(); -#else - return nullptr; -#endif -} - -jobject GDAPI godot_android_get_activity() { -#ifdef __ANDROID__ - OS_Android *os_android = (OS_Android *)OS::get_singleton(); - return os_android->get_godot_java()->get_activity(); -#else - return nullptr; -#endif -} - -jobject GDAPI godot_android_get_surface() { -#ifdef __ANDROID__ - OS_Android *os_android = (OS_Android *)OS::get_singleton(); - return os_android->get_godot_java()->get_surface(); -#else - return nullptr; -#endif -} - -bool GDAPI godot_android_is_activity_resumed() { -#ifdef __ANDROID__ - OS_Android *os_android = (OS_Android *)OS::get_singleton(); - return os_android->get_godot_java()->is_activity_resumed(); -#else - return false; -#endif -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py deleted file mode 100644 index 026a84a70f..0000000000 --- a/modules/gdnative/config.py +++ /dev/null @@ -1,20 +0,0 @@ -def can_build(env, platform): - return True - - -def configure(env): - pass - - -def get_doc_classes(): - return [ - "GDNative", - "GDNativeLibrary", - "NativeScript", - "PluginScript", - "VideoStreamGDNative", - ] - - -def get_doc_path(): - return "doc_classes" diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml deleted file mode 100644 index 4bc149b119..0000000000 --- a/modules/gdnative/doc_classes/GDNative.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="GDNative" inherits="RefCounted" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <methods> - <method name="call_native"> - <return type="Variant" /> - <argument index="0" name="calling_type" type="StringName" /> - <argument index="1" name="procedure_name" type="StringName" /> - <argument index="2" name="arguments" type="Array" /> - <description> - </description> - </method> - <method name="initialize"> - <return type="bool" /> - <description> - </description> - </method> - <method name="terminate"> - <return type="bool" /> - <description> - </description> - </method> - </methods> - <members> - <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library"> - </member> - </members> -</class> diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml deleted file mode 100644 index 21df640ebc..0000000000 --- a/modules/gdnative/doc_classes/GDNativeLibrary.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="GDNativeLibrary" inherits="Resource" version="4.0"> - <brief_description> - An external library containing functions or script classes to use in Godot. - </brief_description> - <description> - A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as XRInterfaceGDNative. The library must be compiled for each platform and architecture that the project will run on. - </description> - <tutorials> - <link title="GDNative C example">$DOCS_URL/tutorials/scripting/gdnative/gdnative_c_example.html</link> - <link title="GDNative C++ example">$DOCS_URL/tutorials/scripting/gdnative/gdnative_cpp_example.html</link> - </tutorials> - <methods> - <method name="get_current_dependencies" qualifiers="const"> - <return type="PackedStringArray" /> - <description> - Returns paths to all dependency libraries for the current platform and architecture. - </description> - </method> - <method name="get_current_library_path" qualifiers="const"> - <return type="String" /> - <description> - Returns the path to the dynamic library file for the current platform and architecture. - </description> - </method> - </methods> - <members> - <member name="config_file" type="ConfigFile" setter="set_config_file" getter="get_config_file"> - This resource in INI-style [ConfigFile] format, as in [code].gdnlib[/code] files. - </member> - <member name="load_once" type="bool" setter="set_load_once" getter="should_load_once" default="true"> - If [code]true[/code], Godot loads only one copy of the library and each script that references the library will share static data like static or global variables. - If [code]false[/code], Godot loads a separate copy of the library into memory for each script that references it. - </member> - <member name="reloadable" type="bool" setter="set_reloadable" getter="is_reloadable" default="true"> - If [code]true[/code], the editor will temporarily unload the library whenever the user switches away from the editor window, allowing the user to recompile the library without restarting Godot. - [b]Note:[/b] If the library defines tool scripts that run inside the editor, [code]reloadable[/code] must be [code]false[/code]. Otherwise, the editor will attempt to unload the tool scripts while they're in use and crash. - </member> - <member name="singleton" type="bool" setter="set_singleton" getter="is_singleton" default="false"> - If [code]true[/code], Godot loads the library at startup rather than the first time a script uses the library, calling [code]{prefix}gdnative_singleton[/code] after initializing the library (where [code]{prefix}[/code] is the value of [member symbol_prefix]). The library remains loaded as long as Godot is running. - [b]Note:[/b] A singleton library cannot be [member reloadable]. - </member> - <member name="symbol_prefix" type="String" setter="set_symbol_prefix" getter="get_symbol_prefix" default=""godot_""> - The prefix this library's entry point functions begin with. For example, a GDNativeLibrary would declare its [code]gdnative_init[/code] function as [code]godot_gdnative_init[/code] by default. - On platforms that require statically linking libraries (currently only iOS), each library must have a different [code]symbol_prefix[/code]. - </member> - </members> -</class> diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml deleted file mode 100644 index 221374a7a4..0000000000 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ /dev/null @@ -1,55 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="NativeScript" inherits="Script" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_class_documentation" qualifiers="const"> - <return type="String" /> - <description> - Returns the documentation string that was previously set with [code]godot_nativescript_set_class_documentation[/code]. - </description> - </method> - <method name="get_method_documentation" qualifiers="const"> - <return type="String" /> - <argument index="0" name="method" type="StringName" /> - <description> - Returns the documentation string that was previously set with [code]godot_nativescript_set_method_documentation[/code]. - </description> - </method> - <method name="get_property_documentation" qualifiers="const"> - <return type="String" /> - <argument index="0" name="path" type="StringName" /> - <description> - Returns the documentation string that was previously set with [code]godot_nativescript_set_property_documentation[/code]. - </description> - </method> - <method name="get_signal_documentation" qualifiers="const"> - <return type="String" /> - <argument index="0" name="signal_name" type="StringName" /> - <description> - Returns the documentation string that was previously set with [code]godot_nativescript_set_signal_documentation[/code]. - </description> - </method> - <method name="new" qualifiers="vararg"> - <return type="Variant" /> - <description> - Constructs a new object of the base type with a script of this type already attached. - [b]Note:[/b] Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension. - </description> - </method> - </methods> - <members> - <member name="class_name" type="String" setter="set_class_name" getter="get_class_name" default=""""> - </member> - <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library"> - </member> - <member name="script_class_icon_path" type="String" setter="set_script_class_icon_path" getter="get_script_class_icon_path" default=""""> - </member> - <member name="script_class_name" type="String" setter="set_script_class_name" getter="get_script_class_name" default=""""> - </member> - </members> -</class> diff --git a/modules/gdnative/doc_classes/PluginScript.xml b/modules/gdnative/doc_classes/PluginScript.xml deleted file mode 100644 index ec80ade394..0000000000 --- a/modules/gdnative/doc_classes/PluginScript.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="PluginScript" inherits="Script" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <methods> - <method name="new" qualifiers="vararg"> - <return type="Variant" /> - <description> - Returns a new instance of the script. - </description> - </method> - </methods> -</class> diff --git a/modules/gdnative/doc_classes/VideoStreamGDNative.xml b/modules/gdnative/doc_classes/VideoStreamGDNative.xml deleted file mode 100644 index dc64e8fc18..0000000000 --- a/modules/gdnative/doc_classes/VideoStreamGDNative.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VideoStreamGDNative" inherits="VideoStream" version="4.0"> - <brief_description> - [VideoStream] resource for for video formats implemented via GDNative. - </brief_description> - <description> - [VideoStream] resource for for video formats implemented via GDNative. - It can be used via [url=https://github.com/KidRigger/godot-videodecoder]godot-videodecoder[/url] which uses the [url=https://ffmpeg.org]FFmpeg[/url] library. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_file"> - <return type="String" /> - <description> - Returns the video file handled by this [VideoStreamGDNative]. - </description> - </method> - <method name="set_file"> - <return type="void" /> - <argument index="0" name="file" type="String" /> - <description> - Sets the video file that this [VideoStreamGDNative] resource handles. The supported extensions depend on the GDNative plugins used to expose video formats. - </description> - </method> - </methods> -</class> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp deleted file mode 100644 index 9445fac1c6..0000000000 --- a/modules/gdnative/gdnative.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/*************************************************************************/ -/* gdnative.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 "gdnative.h" - -#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/os.h" - -#include "scene/main/scene_tree.h" - -static const String init_symbol = "gdnative_init"; -static const String terminate_symbol = "gdnative_terminate"; -static const String default_symbol_prefix = "godot_"; -static const bool default_singleton = false; -static const bool default_load_once = true; -static const bool default_reloadable = true; - -// Defined in gdnative_api_struct.gen.cpp -extern const godot_gdnative_core_api_struct api_struct; - -Map<String, Vector<Ref<GDNative>>> GDNativeLibrary::loaded_libraries; - -GDNativeLibrary::GDNativeLibrary() { - config_file.instantiate(); - - symbol_prefix = default_symbol_prefix; - load_once = default_load_once; - singleton = default_singleton; - reloadable = default_reloadable; -} - -GDNativeLibrary::~GDNativeLibrary() { -} - -bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_property) { - String name = p_name; - - if (name.begins_with("entry/")) { - String key = name.substr(6, name.length() - 6); - - config_file->set_value("entry", key, p_property); - - set_config_file(config_file); - - return true; - } - - if (name.begins_with("dependency/")) { - String key = name.substr(11, name.length() - 11); - - config_file->set_value("dependencies", key, p_property); - - set_config_file(config_file); - - return true; - } - - return false; -} - -bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_property) const { - String name = p_name; - - if (name.begins_with("entry/")) { - String key = name.substr(6, name.length() - 6); - - r_property = config_file->get_value("entry", key); - - return true; - } - - if (name.begins_with("dependency/")) { - String key = name.substr(11, name.length() - 11); - - r_property = config_file->get_value("dependencies", key); - - return true; - } - - return false; -} - -void GDNativeLibrary::reset_state() { - config_file.instantiate(); - current_library_path = ""; - current_dependencies.clear(); - symbol_prefix = default_symbol_prefix; - load_once = default_load_once; - singleton = default_singleton; - reloadable = default_reloadable; -} - -void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const { - // set entries - List<String> entry_key_list; - - if (config_file->has_section("entry")) { - config_file->get_section_keys("entry", &entry_key_list); - } - - for (const String &key : entry_key_list) { - PropertyInfo prop; - - prop.type = Variant::STRING; - prop.name = "entry/" + key; - - p_list->push_back(prop); - } - - // set dependencies - List<String> dependency_key_list; - - if (config_file->has_section("dependencies")) { - config_file->get_section_keys("dependencies", &dependency_key_list); - } - - for (const String &key : dependency_key_list) { - PropertyInfo prop; - - prop.type = Variant::STRING; - prop.name = "dependency/" + key; - - p_list->push_back(prop); - } -} - -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)); - set_reloadable(p_config_file->get_value("general", "reloadable", default_reloadable)); - - String entry_lib_path; - { - List<String> entry_keys; - - if (p_config_file->has_section("entry")) { - p_config_file->get_section_keys("entry", &entry_keys); - } - - for (const String &key : entry_keys) { - Vector<String> tags = key.split("."); - - bool skip = false; - for (int i = 0; i < tags.size(); i++) { - bool has_feature = OS::get_singleton()->has_feature(tags[i]); - - if (!has_feature) { - skip = true; - break; - } - } - - if (skip) { - continue; - } - - entry_lib_path = p_config_file->get_value("entry", key); - break; - } - } - - Vector<String> dependency_paths; - { - List<String> dependency_keys; - - if (p_config_file->has_section("dependencies")) { - p_config_file->get_section_keys("dependencies", &dependency_keys); - } - - for (const String &key : dependency_keys) { - Vector<String> tags = key.split("."); - - bool skip = false; - for (int i = 0; i < tags.size(); i++) { - bool has_feature = OS::get_singleton()->has_feature(tags[i]); - - if (!has_feature) { - skip = true; - break; - } - } - - if (skip) { - continue; - } - - dependency_paths = p_config_file->get_value("dependencies", key); - break; - } - } - - current_library_path = entry_lib_path; - current_dependencies = dependency_paths; -} - -void GDNativeLibrary::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_config_file"), &GDNativeLibrary::get_config_file); - ClassDB::bind_method(D_METHOD("set_config_file", "config_file"), &GDNativeLibrary::set_config_file); - - ClassDB::bind_method(D_METHOD("get_current_library_path"), &GDNativeLibrary::get_current_library_path); - ClassDB::bind_method(D_METHOD("get_current_dependencies"), &GDNativeLibrary::get_current_dependencies); - - ClassDB::bind_method(D_METHOD("should_load_once"), &GDNativeLibrary::should_load_once); - ClassDB::bind_method(D_METHOD("is_singleton"), &GDNativeLibrary::is_singleton); - ClassDB::bind_method(D_METHOD("get_symbol_prefix"), &GDNativeLibrary::get_symbol_prefix); - ClassDB::bind_method(D_METHOD("is_reloadable"), &GDNativeLibrary::is_reloadable); - - ClassDB::bind_method(D_METHOD("set_load_once", "load_once"), &GDNativeLibrary::set_load_once); - ClassDB::bind_method(D_METHOD("set_singleton", "singleton"), &GDNativeLibrary::set_singleton); - 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", 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"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "symbol_prefix"), "set_symbol_prefix", "get_symbol_prefix"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reloadable"), "set_reloadable", "is_reloadable"); -} - -GDNative::GDNative() { - native_handle = nullptr; - initialized = false; -} - -GDNative::~GDNative() { -} - -void GDNative::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_library", "library"), &GDNative::set_library); - ClassDB::bind_method(D_METHOD("get_library"), &GDNative::get_library); - - ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize); - ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate); - - ClassDB::bind_method(D_METHOD("call_native", "calling_type", "procedure_name", "arguments"), &GDNative::call_native); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); -} - -void GDNative::set_library(Ref<GDNativeLibrary> p_library) { - ERR_FAIL_COND_MSG(library.is_valid(), "Tried to change library of GDNative when it is already set."); - library = p_library; -} - -Ref<GDNativeLibrary> GDNative::get_library() const { - return library; -} - -extern "C" void _gdnative_report_version_mismatch(const godot_object *p_library, const char *p_ext, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have); -extern "C" void _gdnative_report_loading_error(const godot_object *p_library, const char *p_what); - -bool GDNative::initialize() { - if (library.is_null()) { - ERR_PRINT("No library set, can't initialize GDNative object"); - return false; - } - - String lib_path = library->get_current_library_path(); - if (lib_path.is_empty()) { - ERR_PRINT("No library set for this platform"); - return false; - } -#ifdef IPHONE_ENABLED - // On iOS we use static linking by default. - String path = ""; - - // On iOS dylibs is not allowed, but can be replaced with .framework or .xcframework. - // If they are used, we can run dlopen on them. - // They should be located under Frameworks directory, so we need to replace library path. - if (!lib_path.ends_with(".a")) { - path = ProjectSettings::get_singleton()->globalize_path(lib_path); - - if (!FileAccess::exists(path)) { - String lib_name = lib_path.get_basename().get_file(); - String framework_path_format = "Frameworks/$name.framework/$name"; - - Dictionary format_dict; - format_dict["name"] = lib_name; - String framework_path = framework_path_format.format(format_dict, "$_"); - - path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file(framework_path); - } - } -#elif defined(ANDROID_ENABLED) - // On Android dynamic libraries are located separately from resource assets, - // we should pass library name to dlopen(). The library name is flattened - // during export. - String path = lib_path.get_file(); -#elif defined(UWP_ENABLED) - // On UWP we use a relative path from the app - String path = lib_path.replace("res://", ""); -#elif defined(OSX_ENABLED) - // 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); - 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 - - if (library->should_load_once()) { - if (GDNativeLibrary::loaded_libraries.has(lib_path)) { - // already loaded. Don't load again. - // copy some of the stuff instead - this->native_handle = GDNativeLibrary::loaded_libraries[lib_path][0]->native_handle; - initialized = true; - return true; - } - } - - Error err = OS::get_singleton()->open_dynamic_library(path, native_handle, true); - if (err != OK) { - return false; - } - - void *library_init; - - // we cheat here a little bit. you saw nothing - initialized = true; - - err = get_symbol(library->get_symbol_prefix() + init_symbol, library_init, false); - - initialized = false; - - if (err || !library_init) { - OS::get_singleton()->close_dynamic_library(native_handle); - native_handle = nullptr; - ERR_PRINT("Failed to obtain " + library->get_symbol_prefix() + "gdnative_init symbol"); - return false; - } - - godot_gdnative_init_fn library_init_fpointer; - library_init_fpointer = (godot_gdnative_init_fn)library_init; - - static uint64_t core_api_hash = 0; - static uint64_t editor_api_hash = 0; - static uint64_t no_api_hash = 0; - - if (!(core_api_hash || editor_api_hash || no_api_hash)) { - core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); - editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); - no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); - } - - godot_gdnative_init_options options; - - options.api_struct = &api_struct; - options.in_editor = Engine::get_singleton()->is_editor_hint(); - options.core_api_hash = core_api_hash; - options.editor_api_hash = editor_api_hash; - options.no_api_hash = no_api_hash; - options.report_version_mismatch = &_gdnative_report_version_mismatch; - options.report_loading_error = &_gdnative_report_loading_error; - options.gd_native_library = (godot_object *)(get_library().ptr()); - options.active_library_path = (godot_string *)&path; - - library_init_fpointer(&options); - - initialized = true; - - if (library->should_load_once() && !GDNativeLibrary::loaded_libraries.has(lib_path)) { - Vector<Ref<GDNative>> gdnatives; - gdnatives.resize(1); - gdnatives.write[0] = Ref<GDNative>(this); - GDNativeLibrary::loaded_libraries.insert(lib_path, gdnatives); - } - - return true; -} - -bool GDNative::terminate() { - if (!initialized) { - ERR_PRINT("No valid library handle, can't terminate GDNative object"); - return false; - } - - if (library->should_load_once()) { - Vector<Ref<GDNative>> *gdnatives = &GDNativeLibrary::loaded_libraries[library->get_current_library_path()]; - if (gdnatives->size() > 1) { - // there are other GDNative's still using this library, so we actually don't terminate - gdnatives->erase(Ref<GDNative>(this)); - initialized = false; - return true; - } else if (gdnatives->size() == 1) { - // we're the last one, terminate! - gdnatives->clear(); - // whew this looks scary, but all it does is remove the entry completely - GDNativeLibrary::loaded_libraries.erase(GDNativeLibrary::loaded_libraries.find(library->get_current_library_path())); - } - } - - void *library_terminate; - Error error = get_symbol(library->get_symbol_prefix() + terminate_symbol, library_terminate); - if (error || !library_terminate) { - OS::get_singleton()->close_dynamic_library(native_handle); - native_handle = nullptr; - initialized = false; - return true; - } - - godot_gdnative_terminate_fn library_terminate_pointer; - library_terminate_pointer = (godot_gdnative_terminate_fn)library_terminate; - - godot_gdnative_terminate_options options; - options.in_editor = Engine::get_singleton()->is_editor_hint(); - - library_terminate_pointer(&options); - - initialized = false; - - // GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path); - - OS::get_singleton()->close_dynamic_library(native_handle); - native_handle = nullptr; - - return true; -} - -bool GDNative::is_initialized() const { - return initialized; -} - -void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, native_call_cb p_callback) { - native_calls.insert(p_call_type, p_callback); -} - -Vector<StringName> GDNativeCallRegistry::get_native_call_types() { - Vector<StringName> call_types; - call_types.resize(native_calls.size()); - - size_t idx = 0; - for (Map<StringName, native_call_cb>::Element *E = native_calls.front(); E; E = E->next(), idx++) { - call_types.write[idx] = E->key(); - } - - return call_types; -} - -Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) { - Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type); - if (!E) { - ERR_PRINT((String("No handler for native call type \"" + p_native_call_type) + "\" found").utf8().get_data()); - return Variant(); - } - - void *procedure_handle; - - Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( - native_handle, - p_procedure_name, - procedure_handle); - - if (err != OK || procedure_handle == nullptr) { - return Variant(); - } - - godot_variant result = E->get()(procedure_handle, (godot_array *)&p_arguments); - - Variant res = *(Variant *)&result; - godot_variant_destroy(&result); - return res; -} - -Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_optional) const { - if (!initialized) { - ERR_PRINT("No valid library handle, can't get symbol from GDNative object"); - return ERR_CANT_OPEN; - } - - Error result = OS::get_singleton()->get_dynamic_library_symbol_handle( - native_handle, - p_procedure_name, - r_handle, - p_optional); - - return result; -} - -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.instantiate(); - - Ref<ConfigFile> config = lib->get_config_file(); - - Error err = config->load(p_path); - - if (r_error) { - *r_error = err; - } - - lib->set_config_file(config); - - return lib; -} - -void GDNativeLibraryResourceLoader::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdnlib"); -} - -bool GDNativeLibraryResourceLoader::handles_type(const String &p_type) const { - return p_type == "GDNativeLibrary"; -} - -String GDNativeLibraryResourceLoader::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "gdnlib") { - return "GDNativeLibrary"; - } - return ""; -} - -Error GDNativeLibraryResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - Ref<GDNativeLibrary> lib = p_resource; - - if (lib.is_null()) { - return ERR_INVALID_DATA; - } - - Ref<ConfigFile> config = lib->get_config_file(); - - config->set_value("general", "singleton", lib->is_singleton()); - config->set_value("general", "load_once", lib->should_load_once()); - config->set_value("general", "symbol_prefix", lib->get_symbol_prefix()); - config->set_value("general", "reloadable", lib->is_reloadable()); - - return config->save(p_path); -} - -bool GDNativeLibraryResourceSaver::recognize(const RES &p_resource) const { - return Object::cast_to<GDNativeLibrary>(*p_resource) != nullptr; -} - -void GDNativeLibraryResourceSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (Object::cast_to<GDNativeLibrary>(*p_resource) != nullptr) { - p_extensions->push_back("gdnlib"); - } -} diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h deleted file mode 100644 index 0cc6487ea4..0000000000 --- a/modules/gdnative/gdnative.h +++ /dev/null @@ -1,184 +0,0 @@ -/*************************************************************************/ -/* gdnative.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 GDNATIVE_H -#define GDNATIVE_H - -#include "core/io/resource.h" -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/os/thread_safe.h" - -#include "gdnative/gdnative.h" -#include "gdnative_api_struct.gen.h" - -#include "core/io/config_file.h" - -class GDNativeLibraryResourceLoader; -class GDNative; - -class GDNativeLibrary : public Resource { - GDCLASS(GDNativeLibrary, Resource); - - static Map<String, Vector<Ref<GDNative>>> loaded_libraries; - - friend class GDNativeLibraryResourceLoader; - friend class GDNative; - - Ref<ConfigFile> config_file; - - String current_library_path; - Vector<String> current_dependencies; - - bool singleton; - bool load_once; - String symbol_prefix; - bool reloadable; - -public: - virtual void reset_state() override; - - GDNativeLibrary(); - ~GDNativeLibrary(); - - virtual bool _set(const StringName &p_name, const Variant &p_property); - virtual bool _get(const StringName &p_name, Variant &r_property) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - _FORCE_INLINE_ Ref<ConfigFile> get_config_file() { return config_file; } - - void set_config_file(Ref<ConfigFile> p_config_file); - - // things that change per-platform - // so there are no setters for this - _FORCE_INLINE_ String get_current_library_path() const { - return current_library_path; - } - _FORCE_INLINE_ Vector<String> get_current_dependencies() const { - return current_dependencies; - } - - // things that are a property of the library itself, not platform specific - _FORCE_INLINE_ bool should_load_once() const { - return load_once; - } - _FORCE_INLINE_ bool is_singleton() const { - return singleton; - } - _FORCE_INLINE_ String get_symbol_prefix() const { - return symbol_prefix; - } - - _FORCE_INLINE_ bool is_reloadable() const { - return reloadable; - } - - _FORCE_INLINE_ void set_load_once(bool p_load_once) { - config_file->set_value("general", "load_once", p_load_once); - load_once = p_load_once; - } - _FORCE_INLINE_ void set_singleton(bool p_singleton) { - config_file->set_value("general", "singleton", p_singleton); - singleton = p_singleton; - } - _FORCE_INLINE_ void set_symbol_prefix(String p_symbol_prefix) { - config_file->set_value("general", "symbol_prefix", p_symbol_prefix); - symbol_prefix = p_symbol_prefix; - } - - _FORCE_INLINE_ void set_reloadable(bool p_reloadable) { - config_file->set_value("general", "reloadable", p_reloadable); - reloadable = p_reloadable; - } - - static void _bind_methods(); -}; - -struct GDNativeCallRegistry { - static GDNativeCallRegistry *singleton; - - inline static GDNativeCallRegistry *get_singleton() { - return singleton; - } - - inline GDNativeCallRegistry() : - native_calls() {} - - Map<StringName, native_call_cb> native_calls; - - void register_native_call_type(StringName p_call_type, native_call_cb p_callback); - - Vector<StringName> get_native_call_types(); -}; - -class GDNative : public RefCounted { - GDCLASS(GDNative, RefCounted); - - Ref<GDNativeLibrary> library; - - void *native_handle; - - bool initialized; - -public: - GDNative(); - ~GDNative(); - - static void _bind_methods(); - - void set_library(Ref<GDNativeLibrary> p_library); - Ref<GDNativeLibrary> get_library() const; - - bool is_initialized() const; - - bool initialize(); - bool terminate(); - - Variant call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments = Array()); - - Error get_symbol(StringName p_procedure_name, void *&r_handle, bool p_optional = true) const; -}; - -class GDNativeLibraryResourceLoader : public ResourceFormatLoader { -public: - virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, 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; -}; - -class GDNativeLibraryResourceSaver : public ResourceFormatSaver { -public: - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags); - virtual bool recognize(const RES &p_resource) const; - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; -}; - -#endif // GDNATIVE_H diff --git a/modules/gdnative/gdnative/aabb.cpp b/modules/gdnative/gdnative/aabb.cpp deleted file mode 100644 index c42b874b4b..0000000000 --- a/modules/gdnative/gdnative/aabb.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************/ -/* aabb.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 "gdnative/aabb.h" - -#include "core/math/aabb.h" - -static_assert(sizeof(godot_aabb) == sizeof(AABB), "AABB size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_aabb_new(godot_aabb *p_self) { - memnew_placement(p_self, AABB); -} - -void GDAPI godot_aabb_new_copy(godot_aabb *r_dest, const godot_aabb *p_src) { - memnew_placement(r_dest, AABB(*(AABB *)p_src)); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp deleted file mode 100644 index 76e131dc06..0000000000 --- a/modules/gdnative/gdnative/array.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************/ -/* array.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 "gdnative/array.h" - -#include "core/os/memory.h" -#include "core/variant/array.h" - -static_assert(sizeof(godot_array) == sizeof(Array), "Array size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_array_new(godot_array *p_self) { - memnew_placement(p_self, Array); -} - -void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src) { - memnew_placement(r_dest, Array(*(Array *)p_src)); -} - -void GDAPI godot_array_destroy(godot_array *p_self) { - ((Array *)p_self)->~Array(); -} - -godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, godot_int p_index) { - Array *self = (Array *)p_self; - return (godot_variant *)&self->operator[](p_index); -} - -const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, godot_int p_index) { - const Array *self = (const Array *)p_self; - return (const godot_variant *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp deleted file mode 100644 index 4641f0bacc..0000000000 --- a/modules/gdnative/gdnative/basis.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* basis.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 "gdnative/basis.h" - -#include "core/math/basis.h" - -static_assert(sizeof(godot_basis) == sizeof(Basis), "Basis size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_basis_new(godot_basis *p_self) { - memnew_placement(p_self, Basis); -} - -void GDAPI godot_basis_new_copy(godot_basis *r_dest, const godot_basis *p_src) { - memnew_placement(r_dest, Basis(*(Basis *)p_src)); -} - -godot_vector3 GDAPI *godot_basis_operator_index(godot_basis *p_self, godot_int p_index) { - Basis *self = (Basis *)p_self; - return (godot_vector3 *)&self->operator[](p_index); -} - -const godot_vector3 GDAPI *godot_basis_operator_index_const(const godot_basis *p_self, godot_int p_index) { - const Basis *self = (const Basis *)p_self; - return (const godot_vector3 *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/color.cpp b/modules/gdnative/gdnative/color.cpp deleted file mode 100644 index 502f89c027..0000000000 --- a/modules/gdnative/gdnative/color.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* color.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 "gdnative/color.h" - -#include "core/math/color.h" - -static_assert(sizeof(godot_color) == sizeof(Color), "Color size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_color_new(godot_color *p_self) { - memnew_placement(p_self, Color); -} - -void GDAPI godot_color_new_copy(godot_color *r_dest, const godot_color *p_src) { - memnew_placement(r_dest, Color(*(Color *)p_src)); -} - -float GDAPI *godot_color_operator_index(godot_color *p_self, godot_int p_index) { - Color *self = (Color *)p_self; - return (float *)&self->operator[](p_index); -} - -const float GDAPI *godot_color_operator_index_const(const godot_color *p_self, godot_int p_index) { - const Color *self = (const Color *)p_self; - return (const float *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/dictionary.cpp b/modules/gdnative/gdnative/dictionary.cpp deleted file mode 100644 index 2bfad6e695..0000000000 --- a/modules/gdnative/gdnative/dictionary.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************/ -/* dictionary.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 "gdnative/dictionary.h" - -#include "core/variant/dictionary.h" -#include "core/variant/variant.h" - -static_assert(sizeof(godot_dictionary) == sizeof(Dictionary), "Dictionary size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_dictionary_new(godot_dictionary *p_self) { - memnew_placement(p_self, Dictionary); -} - -void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src) { - memnew_placement(r_dest, Dictionary(*(Dictionary *)p_src)); -} - -void GDAPI godot_dictionary_destroy(godot_dictionary *p_self) { - Dictionary *self = (Dictionary *)p_self; - self->~Dictionary(); -} - -godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key) { - Dictionary *self = (Dictionary *)p_self; - return (godot_variant *)&self->operator[](*((const Variant *)p_key)); -} - -const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key) { - const Dictionary *self = (const Dictionary *)p_self; - return (const godot_variant *)&self->operator[](*((const Variant *)p_key)); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp deleted file mode 100644 index e0de1a0505..0000000000 --- a/modules/gdnative/gdnative/gdnative.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/*************************************************************************/ -/* gdnative.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 "gdnative/gdnative.h" - -#include "core/config/engine.h" -#include "core/core_constants.h" -#include "core/error/error_macros.h" -#include "core/object/class_db.h" -#include "core/os/os.h" -#include "core/variant/variant.h" - -#include "modules/gdnative/gdnative.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_object_destroy(godot_object *p_o) { - memdelete((Object *)p_o); -} - -// Singleton API - -godot_object GDAPI *godot_global_get_singleton(char *p_name) { - return (godot_object *)Engine::get_singleton()->get_singleton_object(String(p_name)); -} // result shouldn't be freed - -// MethodBind API - -godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname) { - MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname)); - // MethodBind *mb = ClassDB::get_method("Node", "get_name"); - return (godot_method_bind *)mb; -} - -void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret) { - MethodBind *mb = (MethodBind *)p_method_bind; - Object *o = (Object *)p_instance; - mb->ptrcall(o, p_args, p_ret); -} - -godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error) { - MethodBind *mb = (MethodBind *)p_method_bind; - Object *o = (Object *)p_instance; - const Variant **args = (const Variant **)p_args; - - godot_variant ret; - godot_variant_new_nil(&ret); - - Variant *ret_val = (Variant *)&ret; - - Callable::CallError r_error; - *ret_val = mb->call(o, args, p_arg_count, r_error); - - if (p_call_error) { - p_call_error->error = (godot_variant_call_error_error)r_error.error; - p_call_error->argument = r_error.argument; - p_call_error->expected = (godot_variant_type)r_error.expected; - } - - return ret; -} - -godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname) { - ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname)); - if (class_info) { - return (godot_class_constructor)class_info->creation_func; - } - return nullptr; -} - -godot_dictionary GDAPI godot_get_global_constants() { - godot_dictionary constants; - memnew_placement(&constants, Dictionary); - Dictionary *p_constants = (Dictionary *)&constants; - const int constants_count = CoreConstants::get_global_constant_count(); - for (int i = 0; i < constants_count; ++i) { - const char *name = CoreConstants::get_global_constant_name(i); - int value = CoreConstants::get_global_constant_value(i); - (*p_constants)[name] = value; - } - return constants; -} - -// System functions -void GDAPI godot_register_native_call_type(const char *p_call_type, native_call_cb p_callback) { - GDNativeCallRegistry::get_singleton()->register_native_call_type(StringName(p_call_type), p_callback); -} - -void GDAPI *godot_alloc(int p_bytes) { - return memalloc(p_bytes); -} - -void GDAPI *godot_realloc(void *p_ptr, int p_bytes) { - return memrealloc(p_ptr, p_bytes); -} - -void GDAPI godot_free(void *p_ptr) { - memfree(p_ptr); -} - -// Helper print functions. -void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line) { - _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_ERROR); -} -void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line) { - _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_WARNING); -} -void GDAPI godot_print_script_error(const char *p_description, const char *p_function, const char *p_file, int p_line) { - _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT); -} - -void _gdnative_report_version_mismatch(const godot_object *p_library, const char *p_ext, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have) { - String message = "Error loading GDNative file "; - GDNativeLibrary *library = (GDNativeLibrary *)p_library; - - message += library->get_current_library_path() + ": Extension \"" + p_ext + "\" can't be loaded.\n"; - - Dictionary versions; - versions["have_major"] = p_have.major; - versions["have_minor"] = p_have.minor; - versions["want_major"] = p_want.major; - versions["want_minor"] = p_want.minor; - - message += String("Got version {have_major}.{have_minor} but needs {want_major}.{want_minor}!").format(versions); - - _err_print_error("gdnative_init", library->get_current_library_path().utf8().ptr(), 0, message.utf8().ptr()); -} - -void _gdnative_report_loading_error(const godot_object *p_library, const char *p_what) { - String message = "Error loading GDNative file "; - GDNativeLibrary *library = (GDNativeLibrary *)p_library; - - message += library->get_current_library_path() + ": " + p_what; - - _err_print_error("gdnative_init", library->get_current_library_path().utf8().ptr(), 0, message.utf8().ptr()); -} - -godot_object GDAPI *godot_instance_from_id(uint64_t p_instance_id) { - return (godot_object *)ObjectDB::get_instance(ObjectID(p_instance_id)); -} - -void *godot_get_class_tag(const godot_string_name *p_class) { - StringName class_name = *(StringName *)p_class; - ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name); - return class_info ? class_info->class_ptr : nullptr; -} - -godot_object *godot_object_cast_to(const godot_object *p_object, void *p_class_tag) { - if (!p_object) { - return nullptr; - } - Object *o = (Object *)p_object; - - return o->is_class_ptr(p_class_tag) ? (godot_object *)o : nullptr; -} - -uint64_t GDAPI godot_object_get_instance_id(const godot_object *p_object) { - const Object *o = (const Object *)p_object; - return (uint64_t)o->get_instance_id(); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp deleted file mode 100644 index 57d67b9abb..0000000000 --- a/modules/gdnative/gdnative/node_path.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************/ -/* node_path.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 "gdnative/node_path.h" - -#include "core/string/node_path.h" - -static_assert(sizeof(godot_node_path) == sizeof(NodePath), "NodePath size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_node_path_new(godot_node_path *p_self) { - memnew_placement(p_self, NodePath); -} - -void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src) { - memnew_placement(r_dest, NodePath(*(NodePath *)p_src)); -} - -void GDAPI godot_node_path_destroy(godot_node_path *p_self) { - NodePath *self = (NodePath *)p_self; - self->~NodePath(); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/packed_arrays.cpp b/modules/gdnative/gdnative/packed_arrays.cpp deleted file mode 100644 index f03c94aeb8..0000000000 --- a/modules/gdnative/gdnative/packed_arrays.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/*************************************************************************/ -/* packed_arrays.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 "gdnative/packed_arrays.h" - -#include "core/variant/variant.h" - -#include "core/math/vector2.h" -#include "core/math/vector3i.h" - -static_assert(sizeof(godot_packed_byte_array) == sizeof(PackedByteArray), "PackedByteArray size mismatch"); -static_assert(sizeof(godot_packed_int32_array) == sizeof(PackedInt32Array), "PackedInt32Array size mismatch"); -static_assert(sizeof(godot_packed_int64_array) == sizeof(PackedInt64Array), "PackedInt64Array size mismatch"); -static_assert(sizeof(godot_packed_float32_array) == sizeof(PackedFloat32Array), "PackedFloat32Array size mismatch"); -static_assert(sizeof(godot_packed_float64_array) == sizeof(PackedFloat64Array), "PackedFloat64Array size mismatch"); -static_assert(sizeof(godot_packed_string_array) == sizeof(PackedStringArray), "PackedStringArray size mismatch"); -static_assert(sizeof(godot_packed_vector2_array) == sizeof(PackedVector2Array), "PackedVector2Array size mismatch"); -static_assert(sizeof(godot_packed_vector2i_array) == sizeof(Vector<Vector2i>), "Vector<Vector2i> size mismatch"); -static_assert(sizeof(godot_packed_vector3_array) == sizeof(PackedVector3Array), "PackedVector3Array size mismatch"); -static_assert(sizeof(godot_packed_vector3i_array) == sizeof(Vector<Vector3i>), "Vector<Vector3i> size mismatch"); -static_assert(sizeof(godot_packed_color_array) == sizeof(PackedColorArray), "PackedColorArray size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -// byte - -void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self) { - memnew_placement(p_self, PackedByteArray); -} - -void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src) { - memnew_placement(r_dest, PackedByteArray(*(PackedByteArray *)p_src)); -} - -void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self) { - ((PackedByteArray *)p_self)->~PackedByteArray(); -} - -uint8_t GDAPI *godot_packed_byte_array_operator_index(godot_packed_byte_array *p_self, godot_int p_index) { - PackedByteArray *self = (PackedByteArray *)p_self; - return (uint8_t *)&self->operator[](p_index); -} - -const uint8_t GDAPI *godot_packed_byte_array_operator_index_const(const godot_packed_byte_array *p_self, godot_int p_index) { - const PackedByteArray *self = (const PackedByteArray *)p_self; - return (const uint8_t *)&self->operator[](p_index); -} - -// int32 - -void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self) { - memnew_placement(p_self, PackedInt32Array); -} - -void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src) { - memnew_placement(r_dest, PackedInt32Array(*(PackedInt32Array *)p_src)); -} - -void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self) { - ((PackedInt32Array *)p_self)->~PackedInt32Array(); -} - -int32_t GDAPI *godot_packed_int32_array_operator_index(godot_packed_int32_array *p_self, godot_int p_index) { - PackedInt32Array *self = (PackedInt32Array *)p_self; - return (int32_t *)&self->operator[](p_index); -} - -const int32_t GDAPI *godot_packed_int32_array_operator_index_const(const godot_packed_int32_array *p_self, godot_int p_index) { - const PackedInt32Array *self = (const PackedInt32Array *)p_self; - return (const int32_t *)&self->operator[](p_index); -} - -// int64 - -void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self) { - memnew_placement(p_self, PackedInt64Array); -} - -void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src) { - memnew_placement(r_dest, PackedInt64Array(*(PackedInt64Array *)p_src)); -} - -void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self) { - ((PackedInt64Array *)p_self)->~PackedInt64Array(); -} - -int64_t GDAPI *godot_packed_int64_array_operator_index(godot_packed_int64_array *p_self, godot_int p_index) { - PackedInt64Array *self = (PackedInt64Array *)p_self; - return (int64_t *)&self->operator[](p_index); -} - -const int64_t GDAPI *godot_packed_int64_array_operator_index_const(const godot_packed_int64_array *p_self, godot_int p_index) { - const PackedInt64Array *self = (const PackedInt64Array *)p_self; - return (const int64_t *)&self->operator[](p_index); -} - -// float32 - -void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self) { - memnew_placement(p_self, PackedFloat32Array); -} - -void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src) { - memnew_placement(r_dest, PackedFloat32Array(*(PackedFloat32Array *)p_src)); -} - -void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self) { - ((PackedFloat32Array *)p_self)->~PackedFloat32Array(); -} - -float GDAPI *godot_packed_float32_array_operator_index(godot_packed_float32_array *p_self, godot_int p_index) { - PackedFloat32Array *self = (PackedFloat32Array *)p_self; - return (float *)&self->operator[](p_index); -} - -const float GDAPI *godot_packed_float32_array_operator_index_const(const godot_packed_float32_array *p_self, godot_int p_index) { - const PackedFloat32Array *self = (const PackedFloat32Array *)p_self; - return (const float *)&self->operator[](p_index); -} - -// float64 - -void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self) { - memnew_placement(p_self, PackedFloat64Array); -} - -void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src) { - memnew_placement(r_dest, PackedFloat64Array(*(PackedFloat64Array *)p_src)); -} - -void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self) { - ((PackedFloat64Array *)p_self)->~PackedFloat64Array(); -} - -double GDAPI *godot_packed_float64_array_operator_index(godot_packed_float64_array *p_self, godot_int p_index) { - PackedFloat64Array *self = (PackedFloat64Array *)p_self; - return (double *)&self->operator[](p_index); -} - -const double GDAPI *godot_packed_float64_array_operator_index_const(const godot_packed_float64_array *p_self, godot_int p_index) { - const PackedFloat64Array *self = (const PackedFloat64Array *)p_self; - return (const double *)&self->operator[](p_index); -} - -// string - -void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self) { - memnew_placement(p_self, PackedStringArray); -} - -void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src) { - memnew_placement(r_dest, PackedStringArray(*(PackedStringArray *)p_src)); -} - -void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self) { - ((PackedStringArray *)p_self)->~PackedStringArray(); -} - -godot_string GDAPI *godot_packed_string_array_operator_index(godot_packed_string_array *p_self, godot_int p_index) { - PackedStringArray *self = (PackedStringArray *)p_self; - return (godot_string *)&self->operator[](p_index); -} - -const godot_string GDAPI *godot_packed_string_array_operator_index_const(const godot_packed_string_array *p_self, godot_int p_index) { - const PackedStringArray *self = (const PackedStringArray *)p_self; - return (const godot_string *)&self->operator[](p_index); -} - -// vector2 - -void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self) { - memnew_placement(p_self, PackedVector2Array); -} - -void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src) { - memnew_placement(r_dest, PackedVector2Array(*(PackedVector2Array *)p_src)); -} - -void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self) { - ((PackedVector2Array *)p_self)->~PackedVector2Array(); -} - -godot_vector2 GDAPI *godot_packed_vector2_array_operator_index(godot_packed_vector2_array *p_self, godot_int p_index) { - PackedVector2Array *self = (PackedVector2Array *)p_self; - return (godot_vector2 *)&self->operator[](p_index); -} - -const godot_vector2 GDAPI *godot_packed_vector2_array_operator_index_const(const godot_packed_vector2_array *p_self, godot_int p_index) { - const PackedVector2Array *self = (const PackedVector2Array *)p_self; - return (const godot_vector2 *)&self->operator[](p_index); -} - -// vector2i - -void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self) { - memnew_placement(p_self, Vector<Vector2i>); -} - -void GDAPI godot_packed_vector2i_array_new_copy(godot_packed_vector2i_array *r_dest, const godot_packed_vector2i_array *p_src) { - memnew_placement(r_dest, Vector<Vector2i>(*(Vector<Vector2i> *)p_src)); -} - -void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self) { - ((Vector<Vector2i> *)p_self)->~Vector(); -} - -godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index(godot_packed_vector2i_array *p_self, godot_int p_index) { - Vector<Vector2i> *self = (Vector<Vector2i> *)p_self; - return (godot_vector2i *)&self->operator[](p_index); -} - -const godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index_const(const godot_packed_vector2i_array *p_self, godot_int p_index) { - const Vector<Vector2i> *self = (const Vector<Vector2i> *)p_self; - return (const godot_vector2i *)&self->operator[](p_index); -} - -// vector3 - -void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self) { - memnew_placement(p_self, PackedVector3Array); -} - -void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src) { - memnew_placement(r_dest, PackedVector3Array(*(PackedVector3Array *)p_src)); -} - -void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self) { - ((PackedVector3Array *)p_self)->~PackedVector3Array(); -} - -godot_vector3 GDAPI *godot_packed_vector3_array_operator_index(godot_packed_vector3_array *p_self, godot_int p_index) { - PackedVector3Array *self = (PackedVector3Array *)p_self; - return (godot_vector3 *)&self->operator[](p_index); -} - -const godot_vector3 GDAPI *godot_packed_vector3_array_operator_index_const(const godot_packed_vector3_array *p_self, godot_int p_index) { - const PackedVector3Array *self = (const PackedVector3Array *)p_self; - return (const godot_vector3 *)&self->operator[](p_index); -} - -// vector3i - -void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self) { - memnew_placement(p_self, Vector<Vector3i>); -} - -void GDAPI godot_packed_vector3i_array_new_copy(godot_packed_vector3i_array *r_dest, const godot_packed_vector3i_array *p_src) { - memnew_placement(r_dest, Vector<Vector3i>(*(Vector<Vector3i> *)p_src)); -} - -void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self) { - ((Vector<Vector3i> *)p_self)->~Vector(); -} - -godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index(godot_packed_vector3i_array *p_self, godot_int p_index) { - Vector<Vector3i> *self = (Vector<Vector3i> *)p_self; - return (godot_vector3i *)&self->operator[](p_index); -} - -const godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index_const(const godot_packed_vector3i_array *p_self, godot_int p_index) { - const Vector<Vector3i> *self = (const Vector<Vector3i> *)p_self; - return (const godot_vector3i *)&self->operator[](p_index); -} - -// color - -void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self) { - memnew_placement(p_self, PackedColorArray); -} - -void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src) { - memnew_placement(r_dest, PackedColorArray(*(PackedColorArray *)p_src)); -} - -void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self) { - ((PackedColorArray *)p_self)->~PackedColorArray(); -} - -godot_color GDAPI *godot_packed_color_array_operator_index(godot_packed_color_array *p_self, godot_int p_index) { - PackedColorArray *self = (PackedColorArray *)p_self; - return (godot_color *)&self->operator[](p_index); -} - -const godot_color GDAPI *godot_packed_color_array_operator_index_const(const godot_packed_color_array *p_self, godot_int p_index) { - const PackedColorArray *self = (const PackedColorArray *)p_self; - return (const godot_color *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/plane.cpp b/modules/gdnative/gdnative/plane.cpp deleted file mode 100644 index 8b8e84e3c1..0000000000 --- a/modules/gdnative/gdnative/plane.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************/ -/* plane.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 "gdnative/plane.h" - -#include "core/math/plane.h" - -static_assert(sizeof(godot_plane) == sizeof(Plane), "Plane size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_plane_new(godot_plane *p_self) { - memnew_placement(p_self, Plane); -} - -void GDAPI godot_plane_new_copy(godot_plane *r_dest, const godot_plane *p_src) { - memnew_placement(r_dest, Plane(*(Plane *)p_src)); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/quaternion.cpp b/modules/gdnative/gdnative/quaternion.cpp deleted file mode 100644 index 62bcbbd382..0000000000 --- a/modules/gdnative/gdnative/quaternion.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* quaternion.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 "gdnative/quaternion.h" - -#include "core/math/quaternion.h" - -static_assert(sizeof(godot_quaternion) == sizeof(Quaternion), "Quaternion size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_quaternion_new(godot_quaternion *p_self) { - memnew_placement(p_self, Quaternion); -} - -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_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_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); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp deleted file mode 100644 index a196a63188..0000000000 --- a/modules/gdnative/gdnative/rect2.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* rect2.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 "gdnative/rect2.h" - -#include "core/math/rect2.h" - -static_assert(sizeof(godot_rect2) == sizeof(Rect2), "Rect2 size mismatch"); -static_assert(sizeof(godot_rect2i) == sizeof(Rect2i), "Rect2i size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_rect2_new(godot_rect2 *p_self) { - memnew_placement(p_self, Rect2); -} - -void GDAPI godot_rect2_new_copy(godot_rect2 *r_dest, const godot_rect2 *p_src) { - memnew_placement(r_dest, Rect2(*(Rect2 *)p_src)); -} - -void GDAPI godot_rect2i_new(godot_rect2i *p_self) { - memnew_placement(p_self, Rect2i); -} - -void GDAPI godot_rect2i_new_copy(godot_rect2i *r_dest, const godot_rect2i *p_src) { - memnew_placement(r_dest, Rect2i(*(Rect2i *)p_src)); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/rid.cpp b/modules/gdnative/gdnative/rid.cpp deleted file mode 100644 index f8599afcf9..0000000000 --- a/modules/gdnative/gdnative/rid.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* rid.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 "gdnative/rid.h" - -#include "core/os/memory.h" -#include "core/templates/rid.h" - -static_assert(sizeof(godot_rid) == sizeof(RID), "RID size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_rid_new(godot_rid *p_self) { - memnew_placement(p_self, RID); -} - -void GDAPI godot_rid_new_copy(godot_rid *r_dest, const godot_rid *p_src) { - memnew_placement(r_dest, RID(*(RID *)p_src)); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/signal.cpp b/modules/gdnative/gdnative/signal.cpp deleted file mode 100644 index 5963c0e6c6..0000000000 --- a/modules/gdnative/gdnative/signal.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************/ -/* signal.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 "gdnative/signal.h" - -#include "core/variant/callable.h" -#include "core/variant/variant.h" - -static_assert(sizeof(godot_signal) == sizeof(Signal), "Signal size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_signal_new(godot_signal *p_self) { - memnew_placement(p_self, Signal); -} - -void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src) { - memnew_placement(r_dest, Signal(*(Signal *)p_src)); -} - -void GDAPI godot_signal_destroy(godot_signal *p_self) { - Signal *self = (Signal *)p_self; - self->~Signal(); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp deleted file mode 100644 index 1ad1ea8bdf..0000000000 --- a/modules/gdnative/gdnative/string.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/*************************************************************************/ -/* string.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 "gdnative/string.h" - -#include "core/string/ustring.h" - -static_assert(sizeof(godot_string) == sizeof(String), "String size mismatch"); -static_assert(sizeof(godot_char_type) == sizeof(char32_t), "char32_t size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_string_new(godot_string *r_dest) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); -} - -void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src) { - memnew_placement(r_dest, String(*(String *)p_src)); -} - -void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - *dest = String(p_contents); -} - -void GDAPI godot_string_new_with_utf8_chars(godot_string *r_dest, const char *p_contents) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - dest->parse_utf8(p_contents); -} - -void GDAPI godot_string_new_with_utf16_chars(godot_string *r_dest, const char16_t *p_contents) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - dest->parse_utf16(p_contents); -} - -void GDAPI godot_string_new_with_utf32_chars(godot_string *r_dest, const char32_t *p_contents) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - *dest = String((const char32_t *)p_contents); -} - -void GDAPI godot_string_new_with_wide_chars(godot_string *r_dest, const wchar_t *p_contents) { - String *dest = (String *)r_dest; - if (sizeof(wchar_t) == 2) { - // wchar_t is 16 bit, parse. - memnew_placement(dest, String); - dest->parse_utf16((const char16_t *)p_contents); - } else { - // wchar_t is 32 bit, copy. - memnew_placement(dest, String); - *dest = String((const char32_t *)p_contents); - } -} - -void GDAPI godot_string_new_with_latin1_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - *dest = String(p_contents, p_size); -} - -void GDAPI godot_string_new_with_utf8_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - dest->parse_utf8(p_contents, p_size); -} - -void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const char16_t *p_contents, const int p_size) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - dest->parse_utf16(p_contents, p_size); -} - -void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size) { - String *dest = (String *)r_dest; - memnew_placement(dest, String); - *dest = String((const char32_t *)p_contents, p_size); -} - -void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size) { - String *dest = (String *)r_dest; - if (sizeof(wchar_t) == 2) { - // wchar_t is 16 bit, parse. - memnew_placement(dest, String); - dest->parse_utf16((const char16_t *)p_contents, p_size); - } else { - // wchar_t is 32 bit, copy. - memnew_placement(dest, String); - *dest = String((const char32_t *)p_contents, p_size); - } -} - -const char GDAPI *godot_string_to_latin1_chars(const godot_string *p_self) { - String *self = (String *)p_self; - return self->ascii(true).get_data(); -} - -const char GDAPI *godot_string_to_utf8_chars(const godot_string *p_self) { - String *self = (String *)p_self; - return self->utf8().get_data(); -} - -const char16_t GDAPI *godot_string_to_utf16_chars(const godot_string *p_self) { - String *self = (String *)p_self; - return self->utf16().get_data(); -} - -const char32_t GDAPI *godot_string_to_utf32_chars(const godot_string *p_self) { - String *self = (String *)p_self; - return self->get_data(); -} - -const wchar_t GDAPI *godot_string_to_wide_chars(const godot_string *p_self) { - String *self = (String *)p_self; - if (sizeof(wchar_t) == 2) { - return (const wchar_t *)self->utf16().get_data(); - } else { - return (const wchar_t *)self->get_data(); - } -} - -char32_t GDAPI *godot_string_operator_index(godot_string *p_self, godot_int p_index) { - String *self = (String *)p_self; - return self->ptrw(); -} - -const char32_t GDAPI *godot_string_operator_index_const(const godot_string *p_self, godot_int p_index) { - const String *self = (const String *)p_self; - return self->ptr(); -} - -void GDAPI godot_string_destroy(godot_string *p_self) { - String *self = (String *)p_self; - self->~String(); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/transform2d.cpp b/modules/gdnative/gdnative/transform2d.cpp deleted file mode 100644 index 2864818831..0000000000 --- a/modules/gdnative/gdnative/transform2d.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* transform2d.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 "gdnative/transform2d.h" - -#include "core/math/transform_2d.h" - -static_assert(sizeof(godot_transform2d) == sizeof(Transform2D), "Transform2D size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_transform2d_new(godot_transform2d *p_self) { - memnew_placement(p_self, Transform2D); -} - -void GDAPI godot_transform2d_new_copy(godot_transform2d *r_dest, const godot_transform2d *p_src) { - memnew_placement(r_dest, Transform2D(*(Transform2D *)p_src)); -} - -godot_vector2 GDAPI *godot_transform2d_operator_index(godot_transform2d *p_self, godot_int p_index) { - Transform2D *self = (Transform2D *)p_self; - return (godot_vector2 *)&self->operator[](p_index); -} - -const godot_vector2 GDAPI *godot_transform2d_operator_index_const(const godot_transform2d *p_self, godot_int p_index) { - const Transform2D *self = (const Transform2D *)p_self; - return (const godot_vector2 *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/transform_3d.cpp b/modules/gdnative/gdnative/transform_3d.cpp deleted file mode 100644 index 8bd2a68d63..0000000000 --- a/modules/gdnative/gdnative/transform_3d.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************/ -/* transform_3d.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 "gdnative/transform_3d.h" - -#include "core/math/transform_3d.h" - -static_assert(sizeof(godot_transform3d) == sizeof(Transform3D), "Transform3D size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_transform3d_new(godot_transform3d *p_self) { - memnew_placement(p_self, Transform3D); -} - -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 -} -#endif diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp deleted file mode 100644 index ec9aaa0a55..0000000000 --- a/modules/gdnative/gdnative/variant.cpp +++ /dev/null @@ -1,1273 +0,0 @@ -/*************************************************************************/ -/* variant.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 "gdnative/variant.h" - -#include "core/object/ref_counted.h" -#include "core/variant/variant.h" - -#ifdef __cplusplus -extern "C" { -#endif - -static_assert(sizeof(godot_variant) == sizeof(Variant), "Variant size mismatch"); - -// Workaround GCC ICE on armv7hl which was affected GCC 6.0 up to 8.0 (GH-16100). -// It was fixed upstream in 8.1, and a fix was backported to 7.4. -// This can be removed once no supported distro ships with versions older than 7.4. -#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) && \ - (__GNUC__ == 6 || (__GNUC__ == 7 && __GNUC_MINOR__ < 4) || (__GNUC__ == 8 && __GNUC_MINOR__ < 1)) -#pragma GCC push_options -#pragma GCC optimize("-O0") -#endif - -#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) && \ - (__GNUC__ == 6 || (__GNUC__ == 7 && __GNUC_MINOR__ < 4) || (__GNUC__ == 8 && __GNUC_MINOR__ < 1)) -#pragma GCC pop_options -#endif - -// Memory - -void GDAPI godot_variant_new_copy(godot_variant *p_dest, const godot_variant *p_src) { - Variant *dest = (Variant *)p_dest; - const Variant *src = (const Variant *)p_src; - memnew_placement(dest, Variant(*src)); -} - -void GDAPI godot_variant_new_nil(godot_variant *r_dest) { - Variant *dest = (Variant *)r_dest; - memnew_placement(dest, Variant); -} - -void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b) { - Variant *dest = (Variant *)r_dest; - memnew_placement(dest, Variant(p_b)); -} - -void GDAPI godot_variant_new_int(godot_variant *r_dest, const godot_int p_i) { - Variant *dest = (Variant *)r_dest; - memnew_placement(dest, Variant(p_i)); -} - -void GDAPI godot_variant_new_float(godot_variant *r_dest, const godot_float p_r) { - Variant *dest = (Variant *)r_dest; - memnew_placement(dest, Variant(p_r)); -} - -void GDAPI godot_variant_new_string(godot_variant *r_dest, const godot_string *p_s) { - Variant *dest = (Variant *)r_dest; - const String *s = (const String *)p_s; - memnew_placement(dest, Variant(*s)); -} - -void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s) { - Variant *dest = (Variant *)r_dest; - const StringName *s = (const StringName *)p_s; - memnew_placement(dest, Variant(*s)); -} - -void GDAPI godot_variant_new_vector2(godot_variant *r_dest, const godot_vector2 *p_v2) { - Variant *dest = (Variant *)r_dest; - const Vector2 *v2 = (const Vector2 *)p_v2; - memnew_placement(dest, Variant(*v2)); -} - -void GDAPI godot_variant_new_vector2i(godot_variant *r_dest, const godot_vector2i *p_v2) { - Variant *dest = (Variant *)r_dest; - const Vector2i *v2 = (const Vector2i *)p_v2; - memnew_placement(dest, Variant(*v2)); -} - -void GDAPI godot_variant_new_rect2(godot_variant *r_dest, const godot_rect2 *p_rect2) { - Variant *dest = (Variant *)r_dest; - const Rect2 *rect2 = (const Rect2 *)p_rect2; - memnew_placement(dest, Variant(*rect2)); -} - -void GDAPI godot_variant_new_rect2i(godot_variant *r_dest, const godot_rect2i *p_rect2) { - Variant *dest = (Variant *)r_dest; - const Rect2i *rect2 = (const Rect2i *)p_rect2; - memnew_placement(dest, Variant(*rect2)); -} - -void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3 *p_v3) { - Variant *dest = (Variant *)r_dest; - const Vector3 *v3 = (const Vector3 *)p_v3; - memnew_placement(dest, Variant(*v3)); -} - -void GDAPI godot_variant_new_vector3i(godot_variant *r_dest, const godot_vector3i *p_v3) { - Variant *dest = (Variant *)r_dest; - const Vector3i *v3 = (const Vector3i *)p_v3; - memnew_placement(dest, Variant(*v3)); -} - -void GDAPI godot_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d) { - Variant *dest = (Variant *)r_dest; - const Transform2D *t2d = (const Transform2D *)p_t2d; - memnew_placement(dest, Variant(*t2d)); -} - -void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_plane) { - Variant *dest = (Variant *)r_dest; - const Plane *plane = (const Plane *)p_plane; - memnew_placement(dest, Variant(*plane)); -} - -void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion) { - Variant *dest = (Variant *)r_dest; - const Quaternion *quaternion = (const Quaternion *)p_quaternion; - memnew_placement(dest, Variant(*quaternion)); -} - -void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) { - Variant *dest = (Variant *)r_dest; - const AABB *aabb = (const AABB *)p_aabb; - memnew_placement(dest, Variant(*aabb)); -} - -void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis) { - Variant *dest = (Variant *)r_dest; - const Basis *basis = (const Basis *)p_basis; - memnew_placement(dest, Variant(*basis)); -} - -void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans) { - Variant *dest = (Variant *)r_dest; - const Transform3D *trans = (const Transform3D *)p_trans; - memnew_placement(dest, Variant(*trans)); -} - -void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color) { - Variant *dest = (Variant *)r_dest; - const Color *color = (const Color *)p_color; - memnew_placement(dest, Variant(*color)); -} - -void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np) { - Variant *dest = (Variant *)r_dest; - const NodePath *np = (const NodePath *)p_np; - memnew_placement(dest, Variant(*np)); -} - -void GDAPI godot_variant_new_rid(godot_variant *r_dest, const godot_rid *p_rid) { - Variant *dest = (Variant *)r_dest; - const RID *rid = (const RID *)p_rid; - memnew_placement(dest, Variant(*rid)); -} - -void GDAPI godot_variant_new_callable(godot_variant *r_dest, const godot_callable *p_cb) { - Variant *dest = (Variant *)r_dest; - const Callable *cb = (const Callable *)p_cb; - memnew_placement(dest, Variant(*cb)); -} - -void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p_signal) { - Variant *dest = (Variant *)r_dest; - const Signal *signal = (const Signal *)p_signal; - memnew_placement(dest, Variant(*signal)); -} - -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 RefCounted *ref_counted = Object::cast_to<RefCounted>(obj); - REF ref; - if (ref_counted) { - ref = REF(ref_counted); - } - if (!ref.is_null()) { - memnew_placement(dest, Variant(ref)); - } else { -#if defined(DEBUG_METHODS_ENABLED) - if (ref_counted) { - ERR_PRINT("RefCounted object has 0 refcount in godot_variant_new_object - you lost it somewhere."); - } -#endif - memnew_placement(dest, Variant(obj)); - } -} - -void GDAPI godot_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict) { - Variant *dest = (Variant *)r_dest; - const Dictionary *dict = (const Dictionary *)p_dict; - memnew_placement(dest, Variant(*dict)); -} - -void GDAPI godot_variant_new_array(godot_variant *r_dest, const godot_array *p_arr) { - Variant *dest = (Variant *)r_dest; - const Array *arr = (const Array *)p_arr; - memnew_placement(dest, Variant(*arr)); -} - -void GDAPI godot_variant_new_packed_byte_array(godot_variant *r_dest, const godot_packed_byte_array *p_pba) { - Variant *dest = (Variant *)r_dest; - const PackedByteArray *pba = (const PackedByteArray *)p_pba; - memnew_placement(dest, Variant(*pba)); -} - -void GDAPI godot_variant_new_packed_int32_array(godot_variant *r_dest, const godot_packed_int32_array *p_pia) { - Variant *dest = (Variant *)r_dest; - const PackedInt32Array *pia = (const PackedInt32Array *)p_pia; - memnew_placement(dest, Variant(*pia)); -} - -void GDAPI godot_variant_new_packed_int64_array(godot_variant *r_dest, const godot_packed_int64_array *p_pia) { - Variant *dest = (Variant *)r_dest; - const PackedInt64Array *pia = (const PackedInt64Array *)p_pia; - memnew_placement(dest, Variant(*pia)); -} - -void GDAPI godot_variant_new_packed_float32_array(godot_variant *r_dest, const godot_packed_float32_array *p_pra) { - Variant *dest = (Variant *)r_dest; - const PackedFloat32Array *pra = (const PackedFloat32Array *)p_pra; - memnew_placement(dest, Variant(*pra)); -} - -void GDAPI godot_variant_new_packed_float64_array(godot_variant *r_dest, const godot_packed_float64_array *p_pra) { - Variant *dest = (Variant *)r_dest; - const PackedFloat64Array *pra = (const PackedFloat64Array *)p_pra; - memnew_placement(dest, Variant(*pra)); -} - -void GDAPI godot_variant_new_packed_string_array(godot_variant *r_dest, const godot_packed_string_array *p_psa) { - Variant *dest = (Variant *)r_dest; - const PackedStringArray *psa = (const PackedStringArray *)p_psa; - memnew_placement(dest, Variant(*psa)); -} - -void GDAPI godot_variant_new_packed_vector2_array(godot_variant *r_dest, const godot_packed_vector2_array *p_pv2a) { - Variant *dest = (Variant *)r_dest; - const PackedVector2Array *pv2a = (const PackedVector2Array *)p_pv2a; - memnew_placement(dest, Variant(*pv2a)); -} - -void GDAPI godot_variant_new_packed_vector3_array(godot_variant *r_dest, const godot_packed_vector3_array *p_pv3a) { - Variant *dest = (Variant *)r_dest; - const PackedVector3Array *pv3a = (const PackedVector3Array *)p_pv3a; - memnew_placement(dest, Variant(*pv3a)); -} - -void GDAPI godot_variant_new_packed_color_array(godot_variant *r_dest, const godot_packed_color_array *p_pca) { - Variant *dest = (Variant *)r_dest; - const PackedColorArray *pca = (const PackedColorArray *)p_pca; - memnew_placement(dest, Variant(*pca)); -} - -godot_bool GDAPI godot_variant_as_bool(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - return self->operator bool(); -} - -godot_int GDAPI godot_variant_as_int(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - return self->operator int64_t(); -} - -godot_float GDAPI godot_variant_as_float(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - return self->operator double(); -} - -godot_string GDAPI godot_variant_as_string(const godot_variant *p_self) { - godot_string raw_dest; - const Variant *self = (const Variant *)p_self; - String *dest = (String *)&raw_dest; - memnew_placement(dest, String(self->operator String())); // operator = is overloaded by String - return raw_dest; -} - -godot_string_name GDAPI godot_variant_as_string_name(const godot_variant *p_self) { - godot_string_name raw_dest; - const Variant *self = (const Variant *)p_self; - StringName *dest = (StringName *)&raw_dest; - memnew_placement(dest, StringName(self->operator StringName())); // operator = is overloaded by StringName - return raw_dest; -} - -godot_vector2 GDAPI godot_variant_as_vector2(const godot_variant *p_self) { - godot_vector2 raw_dest; - const Variant *self = (const Variant *)p_self; - Vector2 *dest = (Vector2 *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_vector2i GDAPI godot_variant_as_vector2i(const godot_variant *p_self) { - godot_vector2i raw_dest; - const Variant *self = (const Variant *)p_self; - Vector2i *dest = (Vector2i *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_rect2 GDAPI godot_variant_as_rect2(const godot_variant *p_self) { - godot_rect2 raw_dest; - const Variant *self = (const Variant *)p_self; - Rect2 *dest = (Rect2 *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_rect2i GDAPI godot_variant_as_rect2i(const godot_variant *p_self) { - godot_rect2i raw_dest; - const Variant *self = (const Variant *)p_self; - Rect2i *dest = (Rect2i *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_vector3 GDAPI godot_variant_as_vector3(const godot_variant *p_self) { - godot_vector3 raw_dest; - const Variant *self = (const Variant *)p_self; - Vector3 *dest = (Vector3 *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_vector3i GDAPI godot_variant_as_vector3i(const godot_variant *p_self) { - godot_vector3i raw_dest; - const Variant *self = (const Variant *)p_self; - Vector3i *dest = (Vector3i *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_transform2d GDAPI godot_variant_as_transform2d(const godot_variant *p_self) { - godot_transform2d raw_dest; - const Variant *self = (const Variant *)p_self; - Transform2D *dest = (Transform2D *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self) { - godot_plane raw_dest; - const Variant *self = (const Variant *)p_self; - Plane *dest = (Plane *)&raw_dest; - *dest = *self; - return 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; - Quaternion *dest = (Quaternion *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_aabb GDAPI godot_variant_as_aabb(const godot_variant *p_self) { - godot_aabb raw_dest; - const Variant *self = (const Variant *)p_self; - AABB *dest = (AABB *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self) { - godot_basis raw_dest; - const Variant *self = (const Variant *)p_self; - Basis *dest = (Basis *)&raw_dest; - *dest = *self; - return 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; - Transform3D *dest = (Transform3D *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_color GDAPI godot_variant_as_color(const godot_variant *p_self) { - godot_color raw_dest; - const Variant *self = (const Variant *)p_self; - Color *dest = (Color *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_node_path GDAPI godot_variant_as_node_path(const godot_variant *p_self) { - godot_node_path raw_dest; - const Variant *self = (const Variant *)p_self; - NodePath *dest = (NodePath *)&raw_dest; - memnew_placement(dest, NodePath(self->operator NodePath())); // operator = is overloaded by NodePath - return raw_dest; -} - -godot_rid GDAPI godot_variant_as_rid(const godot_variant *p_self) { - godot_rid raw_dest; - const Variant *self = (const Variant *)p_self; - RID *dest = (RID *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_callable GDAPI godot_variant_as_callable(const godot_variant *p_self) { - godot_callable raw_dest; - const Variant *self = (const Variant *)p_self; - Callable *dest = (Callable *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_signal GDAPI godot_variant_as_signal(const godot_variant *p_self) { - godot_signal raw_dest; - const Variant *self = (const Variant *)p_self; - Signal *dest = (Signal *)&raw_dest; - *dest = *self; - return raw_dest; -} - -godot_object GDAPI *godot_variant_as_object(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - Object *dest; - dest = *self; - return (godot_object *)dest; -} - -godot_dictionary GDAPI godot_variant_as_dictionary(const godot_variant *p_self) { - godot_dictionary raw_dest; - const Variant *self = (const Variant *)p_self; - Dictionary *dest = (Dictionary *)&raw_dest; - memnew_placement(dest, Dictionary(self->operator Dictionary())); // operator = is overloaded by Dictionary - return raw_dest; -} - -godot_array GDAPI godot_variant_as_array(const godot_variant *p_self) { - godot_array raw_dest; - const Variant *self = (const Variant *)p_self; - Array *dest = (Array *)&raw_dest; - memnew_placement(dest, Array(self->operator Array())); // operator = is overloaded by Array - return raw_dest; -} - -godot_packed_byte_array GDAPI godot_variant_as_packed_byte_array(const godot_variant *p_self) { - godot_packed_byte_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedByteArray *dest = (PackedByteArray *)&raw_dest; - memnew_placement(dest, PackedByteArray(self->operator PackedByteArray())); // operator = is overloaded by PackedByteArray - *dest = *self; - return raw_dest; -} - -godot_packed_int32_array GDAPI godot_variant_as_packed_int32_array(const godot_variant *p_self) { - godot_packed_int32_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedInt32Array *dest = (PackedInt32Array *)&raw_dest; - memnew_placement(dest, PackedInt32Array(self->operator PackedInt32Array())); // operator = is overloaded by PackedInt32Array - *dest = *self; - return raw_dest; -} - -godot_packed_int64_array GDAPI godot_variant_as_packed_int64_array(const godot_variant *p_self) { - godot_packed_int64_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedInt64Array *dest = (PackedInt64Array *)&raw_dest; - memnew_placement(dest, PackedInt64Array(self->operator PackedInt64Array())); // operator = is overloaded by PackedInt64Array - *dest = *self; - return raw_dest; -} - -godot_packed_float32_array GDAPI godot_variant_as_packed_float32_array(const godot_variant *p_self) { - godot_packed_float32_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedFloat32Array *dest = (PackedFloat32Array *)&raw_dest; - memnew_placement(dest, PackedFloat32Array(self->operator PackedFloat32Array())); // operator = is overloaded by PackedFloat32Array - *dest = *self; - return raw_dest; -} - -godot_packed_float64_array GDAPI godot_variant_as_packed_float64_array(const godot_variant *p_self) { - godot_packed_float64_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedFloat64Array *dest = (PackedFloat64Array *)&raw_dest; - memnew_placement(dest, PackedFloat64Array(self->operator PackedFloat64Array())); // operator = is overloaded by PackedFloat64Array - *dest = *self; - return raw_dest; -} - -godot_packed_string_array GDAPI godot_variant_as_packed_string_array(const godot_variant *p_self) { - godot_packed_string_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedStringArray *dest = (PackedStringArray *)&raw_dest; - memnew_placement(dest, PackedStringArray(self->operator PackedStringArray())); // operator = is overloaded by PackedStringArray - *dest = *self; - return raw_dest; -} - -godot_packed_vector2_array GDAPI godot_variant_as_packed_vector2_array(const godot_variant *p_self) { - godot_packed_vector2_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedVector2Array *dest = (PackedVector2Array *)&raw_dest; - memnew_placement(dest, PackedVector2Array(self->operator PackedVector2Array())); // operator = is overloaded by PackedVector2Array - *dest = *self; - return raw_dest; -} - -godot_packed_vector3_array GDAPI godot_variant_as_packed_vector3_array(const godot_variant *p_self) { - godot_packed_vector3_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedVector3Array *dest = (PackedVector3Array *)&raw_dest; - memnew_placement(dest, PackedVector3Array(self->operator PackedVector3Array())); // operator = is overloaded by PackedVector3Array - *dest = *self; - return raw_dest; -} - -godot_packed_color_array GDAPI godot_variant_as_packed_color_array(const godot_variant *p_self) { - godot_packed_color_array raw_dest; - const Variant *self = (const Variant *)p_self; - PackedColorArray *dest = (PackedColorArray *)&raw_dest; - memnew_placement(dest, PackedColorArray(self->operator PackedColorArray())); // operator = is overloaded by PackedColorArray - *dest = *self; - return raw_dest; -} - -void GDAPI godot_variant_destroy(godot_variant *p_self) { - Variant *self = (Variant *)p_self; - self->~Variant(); -} - -// Dynamic interaction. - -void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) { - Variant *self = (Variant *)p_self; - const StringName *method = (const StringName *)p_method; - const Variant **args = (const Variant **)p_args; - Variant ret; - Callable::CallError error; - self->call(*method, args, p_argcount, ret, error); - memnew_placement(r_return, Variant(ret)); - - if (r_error) { - r_error->error = (godot_variant_call_error_error)error.error; - r_error->argument = error.argument; - r_error->expected = (godot_variant_type)error.expected; - } -} - -void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) { - Variant *self = (Variant *)p_self; - const StringName method(p_method); - const Variant **args = (const Variant **)p_args; - Variant ret; - Callable::CallError error; - self->call(method, args, p_argcount, ret, error); - memnew_placement(r_return, Variant(ret)); - - if (r_error) { - r_error->error = (godot_variant_call_error_error)error.error; - r_error->argument = error.argument; - r_error->expected = (godot_variant_type)error.expected; - } -} - -void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) { - Variant::Type type = (Variant::Type)p_type; - const StringName *method = (const StringName *)p_method; - const Variant **args = (const Variant **)p_args; - Variant ret; - Callable::CallError error; - Variant::call_static(type, *method, args, p_argcount, ret, error); - memnew_placement(r_return, Variant(ret)); - - if (r_error) { - r_error->error = (godot_variant_call_error_error)error.error; - r_error->argument = error.argument; - r_error->expected = (godot_variant_type)error.expected; - } -} - -void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, const char *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) { - Variant::Type type = (Variant::Type)p_type; - const StringName method(p_method); - const Variant **args = (const Variant **)p_args; - Variant ret; - Callable::CallError error; - Variant::call_static(type, method, args, p_argcount, ret, error); - memnew_placement(r_return, Variant(ret)); - - if (r_error) { - r_error->error = (godot_variant_call_error_error)error.error; - r_error->argument = error.argument; - r_error->expected = (godot_variant_type)error.expected; - } -} - -void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid) { - Variant::Operator op = (Variant::Operator)p_op; - const Variant *a = (const Variant *)p_a; - const Variant *b = (const Variant *)p_b; - Variant *ret = (Variant *)r_return; - Variant::evaluate(op, *a, *b, *ret, *r_valid); -} - -void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid) { - Variant *self = (Variant *)p_self; - const Variant *key = (const Variant *)p_key; - const Variant *value = (const Variant *)p_value; - - self->set(*key, *value, r_valid); -} - -void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_key, const godot_variant *p_value, bool *r_valid) { - Variant *self = (Variant *)p_self; - const StringName *key = (const StringName *)p_key; - const Variant *value = (const Variant *)p_value; - - self->set_named(*key, *value, *r_valid); -} - -void GDAPI godot_variant_set_named_with_cstring(godot_variant *p_self, const char *p_key, const godot_variant *p_value, bool *r_valid) { - Variant *self = (Variant *)p_self; - const StringName key(p_key); - const Variant *value = (const Variant *)p_value; - - self->set_named(key, *value, *r_valid); -} - -void GDAPI godot_variant_set_keyed(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid) { - Variant *self = (Variant *)p_self; - const Variant *key = (const Variant *)p_key; - const Variant *value = (const Variant *)p_value; - - self->set_keyed(*key, *value, *r_valid); -} - -void GDAPI godot_variant_set_indexed(godot_variant *p_self, godot_int p_index, const godot_variant *p_value, bool *r_valid, bool *r_oob) { - Variant *self = (Variant *)p_self; - const Variant *value = (const Variant *)p_value; - - self->set_indexed(p_index, value, *r_valid, *r_oob); -} - -godot_variant GDAPI godot_variant_get(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - const Variant *key = (const Variant *)p_key; - Variant ret; - - ret = self->get(*key, r_valid); - godot_variant result; - memnew_placement(&result, Variant(ret)); - return result; -} - -godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const godot_string_name *p_key, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - const StringName *key = (const StringName *)p_key; - Variant ret; - - ret = self->get_named(*key, *r_valid); - godot_variant result; - memnew_placement(&result, Variant(ret)); - return result; -} - -godot_variant GDAPI godot_variant_get_named_with_cstring(const godot_variant *p_self, const char *p_key, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - const StringName *key = (const StringName *)p_key; - Variant ret; - - ret = self->get_named(*key, *r_valid); - godot_variant result; - memnew_placement(&result, Variant(ret)); - return result; -} - -godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - const Variant *key = (const Variant *)p_key; - Variant ret; - - ret = self->get_keyed(*key, *r_valid); - godot_variant result; - memnew_placement(&result, Variant(ret)); - return result; -} - -godot_variant GDAPI godot_variant_get_indexed(const godot_variant *p_self, godot_int p_index, bool *r_valid, bool *r_oob) { - const Variant *self = (const Variant *)p_self; - Variant ret; - - ret = self->get_indexed(p_index, *r_valid, *r_oob); - godot_variant result; - memnew_placement(&result, Variant(ret)); - return result; -} - -/// Iteration. -bool GDAPI godot_variant_iter_init(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - Variant *iter = (Variant *)r_iter; - - return self->iter_init(*iter, *r_valid); -} - -bool GDAPI godot_variant_iter_next(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - Variant *iter = (Variant *)r_iter; - - return self->iter_next(*iter, *r_valid); -} - -godot_variant GDAPI godot_variant_iter_get(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - Variant *iter = (Variant *)r_iter; - - Variant result = self->iter_next(*iter, *r_valid); - godot_variant ret; - memnew_placement(&ret, Variant(result)); - return ret; -} - -/// Variant functions. -godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const godot_variant *p_other) { - const Variant *self = (const Variant *)p_self; - const Variant *other = (const Variant *)p_other; - return self->hash_compare(*other); -} - -godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - return self->booleanize(); -} - -void GDAPI godot_variant_blend(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst) { - const Variant *a = (const Variant *)p_a; - const Variant *b = (const Variant *)p_b; - Variant *dst = (Variant *)r_dst; - Variant::blend(*a, *b, p_c, *dst); -} - -void GDAPI godot_variant_interpolate(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst) { - const Variant *a = (const Variant *)p_a; - const Variant *b = (const Variant *)p_b; - Variant *dst = (Variant *)r_dst; - Variant::interpolate(*a, *b, p_c, *dst); -} - -godot_variant GDAPI godot_variant_duplicate(const godot_variant *p_self, godot_bool p_deep) { - const Variant *self = (const Variant *)p_self; - Variant result = self->duplicate(p_deep); - godot_variant ret; - memnew_placement(&ret, Variant(result)); - return ret; -} - -godot_string GDAPI godot_variant_stringify(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - String result = *self; - godot_string ret; - memnew_placement(&ret, String(result)); - return ret; -} - -// Discovery API - -/// Operators -godot_validated_operator_evaluator GDAPI godot_variant_get_validated_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b) { - return (godot_validated_operator_evaluator)Variant::get_validated_operator_evaluator((Variant::Operator)p_operator, (Variant::Type)p_type_a, (Variant::Type)p_type_b); -} - -godot_ptr_operator_evaluator GDAPI godot_variant_get_ptr_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b) { - return (godot_ptr_operator_evaluator)Variant::get_ptr_operator_evaluator((Variant::Operator)p_operator, (Variant::Type)p_type_a, (Variant::Type)p_type_b); -} - -godot_variant_type GDAPI godot_variant_get_operator_return_type(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b) { - return (godot_variant_type)Variant::get_operator_return_type((Variant::Operator)p_operator, (Variant::Type)p_type_a, (Variant::Type)p_type_b); -} - -godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_operator) { - String op_name = Variant::get_operator_name((Variant::Operator)p_operator); - godot_string ret; - memnew_placement(&ret, String(op_name)); - return ret; -} - -/// Built-in Methods - -bool GDAPI godot_variant_has_builtin_method(godot_variant_type p_type, const godot_string_name *p_method) { - return Variant::has_builtin_method((Variant::Type)p_type, *((const StringName *)p_method)); -} - -bool GDAPI godot_variant_has_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method) { - return Variant::has_builtin_method((Variant::Type)p_type, StringName(p_method)); -} - -godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method(godot_variant_type p_type, const godot_string_name *p_method) { - return (godot_validated_builtin_method)Variant::get_validated_builtin_method((Variant::Type)p_type, *((const StringName *)p_method)); -} - -godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method) { - return (godot_validated_builtin_method)Variant::get_validated_builtin_method((Variant::Type)p_type, StringName(p_method)); -} - -godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method(godot_variant_type p_type, const godot_string_name *p_method) { - return (godot_ptr_builtin_method)Variant::get_ptr_builtin_method((Variant::Type)p_type, *((const StringName *)p_method)); -} - -godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method) { - return (godot_ptr_builtin_method)Variant::get_ptr_builtin_method((Variant::Type)p_type, StringName(p_method)); -} - -int GDAPI godot_variant_get_builtin_method_argument_count(godot_variant_type p_type, const godot_string_name *p_method) { - return Variant::get_builtin_method_argument_count((Variant::Type)p_type, *((const StringName *)p_method)); -} - -int GDAPI godot_variant_get_builtin_method_argument_count_with_cstring(godot_variant_type p_type, const char *p_method) { - return Variant::get_builtin_method_argument_count((Variant::Type)p_type, StringName(p_method)); -} - -godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type(godot_variant_type p_type, const godot_string_name *p_method, int p_argument) { - return (godot_variant_type)Variant::get_builtin_method_argument_type((Variant::Type)p_type, *((const StringName *)p_method), p_argument); -} - -godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument) { - return (godot_variant_type)Variant::get_builtin_method_argument_type((Variant::Type)p_type, StringName(p_method), p_argument); -} - -godot_string GDAPI godot_variant_get_builtin_method_argument_name(godot_variant_type p_type, const godot_string_name *p_method, int p_argument) { - String name = Variant::get_builtin_method_argument_name((Variant::Type)p_type, *((const StringName *)p_method), p_argument); - return *(godot_string *)&name; -} - -godot_string GDAPI godot_variant_get_builtin_method_argument_name_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument) { - String name = Variant::get_builtin_method_argument_name((Variant::Type)p_type, StringName(p_method), p_argument); - return *(godot_string *)&name; -} - -bool GDAPI godot_variant_has_builtin_method_return_value(godot_variant_type p_type, const godot_string_name *p_method) { - return Variant::has_builtin_method_return_value((Variant::Type)p_type, *((const StringName *)p_method)); -} - -bool GDAPI godot_variant_has_builtin_method_return_value_with_cstring(godot_variant_type p_type, const char *p_method) { - return Variant::has_builtin_method_return_value((Variant::Type)p_type, StringName(p_method)); -} - -godot_variant_type GDAPI godot_variant_get_builtin_method_return_type(godot_variant_type p_type, const godot_string_name *p_method) { - return (godot_variant_type)Variant::get_builtin_method_return_type((Variant::Type)p_type, *((const StringName *)p_method)); -} - -godot_variant_type GDAPI godot_variant_get_builtin_method_return_type_with_cstring(godot_variant_type p_type, const char *p_method) { - return (godot_variant_type)Variant::get_builtin_method_return_type((Variant::Type)p_type, StringName(p_method)); -} - -bool GDAPI godot_variant_is_builtin_method_const(godot_variant_type p_type, const godot_string_name *p_method) { - return Variant::is_builtin_method_const((Variant::Type)p_type, *((const StringName *)p_method)); -} - -bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type p_type, const char *p_method) { - return Variant::is_builtin_method_const((Variant::Type)p_type, StringName(p_method)); -} - -bool GDAPI godot_variant_is_builtin_method_static(godot_variant_type p_type, const godot_string_name *p_method) { - return Variant::is_builtin_method_static((Variant::Type)p_type, *((const StringName *)p_method)); -} - -bool GDAPI godot_variant_is_builtin_method_static_with_cstring(godot_variant_type p_type, const char *p_method) { - return Variant::is_builtin_method_static((Variant::Type)p_type, StringName(p_method)); -} - -bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method) { - return Variant::is_builtin_method_vararg((Variant::Type)p_type, *((const StringName *)p_method)); -} - -bool GDAPI godot_variant_is_builtin_method_vararg_with_cstring(godot_variant_type p_type, const char *p_method) { - return Variant::is_builtin_method_vararg((Variant::Type)p_type, StringName(p_method)); -} - -int GDAPI godot_variant_get_builtin_method_count(godot_variant_type p_type) { - return Variant::get_builtin_method_count((Variant::Type)p_type); -} - -void GDAPI godot_variant_get_builtin_method_list(godot_variant_type p_type, godot_string_name *r_list) { - List<StringName> list; - Variant::get_builtin_method_list((Variant::Type)p_type, &list); - int i = 0; - for (const StringName &E : list) { - memnew_placement(&r_list[i], StringName(E)); - } -} - -/// Constructors - -int GDAPI godot_variant_get_constructor_count(godot_variant_type p_type) { - return Variant::get_constructor_count((Variant::Type)p_type); -} - -godot_validated_constructor GDAPI godot_variant_get_validated_constructor(godot_variant_type p_type, int p_constructor) { - return (godot_validated_constructor)Variant::get_validated_constructor((Variant::Type)p_type, p_constructor); -} - -godot_ptr_constructor GDAPI godot_variant_get_ptr_constructor(godot_variant_type p_type, int p_constructor) { - return (godot_ptr_constructor)Variant::get_ptr_constructor((Variant::Type)p_type, p_constructor); -} - -int GDAPI godot_variant_get_constructor_argument_count(godot_variant_type p_type, int p_constructor) { - return Variant::get_constructor_argument_count((Variant::Type)p_type, p_constructor); -} - -godot_variant_type GDAPI godot_variant_get_constructor_argument_type(godot_variant_type p_type, int p_constructor, int p_argument) { - return (godot_variant_type)Variant::get_constructor_argument_type((Variant::Type)p_type, p_constructor, p_argument); -} - -godot_string GDAPI godot_variant_get_constructor_argument_name(godot_variant_type p_type, int p_constructor, int p_argument) { - String name = Variant::get_constructor_argument_name((Variant::Type)p_type, p_constructor, p_argument); - godot_string ret; - memnew_placement(&ret, String(name)); - return ret; -} - -void GDAPI godot_variant_construct(godot_variant_type p_type, godot_variant *p_base, const godot_variant **p_args, int p_argcount, godot_variant_call_error *r_error) { - Variant::construct((Variant::Type)p_type, *((Variant *)p_base), (const Variant **)p_args, p_argcount, *((Callable::CallError *)r_error)); -} - -/// Properties. -godot_variant_type GDAPI godot_variant_get_member_type(godot_variant_type p_type, const godot_string_name *p_member) { - return (godot_variant_type)Variant::get_member_type((Variant::Type)p_type, *((const StringName *)p_member)); -} - -godot_variant_type GDAPI godot_variant_get_member_type_with_cstring(godot_variant_type p_type, const char *p_member) { - return (godot_variant_type)Variant::get_member_type((Variant::Type)p_type, StringName(p_member)); -} - -int GDAPI godot_variant_get_member_count(godot_variant_type p_type) { - return Variant::get_member_count((Variant::Type)p_type); -} - -void GDAPI godot_variant_get_member_list(godot_variant_type p_type, godot_string_name *r_list) { - List<StringName> members; - Variant::get_member_list((Variant::Type)p_type, &members); - int i = 0; - for (const StringName &E : members) { - memnew_placement(&r_list[i++], StringName(E)); - } -} - -godot_validated_setter GDAPI godot_variant_get_validated_setter(godot_variant_type p_type, const godot_string_name *p_member) { - return (godot_validated_setter)Variant::get_member_validated_setter((Variant::Type)p_type, *((const StringName *)p_member)); -} - -godot_validated_setter GDAPI godot_variant_get_validated_setter_with_cstring(godot_variant_type p_type, const char *p_member) { - return (godot_validated_setter)Variant::get_member_validated_setter((Variant::Type)p_type, StringName(p_member)); -} - -godot_validated_getter GDAPI godot_variant_get_validated_getter(godot_variant_type p_type, const godot_string_name *p_member) { - return (godot_validated_getter)Variant::get_member_validated_getter((Variant::Type)p_type, *((const StringName *)p_member)); -} - -godot_validated_getter GDAPI godot_variant_get_validated_getter_with_cstring(godot_variant_type p_type, const char *p_member) { - return (godot_validated_getter)Variant::get_member_validated_getter((Variant::Type)p_type, StringName(p_member)); -} - -godot_ptr_setter GDAPI godot_variant_get_ptr_setter(godot_variant_type p_type, const godot_string_name *p_member) { - return (godot_ptr_setter)Variant::get_member_ptr_setter((Variant::Type)p_type, *((const StringName *)p_member)); -} - -godot_ptr_setter GDAPI godot_variant_get_ptr_setter_with_cstring(godot_variant_type p_type, const char *p_member) { - return (godot_ptr_setter)Variant::get_member_ptr_setter((Variant::Type)p_type, StringName(p_member)); -} - -godot_ptr_getter GDAPI godot_variant_get_ptr_getter(godot_variant_type p_type, const godot_string_name *p_member) { - return (godot_ptr_getter)Variant::get_member_ptr_getter((Variant::Type)p_type, *((const StringName *)p_member)); -} - -godot_ptr_getter GDAPI godot_variant_get_ptr_getter_with_cstring(godot_variant_type p_type, const char *p_member) { - return (godot_ptr_getter)Variant::get_member_ptr_getter((Variant::Type)p_type, StringName(p_member)); -} - -/// Indexing. -bool GDAPI godot_variant_has_indexing(godot_variant_type p_type) { - return Variant::has_indexing((Variant::Type)p_type); -} - -godot_variant_type GDAPI godot_variant_get_indexed_element_type(godot_variant_type p_type) { - return (godot_variant_type)Variant::get_indexed_element_type((Variant::Type)p_type); -} - -godot_validated_indexed_setter GDAPI godot_variant_get_validated_indexed_setter(godot_variant_type p_type) { - return (godot_validated_indexed_setter)Variant::get_member_validated_indexed_setter((Variant::Type)p_type); -} - -godot_validated_indexed_getter GDAPI godot_variant_get_validated_indexed_getter(godot_variant_type p_type) { - return (godot_validated_indexed_getter)Variant::get_member_validated_indexed_getter((Variant::Type)p_type); -} - -godot_ptr_indexed_setter GDAPI godot_variant_get_ptr_indexed_setter(godot_variant_type p_type) { - return (godot_ptr_indexed_setter)Variant::get_member_ptr_indexed_setter((Variant::Type)p_type); -} - -godot_ptr_indexed_getter GDAPI godot_variant_get_ptr_indexed_getter(godot_variant_type p_type) { - return (godot_ptr_indexed_getter)Variant::get_member_ptr_indexed_getter((Variant::Type)p_type); -} - -uint64_t GDAPI godot_variant_get_indexed_size(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - return self->get_indexed_size(); -} - -/// Keying. -bool GDAPI godot_variant_is_keyed(godot_variant_type p_type) { - return Variant::is_keyed((Variant::Type)p_type); -} - -godot_validated_keyed_setter GDAPI godot_variant_get_validated_keyed_setter(godot_variant_type p_type) { - return (godot_validated_keyed_setter)Variant::get_member_validated_keyed_setter((Variant::Type)p_type); -} - -godot_validated_keyed_getter GDAPI godot_variant_get_validated_keyed_getter(godot_variant_type p_type) { - return (godot_validated_keyed_getter)Variant::get_member_validated_keyed_getter((Variant::Type)p_type); -} - -godot_validated_keyed_checker GDAPI godot_variant_get_validated_keyed_checker(godot_variant_type p_type) { - return (godot_validated_keyed_checker)Variant::get_member_validated_keyed_checker((Variant::Type)p_type); -} - -godot_ptr_keyed_setter GDAPI godot_variant_get_ptr_keyed_setter(godot_variant_type p_type) { - return (godot_ptr_keyed_setter)Variant::get_member_ptr_keyed_setter((Variant::Type)p_type); -} - -godot_ptr_keyed_getter GDAPI godot_variant_get_ptr_keyed_getter(godot_variant_type p_type) { - return (godot_ptr_keyed_getter)Variant::get_member_ptr_keyed_getter((Variant::Type)p_type); -} - -godot_ptr_keyed_checker GDAPI godot_variant_get_ptr_keyed_checker(godot_variant_type p_type) { - return (godot_ptr_keyed_checker)Variant::get_member_ptr_keyed_checker((Variant::Type)p_type); -} - -/// Constants. -int GDAPI godot_variant_get_constants_count(godot_variant_type p_type) { - return Variant::get_constants_count_for_type((Variant::Type)p_type); -} - -void GDAPI godot_variant_get_constants_list(godot_variant_type p_type, godot_string_name *r_list) { - List<StringName> constants; - int i = 0; - Variant::get_constants_for_type((Variant::Type)p_type, &constants); - for (const StringName &E : constants) { - memnew_placement(&r_list[i++], StringName(E)); - } -} - -bool GDAPI godot_variant_has_constant(godot_variant_type p_type, const godot_string_name *p_constant) { - return Variant::has_constant((Variant::Type)p_type, *((const StringName *)p_constant)); -} - -bool GDAPI godot_variant_has_constant_with_cstring(godot_variant_type p_type, const char *p_constant) { - return Variant::has_constant((Variant::Type)p_type, StringName(p_constant)); -} - -godot_variant GDAPI godot_variant_get_constant_value(godot_variant_type p_type, const godot_string_name *p_constant) { - Variant constant = Variant::get_constant_value((Variant::Type)p_type, *((const StringName *)p_constant)); - godot_variant ret; - memnew_placement(&ret, Variant(constant)); - return ret; -} - -godot_variant GDAPI godot_variant_get_constant_value_with_cstring(godot_variant_type p_type, const char *p_constant) { - Variant constant = Variant::get_constant_value((Variant::Type)p_type, StringName(p_constant)); - godot_variant ret; - memnew_placement(&ret, Variant(constant)); - return ret; -} - -/// Utilities. -bool GDAPI godot_variant_has_utility_function(const godot_string_name *p_function) { - return Variant::has_utility_function(*((const StringName *)p_function)); -} - -bool GDAPI godot_variant_has_utility_function_with_cstring(const char *p_function) { - return Variant::has_utility_function(StringName(p_function)); -} - -void GDAPI godot_variant_call_utility_function(const godot_string_name *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error) { - const StringName *function = (const StringName *)p_function; - Variant *ret = (Variant *)r_ret; - const Variant **args = (const Variant **)p_args; - Callable::CallError error; - - Variant::call_utility_function(*function, ret, args, p_argument_count, error); - - if (r_error) { - r_error->error = (godot_variant_call_error_error)error.error; - r_error->argument = error.argument; - r_error->expected = (godot_variant_type)error.expected; - } -} - -void GDAPI godot_variant_call_utility_function_with_cstring(const char *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error) { - Variant *ret = (Variant *)r_ret; - const Variant **args = (const Variant **)p_args; - Callable::CallError error; - - Variant::call_utility_function(StringName(p_function), ret, args, p_argument_count, error); - - if (r_error) { - r_error->error = (godot_variant_call_error_error)error.error; - r_error->argument = error.argument; - r_error->expected = (godot_variant_type)error.expected; - } -} - -godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function(const godot_string_name *p_function) { - return (godot_ptr_utility_function)Variant::get_ptr_utility_function(*((const StringName *)p_function)); -} - -godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function_with_cstring(const char *p_function) { - return (godot_ptr_utility_function)Variant::get_ptr_utility_function(StringName(p_function)); -} - -godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function(const godot_string_name *p_function) { - return (godot_validated_utility_function)Variant::get_validated_utility_function(*((const StringName *)p_function)); -} - -godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function_with_cstring(const char *p_function) { - return (godot_validated_utility_function)Variant::get_validated_utility_function(StringName(p_function)); -} - -godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type(const godot_string_name *p_function) { - return (godot_variant_utility_function_type)Variant::get_utility_function_type(*((const StringName *)p_function)); -} - -godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type_with_cstring(const char *p_function) { - return (godot_variant_utility_function_type)Variant::get_utility_function_type(StringName(p_function)); -} - -int GDAPI godot_variant_get_utility_function_argument_count(const godot_string_name *p_function) { - return Variant::get_utility_function_argument_count(*((const StringName *)p_function)); -} - -int GDAPI godot_variant_get_utility_function_argument_count_with_cstring(const char *p_function) { - return Variant::get_utility_function_argument_count(StringName(p_function)); -} - -godot_variant_type GDAPI godot_variant_get_utility_function_argument_type(const godot_string_name *p_function, int p_argument) { - return (godot_variant_type)Variant::get_utility_function_argument_type(*((const StringName *)p_function), p_argument); -} - -godot_variant_type GDAPI godot_variant_get_utility_function_argument_type_with_cstring(const char *p_function, int p_argument) { - return (godot_variant_type)Variant::get_utility_function_argument_type(StringName(p_function), p_argument); -} - -godot_string GDAPI godot_variant_get_utility_function_argument_name(const godot_string_name *p_function, int p_argument) { - String argument_name = Variant::get_utility_function_argument_name(*((const StringName *)p_function), p_argument); - godot_string ret; - memnew_placement(&ret, String(argument_name)); - return ret; -} - -godot_string GDAPI godot_variant_get_utility_function_argument_name_with_cstring(const char *p_function, int p_argument) { - String argument_name = Variant::get_utility_function_argument_name(StringName(p_function), p_argument); - godot_string ret; - memnew_placement(&ret, String(argument_name)); - return ret; -} - -bool GDAPI godot_variant_has_utility_function_return_value(const godot_string_name *p_function) { - return Variant::has_utility_function_return_value(*((const StringName *)p_function)); -} - -bool GDAPI godot_variant_has_utility_function_return_value_with_cstring(const char *p_function) { - return Variant::has_utility_function_return_value(StringName(p_function)); -} - -godot_variant_type GDAPI godot_variant_get_utility_function_return_type(const godot_string_name *p_function) { - return (godot_variant_type)Variant::get_utility_function_return_type(*((const StringName *)p_function)); -} - -godot_variant_type GDAPI godot_variant_get_utility_function_return_type_with_cstring(const char *p_function) { - return (godot_variant_type)Variant::get_utility_function_return_type(StringName(p_function)); -} - -bool GDAPI godot_variant_is_utility_function_vararg(const godot_string_name *p_function) { - return Variant::is_utility_function_vararg(*((const StringName *)p_function)); -} - -bool GDAPI godot_variant_is_utility_function_vararg_with_cstring(const char *p_function) { - return Variant::is_utility_function_vararg(StringName(p_function)); -} - -int GDAPI godot_variant_get_utility_function_count() { - return Variant::get_utility_function_count(); -} - -void GDAPI godot_variant_get_utility_function_list(godot_string_name *r_functions) { - List<StringName> functions; - godot_string_name *func = r_functions; - Variant::get_utility_function_list(&functions); - - for (const StringName &E : functions) { - memnew_placement(func++, StringName(E)); - } -} - -// Introspection. - -godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_self) { - const Variant *self = (const Variant *)p_self; - return (godot_variant_type)self->get_type(); -} - -bool GDAPI godot_variant_has_method(const godot_variant *p_self, const godot_string_name *p_method) { - const Variant *self = (const Variant *)p_self; - const StringName *method = (const StringName *)p_method; - return self->has_method(*method); -} - -bool GDAPI godot_variant_has_member(godot_variant_type p_type, const godot_string_name *p_member) { - return Variant::has_member((Variant::Type)p_type, *((const StringName *)p_member)); -} - -bool GDAPI godot_variant_has_key(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) { - const Variant *self = (const Variant *)p_self; - const Variant *key = (const Variant *)p_key; - return self->has_key(*key, *r_valid); -} - -godot_string GDAPI godot_variant_get_type_name(godot_variant_type p_type) { - String name = Variant::get_type_name((Variant::Type)p_type); - godot_string ret; - memnew_placement(&ret, String(name)); - return ret; -} - -bool GDAPI godot_variant_can_convert(godot_variant_type p_from, godot_variant_type p_to) { - return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to); -} - -bool GDAPI godot_variant_can_convert_strict(godot_variant_type p_from, godot_variant_type p_to) { - return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp deleted file mode 100644 index 6a01a7ad59..0000000000 --- a/modules/gdnative/gdnative/vector2.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************/ -/* vector2.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 "gdnative/vector2.h" - -#include "core/math/vector2.h" - -static_assert(sizeof(godot_vector2) == sizeof(Vector2), "Vector2 size mismatch"); -static_assert(sizeof(godot_vector2i) == sizeof(Vector2i), "Vector2i size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_vector2_new(godot_vector2 *p_self) { - memnew_placement(p_self, Vector2); -} - -void GDAPI godot_vector2_new_copy(godot_vector2 *r_dest, const godot_vector2 *p_src) { - memnew_placement(r_dest, Vector2(*(Vector2 *)p_src)); -} - -void GDAPI godot_vector2i_new(godot_vector2i *p_self) { - memnew_placement(p_self, Vector2i); -} - -void GDAPI godot_vector2i_new_copy(godot_vector2i *r_dest, const godot_vector2i *p_src) { - memnew_placement(r_dest, Vector2i(*(Vector2i *)p_src)); -} - -godot_real_t GDAPI *godot_vector2_operator_index(godot_vector2 *p_self, godot_int p_index) { - Vector2 *self = (Vector2 *)p_self; - return (godot_real_t *)&self->operator[](p_index); -} - -const godot_real_t GDAPI *godot_vector2_operator_index_const(const godot_vector2 *p_self, godot_int p_index) { - const Vector2 *self = (const Vector2 *)p_self; - return (const godot_real_t *)&self->operator[](p_index); -} - -int32_t GDAPI *godot_vector2i_operator_index(godot_vector2i *p_self, godot_int p_index) { - Vector2i *self = (Vector2i *)p_self; - return (int32_t *)&self->operator[](p_index); -} - -const int32_t GDAPI *godot_vector2i_operator_index_const(const godot_vector2i *p_self, godot_int p_index) { - const Vector2i *self = (const Vector2i *)p_self; - return (const int32_t *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative/vector3.cpp b/modules/gdnative/gdnative/vector3.cpp deleted file mode 100644 index fb426c8ac4..0000000000 --- a/modules/gdnative/gdnative/vector3.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************/ -/* vector3.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 "gdnative/vector3.h" - -#include "core/math/vector3.h" - -static_assert(sizeof(godot_vector3) == sizeof(Vector3), "Vector3 size mismatch"); -static_assert(sizeof(godot_vector3i) == sizeof(Vector3i), "Vector3i size mismatch"); - -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_vector3_new(godot_vector3 *p_self) { - memnew_placement(p_self, Vector3); -} - -void GDAPI godot_vector3_new_copy(godot_vector3 *r_dest, const godot_vector3 *p_src) { - memnew_placement(r_dest, Vector3(*(Vector3 *)p_src)); -} - -void GDAPI godot_vector3i_new(godot_vector3i *p_self) { - memnew_placement(p_self, Vector3i); -} - -void GDAPI godot_vector3i_new_copy(godot_vector3i *r_dest, const godot_vector3i *p_src) { - memnew_placement(r_dest, Vector3i(*(Vector3i *)p_src)); -} - -godot_real_t GDAPI *godot_vector3_operator_index(godot_vector3 *p_self, godot_int p_index) { - Vector3 *self = (Vector3 *)p_self; - return (godot_real_t *)&self->operator[](p_index); -} - -const godot_real_t GDAPI *godot_vector3_operator_index_const(const godot_vector3 *p_self, godot_int p_index) { - const Vector3 *self = (const Vector3 *)p_self; - return (const godot_real_t *)&self->operator[](p_index); -} - -int32_t GDAPI *godot_vector3i_operator_index(godot_vector3i *p_self, godot_int p_index) { - Vector3i *self = (Vector3i *)p_self; - return (int32_t *)&self->operator[](p_index); -} - -const int32_t GDAPI *godot_vector3i_operator_index_const(const godot_vector3i *p_self, godot_int p_index) { - const Vector3i *self = (const Vector3i *)p_self; - return (const int32_t *)&self->operator[](p_index); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json deleted file mode 100644 index cf1c7dc01f..0000000000 --- a/modules/gdnative/gdnative_api.json +++ /dev/null @@ -1,5108 +0,0 @@ -{ - "core": { - "type": "CORE", - "version": { - "major": 4, - "minor": 0 - }, - "next": null, - "api": [ - { - "name": "godot_object_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_object *", - "p_o" - ] - ] - }, - { - "name": "godot_global_get_singleton", - "return_type": "godot_object *", - "arguments": [ - [ - "char *", - "p_name" - ] - ] - }, - { - "name": "godot_method_bind_get_method", - "return_type": "godot_method_bind *", - "arguments": [ - [ - "const char *", - "p_classname" - ], - [ - "const char *", - "p_methodname" - ] - ] - }, - { - "name": "godot_method_bind_ptrcall", - "return_type": "void", - "arguments": [ - [ - "godot_method_bind *", - "p_method_bind" - ], - [ - "godot_object *", - "p_instance" - ], - [ - "const void **", - "p_args" - ], - [ - "void *", - "p_ret" - ] - ] - }, - { - "name": "godot_method_bind_call", - "return_type": "godot_variant", - "arguments": [ - [ - "godot_method_bind *", - "p_method_bind" - ], - [ - "godot_object *", - "p_instance" - ], - [ - "const godot_variant **", - "p_args" - ], - [ - "const int", - "p_arg_count" - ], - [ - "godot_variant_call_error *", - "p_call_error" - ] - ] - }, - { - "name": "godot_get_class_constructor", - "return_type": "godot_class_constructor", - "arguments": [ - [ - "const char *", - "p_classname" - ] - ] - }, - { - "name": "godot_get_global_constants", - "return_type": "godot_dictionary", - "arguments": [] - }, - { - "name": "godot_register_native_call_type", - "return_type": "void", - "arguments": [ - [ - "const char *", - "call_type" - ], - [ - "native_call_cb", - "p_callback" - ] - ] - }, - { - "name": "godot_alloc", - "return_type": "void *", - "arguments": [ - [ - "int", - "p_bytes" - ] - ] - }, - { - "name": "godot_realloc", - "return_type": "void *", - "arguments": [ - [ - "void *", - "p_ptr" - ], - [ - "int", - "p_bytes" - ] - ] - }, - { - "name": "godot_free", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_ptr" - ] - ] - }, - { - "name": "godot_print_error", - "return_type": "void", - "arguments": [ - [ - "const char *", - "p_description" - ], - [ - "const char *", - "p_function" - ], - [ - "const char *", - "p_file" - ], - [ - "int", - "p_line" - ] - ] - }, - { - "name": "godot_print_warning", - "return_type": "void", - "arguments": [ - [ - "const char *", - "p_description" - ], - [ - "const char *", - "p_function" - ], - [ - "const char *", - "p_file" - ], - [ - "int", - "p_line" - ] - ] - }, - { - "name": "godot_print_script_error", - "return_type": "void", - "arguments": [ - [ - "const char *", - "p_description" - ], - [ - "const char *", - "p_function" - ], - [ - "const char *", - "p_file" - ], - [ - "int", - "p_line" - ] - ] - }, - { - "name": "godot_get_class_tag", - "return_type": "void *", - "arguments": [ - [ - "const godot_string_name *", - "p_class" - ] - ] - }, - { - "name": "godot_object_cast_to", - "return_type": "godot_object *", - "arguments": [ - [ - "const godot_object *", - "p_object" - ], - [ - "void *", - "p_class_tag" - ] - ] - }, - { - "name": "godot_instance_from_id", - "return_type": "godot_object *", - "arguments": [ - [ - "uint64_t", - "p_instance_id" - ] - ] - }, - { - "name": "godot_object_get_instance_id", - "return_type": "uint64_t", - "arguments": [ - [ - "const godot_object *", - "p_object" - ] - ] - }, - { - "name": "godot_variant_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_variant *", - "p_src" - ] - ] - }, - { - "name": "godot_variant_new_nil", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ] - ] - }, - { - "name": "godot_variant_new_bool", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_bool", - "p_b" - ] - ] - }, - { - "name": "godot_variant_new_int", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const int64_t", - "p_i" - ] - ] - }, - { - "name": "godot_variant_new_float", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const double", - "p_f" - ] - ] - }, - { - "name": "godot_variant_new_string", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_string *", - "p_s" - ] - ] - }, - { - "name": "godot_variant_new_string_name", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_string_name *", - "p_s" - ] - ] - }, - { - "name": "godot_variant_new_vector2", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_vector2 *", - "p_v2" - ] - ] - }, - { - "name": "godot_variant_new_vector2i", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_vector2i *", - "p_v2" - ] - ] - }, - { - "name": "godot_variant_new_rect2", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_rect2 *", - "p_rect2" - ] - ] - }, - { - "name": "godot_variant_new_rect2i", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_rect2i *", - "p_rect2" - ] - ] - }, - { - "name": "godot_variant_new_vector3", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_vector3 *", - "p_v3" - ] - ] - }, - { - "name": "godot_variant_new_vector3i", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_vector3i *", - "p_v3" - ] - ] - }, - { - "name": "godot_variant_new_transform2d", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_transform2d *", - "p_t2d" - ] - ] - }, - { - "name": "godot_variant_new_plane", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_plane *", - "p_plane" - ] - ] - }, - { - "name": "godot_variant_new_quaternion", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_quaternion *", - "p_quaternion" - ] - ] - }, - { - "name": "godot_variant_new_aabb", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_aabb *", - "p_aabb" - ] - ] - }, - { - "name": "godot_variant_new_basis", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_basis *", - "p_basis" - ] - ] - }, - { - "name": "godot_variant_new_transform3d", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_transform3d *", - "p_trans" - ] - ] - }, - { - "name": "godot_variant_new_color", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_color *", - "p_color" - ] - ] - }, - { - "name": "godot_variant_new_node_path", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_node_path *", - "p_np" - ] - ] - }, - { - "name": "godot_variant_new_rid", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_rid *", - "p_rid" - ] - ] - }, - { - "name": "godot_variant_new_object", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_object *", - "p_obj" - ] - ] - }, - { - "name": "godot_variant_new_callable", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_callable *", - "p_cb" - ] - ] - }, - { - "name": "godot_variant_new_signal", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_signal *", - "p_signal" - ] - ] - }, - { - "name": "godot_variant_new_dictionary", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_dictionary *", - "p_dict" - ] - ] - }, - { - "name": "godot_variant_new_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_array *", - "p_arr" - ] - ] - }, - { - "name": "godot_variant_new_packed_byte_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_byte_array *", - "p_pba" - ] - ] - }, - { - "name": "godot_variant_new_packed_int32_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_int32_array *", - "p_pia" - ] - ] - }, - { - "name": "godot_variant_new_packed_int64_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_int64_array *", - "p_pia" - ] - ] - }, - { - "name": "godot_variant_new_packed_float32_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_float32_array *", - "p_pra" - ] - ] - }, - { - "name": "godot_variant_new_packed_float64_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_float64_array *", - "p_pra" - ] - ] - }, - { - "name": "godot_variant_new_packed_string_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_string_array *", - "p_psa" - ] - ] - }, - { - "name": "godot_variant_new_packed_vector2_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_vector2_array *", - "p_pv2a" - ] - ] - }, - { - "name": "godot_variant_new_packed_vector3_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_vector3_array *", - "p_pv3a" - ] - ] - }, - { - "name": "godot_variant_new_packed_color_array", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "r_dest" - ], - [ - "const godot_packed_color_array *", - "p_pca" - ] - ] - }, - { - "name": "godot_variant_as_bool", - "return_type": "godot_bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_int", - "return_type": "int64_t", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_float", - "return_type": "double", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_string", - "return_type": "godot_string", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_string_name", - "return_type": "godot_string_name", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_vector2", - "return_type": "godot_vector2", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_vector2i", - "return_type": "godot_vector2i", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_rect2", - "return_type": "godot_rect2", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_rect2i", - "return_type": "godot_rect2i", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_vector3", - "return_type": "godot_vector3", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_vector3i", - "return_type": "godot_vector3i", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_transform2d", - "return_type": "godot_transform2d", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_plane", - "return_type": "godot_plane", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_quaternion", - "return_type": "godot_quaternion", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_aabb", - "return_type": "godot_aabb", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_basis", - "return_type": "godot_basis", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_transform3d", - "return_type": "godot_transform3d", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_color", - "return_type": "godot_color", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_node_path", - "return_type": "godot_node_path", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_rid", - "return_type": "godot_rid", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_object", - "return_type": "godot_object *", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_callable", - "return_type": "godot_callable", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_signal", - "return_type": "godot_signal", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_dictionary", - "return_type": "godot_dictionary", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_array", - "return_type": "godot_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_byte_array", - "return_type": "godot_packed_byte_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_int32_array", - "return_type": "godot_packed_int32_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_int64_array", - "return_type": "godot_packed_int64_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_float32_array", - "return_type": "godot_packed_float32_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_float64_array", - "return_type": "godot_packed_float64_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_string_array", - "return_type": "godot_packed_string_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_vector2_array", - "return_type": "godot_packed_vector2_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_vector3_array", - "return_type": "godot_packed_vector3_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_as_packed_color_array", - "return_type": "godot_packed_color_array", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_call", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "const godot_string_name *", - "p_method" - ], - [ - "const godot_variant **", - "p_args" - ], - [ - "const godot_int", - "p_argument_count" - ], - [ - "godot_variant *", - "r_return" - ], - [ - "godot_variant_call_error *", - "r_error" - ] - ] - }, - { - "name": "godot_variant_call_with_cstring", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "const char *", - "p_method" - ], - [ - "const godot_variant **", - "p_args" - ], - [ - "const godot_int", - "p_argument_count" - ], - [ - "godot_variant *", - "r_return" - ], - [ - "godot_variant_call_error *", - "r_error" - ] - ] - }, - { - "name": "godot_variant_evaluate", - "return_type": "void", - "arguments": [ - [ - "godot_variant_operator", - "p_op" - ], - [ - "const godot_variant *", - "p_a" - ], - [ - "const godot_variant *", - "p_b" - ], - [ - "godot_variant *", - "r_return" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_set", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ], - [ - "const godot_variant *", - "p_value" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_set_named", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "const godot_string_name *", - "p_key" - ], - [ - "const godot_variant *", - "p_value" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_set_named_with_cstring", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "const char *", - "p_key" - ], - [ - "const godot_variant *", - "p_value" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_set_keyed", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ], - [ - "const godot_variant *", - "p_value" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_set_indexed", - "return_type": "void", - "arguments": [ - [ - "godot_variant *", - "p_self" - ], - [ - "godot_int", - "p_index" - ], - [ - "const godot_variant *", - "p_value" - ], - [ - "bool *", - "r_valid" - ], - [ - "bool *", - "r_oob" - ] - ] - }, - { - "name": "godot_variant_get", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_get_named", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const godot_string_name *", - "p_key" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_get_named_with_cstring", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const char *", - "p_key" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_get_keyed", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_get_indexed", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "godot_int", - "p_index" - ], - [ - "bool *", - "r_valid" - ], - [ - "bool *", - "r_oob" - ] - ] - }, - { - "name": "godot_variant_iter_init", - "return_type": "bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "godot_variant *", - "r_iter" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_iter_next", - "return_type": "bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "godot_variant *", - "r_iter" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_iter_get", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "godot_variant *", - "r_iter" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_hash_compare", - "return_type": "godot_bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const godot_variant *", - "p_other" - ] - ] - }, - { - "name": "godot_variant_booleanize", - "return_type": "godot_bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_blend", - "return_type": "void", - "arguments": [ - [ - "const godot_variant *", - "p_a" - ], - [ - "const godot_variant *", - "p_b" - ], - [ - "float", - "p_c" - ], - [ - "godot_variant *", - "r_dst" - ] - ] - }, - { - "name": "godot_variant_interpolate", - "return_type": "void", - "arguments": [ - [ - "const godot_variant *", - "p_a" - ], - [ - "const godot_variant *", - "p_b" - ], - [ - "float", - "p_c" - ], - [ - "godot_variant *", - "r_dst" - ] - ] - }, - { - "name": "godot_variant_duplicate", - "return_type": "godot_variant", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "godot_bool", - "p_deep" - ] - ] - }, - { - "name": "godot_variant_stringify", - "return_type": "godot_string", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_get_validated_operator_evaluator", - "return_type": "godot_validated_operator_evaluator", - "arguments": [ - [ - "godot_variant_operator", - "p_operator" - ], - [ - "godot_variant_type", - "p_type_a" - ], - [ - "godot_variant_type", - "p_type_b" - ] - ] - }, - { - "name": "godot_variant_get_ptr_operator_evaluator", - "return_type": "godot_ptr_operator_evaluator", - "arguments": [ - [ - "godot_variant_operator", - "p_operator" - ], - [ - "godot_variant_type", - "p_type_a" - ], - [ - "godot_variant_type", - "p_type_b" - ] - ] - }, - { - "name": "godot_variant_get_operator_return_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_operator", - "p_operator" - ], - [ - "godot_variant_type", - "p_type_a" - ], - [ - "godot_variant_type", - "p_type_b" - ] - ] - }, - { - "name": "godot_variant_get_operator_name", - "return_type": "godot_string", - "arguments": [ - [ - "godot_variant_operator", - "p_operator" - ] - ] - }, - { - "name": "godot_variant_has_builtin_method", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_has_builtin_method_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_validated_builtin_method", - "return_type": "godot_validated_builtin_method", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_validated_builtin_method_with_cstring", - "return_type": "godot_validated_builtin_method", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_ptr_builtin_method", - "return_type": "godot_ptr_builtin_method", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_ptr_builtin_method_with_cstring", - "return_type": "godot_ptr_builtin_method", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_argument_count", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_argument_count_with_cstring", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_argument_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_argument_type_with_cstring", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_argument_name", - "return_type": "godot_string", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_argument_name_with_cstring", - "return_type": "godot_string", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_has_builtin_method_return_value", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_has_builtin_method_return_value_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_return_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_return_type_with_cstring", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_is_builtin_method_const", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_is_builtin_method_const_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_is_builtin_method_static", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_is_builtin_method_static_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_is_builtin_method_vararg", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_is_builtin_method_vararg_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_count", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_builtin_method_list", - "return_type": "void", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "godot_string_name *", - "r_list" - ] - ] - }, - { - "name": "godot_variant_get_constructor_count", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_validated_constructor", - "return_type": "godot_validated_constructor", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "int", - "p_constructor" - ] - ] - }, - { - "name": "godot_variant_get_ptr_constructor", - "return_type": "godot_ptr_constructor", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "int", - "p_constructor" - ] - ] - }, - { - "name": "godot_variant_get_constructor_argument_count", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "int", - "p_constructor" - ] - ] - }, - { - "name": "godot_variant_get_constructor_argument_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "int", - "p_constructor" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_constructor_argument_name", - "return_type": "godot_string", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "int", - "p_constructor" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_construct", - "return_type": "void", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "godot_variant *", - "p_base" - ], - [ - "const godot_variant **", - "p_args" - ], - [ - "int", - "p_argument_count" - ], - [ - "godot_variant_call_error *", - "r_error" - ] - ] - }, - { - "name": "godot_variant_get_member_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_member_type_with_cstring", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_member_count", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_member_list", - "return_type": "void", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "godot_string_name *", - "r_list" - ] - ] - }, - { - "name": "godot_variant_get_validated_setter", - "return_type": "godot_validated_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_validated_setter_with_cstring", - "return_type": "godot_validated_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_validated_getter", - "return_type": "godot_validated_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_validated_getter_with_cstring", - "return_type": "godot_validated_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_ptr_setter", - "return_type": "godot_ptr_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_ptr_setter_with_cstring", - "return_type": "godot_ptr_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_ptr_getter", - "return_type": "godot_ptr_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_get_ptr_getter_with_cstring", - "return_type": "godot_ptr_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_has_indexing", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_indexed_element_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_validated_indexed_setter", - "return_type": "godot_validated_indexed_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_validated_indexed_getter", - "return_type": "godot_validated_indexed_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_ptr_indexed_setter", - "return_type": "godot_ptr_indexed_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_ptr_indexed_getter", - "return_type": "godot_ptr_indexed_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_indexed_size", - "return_type": "uint64_t", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_is_keyed", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_validated_keyed_setter", - "return_type": "godot_validated_keyed_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_validated_keyed_getter", - "return_type": "godot_validated_keyed_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_validated_keyed_checker", - "return_type": "godot_validated_keyed_checker", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_ptr_keyed_setter", - "return_type": "godot_ptr_keyed_setter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_ptr_keyed_getter", - "return_type": "godot_ptr_keyed_getter", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_ptr_keyed_checker", - "return_type": "godot_ptr_keyed_checker", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_constants_count", - "return_type": "int", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_get_constants_list", - "return_type": "void", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "godot_string_name *", - "r_list" - ] - ] - }, - { - "name": "godot_variant_has_constant", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_constant" - ] - ] - }, - { - "name": "godot_variant_has_constant_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_constant" - ] - ] - }, - { - "name": "godot_variant_get_constant_value", - "return_type": "godot_variant", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_constant" - ] - ] - }, - { - "name": "godot_variant_get_constant_value_with_cstring", - "return_type": "godot_variant", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const char *", - "p_constant" - ] - ] - }, - { - "name": "godot_variant_has_utility_function", - "return_type": "bool", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_has_utility_function_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_call_utility_function", - "return_type": "void", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ], - [ - "godot_variant *", - "r_ret" - ], - [ - "const godot_variant **", - "p_args" - ], - [ - "int", - "p_argument_count" - ], - [ - "godot_variant_call_error *", - "r_error" - ] - ] - }, - { - "name": "godot_variant_call_utility_function_with_cstring", - "return_type": "void", - "arguments": [ - [ - "const char *", - "p_function" - ], - [ - "godot_variant *", - "r_ret" - ], - [ - "const godot_variant **", - "p_args" - ], - [ - "int", - "p_argument_count" - ], - [ - "godot_variant_call_error *", - "r_error" - ] - ] - }, - { - "name": "godot_variant_get_ptr_utility_function", - "return_type": "godot_ptr_utility_function", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_ptr_utility_function_with_cstring", - "return_type": "godot_ptr_utility_function", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_validated_utility_function", - "return_type": "godot_validated_utility_function", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_validated_utility_function_with_cstring", - "return_type": "godot_validated_utility_function", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_type", - "return_type": "godot_variant_utility_function_type", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_type_with_cstring", - "return_type": "godot_variant_utility_function_type", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_argument_count", - "return_type": "int", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_argument_count_with_cstring", - "return_type": "int", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_argument_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_argument_type_with_cstring", - "return_type": "godot_variant_type", - "arguments": [ - [ - "const char *", - "p_function" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_argument_name", - "return_type": "godot_string", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_argument_name_with_cstring", - "return_type": "godot_string", - "arguments": [ - [ - "const char *", - "p_function" - ], - [ - "int", - "p_argument" - ] - ] - }, - { - "name": "godot_variant_has_utility_function_return_value", - "return_type": "bool", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_has_utility_function_return_value_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_return_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_return_type_with_cstring", - "return_type": "godot_variant_type", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_is_utility_function_vararg", - "return_type": "bool", - "arguments": [ - [ - "const godot_string_name *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_is_utility_function_vararg_with_cstring", - "return_type": "bool", - "arguments": [ - [ - "const char *", - "p_function" - ] - ] - }, - { - "name": "godot_variant_get_utility_function_count", - "return_type": "int", - "arguments": [] - }, - { - "name": "godot_variant_get_utility_function_list", - "return_type": "void", - "arguments": [ - [ - "godot_string_name *", - "r_functions" - ] - ] - }, - { - "name": "godot_variant_get_type", - "return_type": "godot_variant_type", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ] - ] - }, - { - "name": "godot_variant_has_method", - "return_type": "bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const godot_string_name *", - "p_method" - ] - ] - }, - { - "name": "godot_variant_has_member", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ], - [ - "const godot_string_name *", - "p_member" - ] - ] - }, - { - "name": "godot_variant_has_key", - "return_type": "bool", - "arguments": [ - [ - "const godot_variant *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ], - [ - "bool *", - "r_valid" - ] - ] - }, - { - "name": "godot_variant_get_type_name", - "return_type": "godot_string", - "arguments": [ - [ - "godot_variant_type", - "p_type" - ] - ] - }, - { - "name": "godot_variant_can_convert", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_from" - ], - [ - "godot_variant_type", - "p_to" - ] - ] - }, - { - "name": "godot_variant_can_convert_strict", - "return_type": "bool", - "arguments": [ - [ - "godot_variant_type", - "p_from" - ], - [ - "godot_variant_type", - "p_to" - ] - ] - }, - { - "name": "godot_aabb_new", - "return_type": "void", - "arguments": [ - [ - "godot_aabb *", - "p_self" - ] - ] - }, - { - "name": "godot_aabb_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_aabb *", - "r_dest" - ], - [ - "const godot_aabb *", - "p_src" - ] - ] - }, - { - "name": "godot_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_array *", - "p_self" - ] - ] - }, - { - "name": "godot_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_array *", - "r_dest" - ], - [ - "const godot_array *", - "p_src" - ] - ] - }, - { - "name": "godot_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_array *", - "p_self" - ] - ] - }, - { - "name": "godot_array_operator_index", - "return_type": "godot_variant *", - "arguments": [ - [ - "godot_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_array_operator_index_const", - "return_type": "const godot_variant *", - "arguments": [ - [ - "const godot_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_basis_new", - "return_type": "void", - "arguments": [ - [ - "godot_basis *", - "p_self" - ] - ] - }, - { - "name": "godot_basis_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_basis *", - "r_dest" - ], - [ - "const godot_basis *", - "p_src" - ] - ] - }, - { - "name": "godot_basis_operator_index", - "return_type": "godot_vector3 *", - "arguments": [ - [ - "godot_basis *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_basis_operator_index_const", - "return_type": "const godot_vector3 *", - "arguments": [ - [ - "const godot_basis *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_callable_new", - "return_type": "void", - "arguments": [ - [ - "godot_callable *", - "p_self" - ] - ] - }, - { - "name": "godot_callable_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_callable *", - "r_dest" - ], - [ - "const godot_callable *", - "p_src" - ] - ] - }, - { - "name": "godot_callable_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_callable *", - "p_self" - ] - ] - }, - { - "name": "godot_color_new", - "return_type": "void", - "arguments": [ - [ - "godot_color *", - "p_self" - ] - ] - }, - { - "name": "godot_color_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_color *", - "r_dest" - ], - [ - "const godot_color *", - "p_src" - ] - ] - }, - { - "name": "godot_color_operator_index", - "return_type": "float *", - "arguments": [ - [ - "godot_color *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_color_operator_index_const", - "return_type": "const float *", - "arguments": [ - [ - "const godot_color *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_dictionary_new", - "return_type": "void", - "arguments": [ - [ - "godot_dictionary *", - "p_self" - ] - ] - }, - { - "name": "godot_dictionary_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_dictionary *", - "r_dest" - ], - [ - "const godot_dictionary *", - "p_src" - ] - ] - }, - { - "name": "godot_dictionary_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_dictionary *", - "p_self" - ] - ] - }, - { - "name": "godot_dictionary_operator_index", - "return_type": "godot_variant *", - "arguments": [ - [ - "godot_dictionary *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ] - ] - }, - { - "name": "godot_dictionary_operator_index_const", - "return_type": "const godot_variant *", - "arguments": [ - [ - "const godot_dictionary *", - "p_self" - ], - [ - "const godot_variant *", - "p_key" - ] - ] - }, - { - "name": "godot_node_path_new", - "return_type": "void", - "arguments": [ - [ - "godot_node_path *", - "p_self" - ] - ] - }, - { - "name": "godot_node_path_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_node_path *", - "r_dest" - ], - [ - "const godot_node_path *", - "p_src" - ] - ] - }, - { - "name": "godot_node_path_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_node_path *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_byte_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_byte_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_byte_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_byte_array *", - "r_dest" - ], - [ - "const godot_packed_byte_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_byte_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_byte_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_byte_array_operator_index", - "return_type": "uint8_t *", - "arguments": [ - [ - "godot_packed_byte_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_byte_array_operator_index_const", - "return_type": "const uint8_t *", - "arguments": [ - [ - "const godot_packed_byte_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_int32_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_int32_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_int32_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_int32_array *", - "r_dest" - ], - [ - "const godot_packed_int32_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_int32_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_int32_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_int32_array_operator_index", - "return_type": "int32_t *", - "arguments": [ - [ - "godot_packed_int32_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_int32_array_operator_index_const", - "return_type": "const int32_t *", - "arguments": [ - [ - "const godot_packed_int32_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_int64_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_int64_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_int64_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_int64_array *", - "r_dest" - ], - [ - "const godot_packed_int64_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_int64_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_int64_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_int64_array_operator_index", - "return_type": "int64_t *", - "arguments": [ - [ - "godot_packed_int64_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_int64_array_operator_index_const", - "return_type": "const int64_t *", - "arguments": [ - [ - "const godot_packed_int64_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_float32_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_float32_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_float32_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_float32_array *", - "r_dest" - ], - [ - "const godot_packed_float32_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_float32_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_float32_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_float32_array_operator_index", - "return_type": "float *", - "arguments": [ - [ - "godot_packed_float32_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_float32_array_operator_index_const", - "return_type": "const float *", - "arguments": [ - [ - "const godot_packed_float32_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_float64_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_float64_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_float64_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_float64_array *", - "r_dest" - ], - [ - "const godot_packed_float64_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_float64_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_float64_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_float64_array_operator_index", - "return_type": "double *", - "arguments": [ - [ - "godot_packed_float64_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_float64_array_operator_index_const", - "return_type": "const double *", - "arguments": [ - [ - "const godot_packed_float64_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_string_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_string_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_string_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_string_array *", - "r_dest" - ], - [ - "const godot_packed_string_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_string_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_string_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_string_array_operator_index", - "return_type": "godot_string *", - "arguments": [ - [ - "godot_packed_string_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_string_array_operator_index_const", - "return_type": "const godot_string *", - "arguments": [ - [ - "const godot_packed_string_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector2_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector2_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector2_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector2_array *", - "r_dest" - ], - [ - "const godot_packed_vector2_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_vector2_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector2_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector2_array_operator_index", - "return_type": "godot_vector2 *", - "arguments": [ - [ - "godot_packed_vector2_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector2_array_operator_index_const", - "return_type": "const godot_vector2 *", - "arguments": [ - [ - "const godot_packed_vector2_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector2i_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector2i_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector2i_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector2i_array *", - "r_dest" - ], - [ - "const godot_packed_vector2i_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_vector2i_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector2i_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector2i_array_operator_index", - "return_type": "godot_vector2i *", - "arguments": [ - [ - "godot_packed_vector2i_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector2i_array_operator_index_const", - "return_type": "const godot_vector2i *", - "arguments": [ - [ - "const godot_packed_vector2i_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector3_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector3_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector3_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector3_array *", - "r_dest" - ], - [ - "const godot_packed_vector3_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_vector3_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector3_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector3_array_operator_index", - "return_type": "godot_vector3 *", - "arguments": [ - [ - "godot_packed_vector3_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector3_array_operator_index_const", - "return_type": "const godot_vector3 *", - "arguments": [ - [ - "const godot_packed_vector3_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector3i_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector3i_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector3i_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector3i_array *", - "r_dest" - ], - [ - "const godot_packed_vector3i_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_vector3i_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_vector3i_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_vector3i_array_operator_index", - "return_type": "godot_vector3i *", - "arguments": [ - [ - "godot_packed_vector3i_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_vector3i_array_operator_index_const", - "return_type": "const godot_vector3i *", - "arguments": [ - [ - "const godot_packed_vector3i_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_color_array_new", - "return_type": "void", - "arguments": [ - [ - "godot_packed_color_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_color_array_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_color_array *", - "r_dest" - ], - [ - "const godot_packed_color_array *", - "p_src" - ] - ] - }, - { - "name": "godot_packed_color_array_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_packed_color_array *", - "p_self" - ] - ] - }, - { - "name": "godot_packed_color_array_operator_index", - "return_type": "godot_color *", - "arguments": [ - [ - "godot_packed_color_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_packed_color_array_operator_index_const", - "return_type": "const godot_color *", - "arguments": [ - [ - "const godot_packed_color_array *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_plane_new", - "return_type": "void", - "arguments": [ - [ - "godot_plane *", - "p_self" - ] - ] - }, - { - "name": "godot_plane_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_plane *", - "r_dest" - ], - [ - "const godot_plane *", - "p_src" - ] - ] - }, - { - "name": "godot_quaternion_new", - "return_type": "void", - "arguments": [ - [ - "godot_quaternion *", - "p_self" - ] - ] - }, - { - "name": "godot_quaternion_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_quaternion *", - "r_dest" - ], - [ - "const godot_quaternion *", - "p_src" - ] - ] - }, - { - "name": "godot_quaternion_operator_index", - "return_type": "godot_real_t *", - "arguments": [ - [ - "godot_quaternion *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_quaternion_operator_index_const", - "return_type": "const godot_real_t *", - "arguments": [ - [ - "const godot_quaternion *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_rect2_new", - "return_type": "void", - "arguments": [ - [ - "godot_rect2 *", - "p_self" - ] - ] - }, - { - "name": "godot_rect2_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_rect2 *", - "r_dest" - ], - [ - "const godot_rect2 *", - "p_src" - ] - ] - }, - { - "name": "godot_rect2i_new", - "return_type": "void", - "arguments": [ - [ - "godot_rect2i *", - "p_self" - ] - ] - }, - { - "name": "godot_rect2i_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_rect2i *", - "r_dest" - ], - [ - "const godot_rect2i *", - "p_src" - ] - ] - }, - { - "name": "godot_rid_new", - "return_type": "void", - "arguments": [ - [ - "godot_rid *", - "p_self" - ] - ] - }, - { - "name": "godot_rid_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_rid *", - "r_dest" - ], - [ - "const godot_rid *", - "p_src" - ] - ] - }, - { - "name": "godot_signal_new", - "return_type": "void", - "arguments": [ - [ - "godot_signal *", - "p_self" - ] - ] - }, - { - "name": "godot_signal_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_signal *", - "r_dest" - ], - [ - "const godot_signal *", - "p_src" - ] - ] - }, - { - "name": "godot_signal_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_signal *", - "p_self" - ] - ] - }, - { - "name": "godot_string_new", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ] - ] - }, - { - "name": "godot_string_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const godot_string *", - "p_src" - ] - ] - }, - { - "name": "godot_string_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "p_self" - ] - ] - }, - { - "name": "godot_string_new_with_latin1_chars", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char *", - "p_contents" - ] - ] - }, - { - "name": "godot_string_new_with_utf8_chars", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char *", - "p_contents" - ] - ] - }, - { - "name": "godot_string_new_with_utf16_chars", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char16_t *", - "p_contents" - ] - ] - }, - { - "name": "godot_string_new_with_utf32_chars", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char32_t *", - "p_contents" - ] - ] - }, - { - "name": "godot_string_new_with_wide_chars", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const wchar_t *", - "p_contents" - ] - ] - }, - { - "name": "godot_string_new_with_latin1_chars_and_len", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char *", - "p_contents" - ], - [ - "const int", - "p_size" - ] - ] - }, - { - "name": "godot_string_new_with_utf8_chars_and_len", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char *", - "p_contents" - ], - [ - "const int", - "p_size" - ] - ] - }, - { - "name": "godot_string_new_with_utf16_chars_and_len", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char16_t *", - "p_contents" - ], - [ - "const int", - "p_size" - ] - ] - }, - { - "name": "godot_string_new_with_utf32_chars_and_len", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const char32_t *", - "p_contents" - ], - [ - "const int", - "p_size" - ] - ] - }, - { - "name": "godot_string_new_with_wide_chars_and_len", - "return_type": "void", - "arguments": [ - [ - "godot_string *", - "r_dest" - ], - [ - "const wchar_t *", - "p_contents" - ], - [ - "const int", - "p_size" - ] - ] - }, - { - "name": "godot_string_to_latin1_chars", - "return_type": "const char *", - "arguments": [ - [ - "const godot_string *", - "p_self" - ] - ] - }, - { - "name": "godot_string_to_utf8_chars", - "return_type": "const char *", - "arguments": [ - [ - "const godot_string *", - "p_self" - ] - ] - }, - { - "name": "godot_string_to_utf16_chars", - "return_type": "const char16_t *", - "arguments": [ - [ - "const godot_string *", - "p_self" - ] - ] - }, - { - "name": "godot_string_to_utf32_chars", - "return_type": "const char32_t *", - "arguments": [ - [ - "const godot_string *", - "p_self" - ] - ] - }, - { - "name": "godot_string_to_wide_chars", - "return_type": "const wchar_t *", - "arguments": [ - [ - "const godot_string *", - "p_self" - ] - ] - }, - { - "name": "godot_string_operator_index", - "return_type": "char32_t *", - "arguments": [ - [ - "godot_string *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_string_operator_index_const", - "return_type": "const char32_t *", - "arguments": [ - [ - "const godot_string *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_string_name_new", - "return_type": "void", - "arguments": [ - [ - "godot_string_name *", - "r_dest" - ] - ] - }, - { - "name": "godot_string_name_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_string_name *", - "r_dest" - ], - [ - "const godot_string_name *", - "p_src" - ] - ] - }, - { - "name": "godot_string_name_destroy", - "return_type": "void", - "arguments": [ - [ - "godot_string_name *", - "p_self" - ] - ] - }, - { - "name": "godot_string_name_new_with_latin1_chars", - "return_type": "void", - "arguments": [ - [ - "godot_string_name *", - "r_dest" - ], - [ - "const char *", - "p_contents" - ] - ] - }, - { - "name": "godot_transform3d_new", - "return_type": "void", - "arguments": [ - [ - "godot_transform3d *", - "r_dest" - ] - ] - }, - { - "name": "godot_transform3d_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_transform3d *", - "r_dest" - ], - [ - "const godot_transform3d *", - "p_src" - ] - ] - }, - { - "name": "godot_transform2d_new", - "return_type": "void", - "arguments": [ - [ - "godot_transform2d *", - "r_dest" - ] - ] - }, - { - "name": "godot_transform2d_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_transform2d *", - "r_dest" - ], - [ - "const godot_transform2d *", - "p_src" - ] - ] - }, - { - "name": "godot_transform2d_operator_index", - "return_type": "godot_vector2 *", - "arguments": [ - [ - "godot_transform2d *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_transform2d_operator_index_const", - "return_type": "const godot_vector2 *", - "arguments": [ - [ - "const godot_transform2d *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector2_new", - "return_type": "void", - "arguments": [ - [ - "godot_vector2 *", - "r_dest" - ] - ] - }, - { - "name": "godot_vector2_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_vector2 *", - "r_dest" - ], - [ - "const godot_vector2 *", - "p_src" - ] - ] - }, - { - "name": "godot_vector2_operator_index", - "return_type": "godot_real_t *", - "arguments": [ - [ - "godot_vector2 *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector2_operator_index_const", - "return_type": "const godot_real_t *", - "arguments": [ - [ - "const godot_vector2 *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector2i_new", - "return_type": "void", - "arguments": [ - [ - "godot_vector2i *", - "r_dest" - ] - ] - }, - { - "name": "godot_vector2i_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_vector2i *", - "r_dest" - ], - [ - "const godot_vector2i *", - "p_src" - ] - ] - }, - { - "name": "godot_vector2i_operator_index", - "return_type": "int32_t *", - "arguments": [ - [ - "godot_vector2i *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector2i_operator_index_const", - "return_type": "const int32_t *", - "arguments": [ - [ - "const godot_vector2i *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector3_new", - "return_type": "void", - "arguments": [ - [ - "godot_vector3 *", - "r_dest" - ] - ] - }, - { - "name": "godot_vector3_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_vector3 *", - "r_dest" - ], - [ - "const godot_vector3 *", - "p_src" - ] - ] - }, - { - "name": "godot_vector3_operator_index", - "return_type": "godot_real_t *", - "arguments": [ - [ - "godot_vector3 *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector3_operator_index_const", - "return_type": "const godot_real_t *", - "arguments": [ - [ - "const godot_vector3 *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector3i_new", - "return_type": "void", - "arguments": [ - [ - "godot_vector3i *", - "r_dest" - ] - ] - }, - { - "name": "godot_vector3i_new_copy", - "return_type": "void", - "arguments": [ - [ - "godot_vector3i *", - "r_dest" - ], - [ - "const godot_vector3i *", - "p_src" - ] - ] - }, - { - "name": "godot_vector3i_operator_index", - "return_type": "int32_t *", - "arguments": [ - [ - "godot_vector3i *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - }, - { - "name": "godot_vector3i_operator_index_const", - "return_type": "const int32_t *", - "arguments": [ - [ - "const godot_vector3i *", - "p_self" - ], - [ - "godot_int", - "p_index" - ] - ] - } - ] - }, - "extensions": [ - { - "name": "nativescript", - "type": "NATIVESCRIPT", - "version": { - "major": 4, - "minor": 0 - }, - "next": null, - "api": [ - { - "name": "godot_nativescript_register_class", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_base" - ], - [ - "godot_nativescript_instance_create_func", - "p_create_func" - ], - [ - "godot_nativescript_instance_destroy_func", - "p_destroy_func" - ] - ] - }, - { - "name": "godot_nativescript_register_tool_class", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_base" - ], - [ - "godot_nativescript_instance_create_func", - "p_create_func" - ], - [ - "godot_nativescript_instance_destroy_func", - "p_destroy_func" - ] - ] - }, - { - "name": "godot_nativescript_register_method", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_function_name" - ], - [ - "godot_nativescript_method_attributes", - "p_attr" - ], - [ - "godot_nativescript_instance_method", - "p_method" - ] - ] - }, - { - "name": "godot_nativescript_set_method_argument_information", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_function_name" - ], - [ - "int", - "p_num_args" - ], - [ - "const godot_nativescript_method_argument *", - "p_args" - ] - ] - }, - { - "name": "godot_nativescript_register_property", - "return_type": "void", - "arguments": [ - [ - "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" - ] - ] - }, - { - "name": "godot_nativescript_register_signal", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const godot_nativescript_signal *", - "p_signal" - ] - ] - }, - { - "name": "godot_nativescript_get_userdata", - "return_type": "void *", - "arguments": [ - [ - "godot_object *", - "p_instance" - ] - ] - }, - { - "name": "godot_nativescript_set_class_documentation", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "godot_string", - "p_documentation" - ] - ] - }, - { - "name": "godot_nativescript_set_method_documentation", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_function_name" - ], - [ - "godot_string", - "p_documentation" - ] - ] - }, - { - "name": "godot_nativescript_set_property_documentation", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_path" - ], - [ - "godot_string", - "p_documentation" - ] - ] - }, - { - "name": "godot_nativescript_set_signal_documentation", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const char *", - "p_signal_name" - ], - [ - "godot_string", - "p_documentation" - ] - ] - }, - { - "name": "godot_nativescript_set_global_type_tag", - "return_type": "void", - "arguments": [ - [ - "int", - "p_idx" - ], - [ - "const char *", - "p_name" - ], - [ - "const void *", - "p_type_tag" - ] - ] - }, - { - "name": "godot_nativescript_get_global_type_tag", - "return_type": "const void *", - "arguments": [ - [ - "int", - "p_idx" - ], - [ - "const char *", - "p_name" - ] - ] - }, - { - "name": "godot_nativescript_set_type_tag", - "return_type": "void", - "arguments": [ - [ - "void *", - "p_gdnative_handle" - ], - [ - "const char *", - "p_name" - ], - [ - "const void *", - "p_type_tag" - ] - ] - }, - { - "name": "godot_nativescript_get_type_tag", - "return_type": "const void *", - "arguments": [ - [ - "const godot_object *", - "p_object" - ] - ] - }, - { - "name": "godot_nativescript_register_instance_binding_data_functions", - "return_type": "int", - "arguments": [ - [ - "godot_nativescript_instance_binding_functions", - "p_binding_functions" - ] - ] - }, - { - "name": "godot_nativescript_unregister_instance_binding_data_functions", - "return_type": "void", - "arguments": [ - [ - "int", - "p_idx" - ] - ] - }, - { - "name": "godot_nativescript_get_instance_binding_data", - "return_type": "void *", - "arguments": [ - [ - "int", - "p_idx" - ], - [ - "godot_object *", - "p_object" - ] - ] - }, - { - "name": "godot_nativescript_profiling_add_data", - "return_type": "void", - "arguments": [ - [ - "const char *", - "p_signature" - ], - [ - "uint64_t", - "p_line" - ] - ] - } - ] - }, - { - "name": "pluginscript", - "type": "PLUGINSCRIPT", - "version": { - "major": 1, - "minor": 0 - }, - "next": null, - "api": [ - { - "name": "godot_pluginscript_register_language", - "return_type": "void", - "arguments": [ - [ - "const godot_pluginscript_language_desc *", - "language_desc" - ] - ] - } - ] - }, - { - "name": "android", - "type": "ANDROID", - "version": { - "major": 1, - "minor": 1 - }, - "next": null, - "api": [ - { - "name": "godot_android_get_env", - "return_type": "JNIEnv*", - "arguments": [] - }, - { - "name": "godot_android_get_activity", - "return_type": "jobject", - "arguments": [] - }, - { - "name": "godot_android_get_surface", - "return_type": "jobject", - "arguments": [] - }, - { - "name": "godot_android_is_activity_resumed", - "return_type": "bool", - "arguments": [] - } - ] - }, - { - "name": "videodecoder", - "type": "VIDEODECODER", - "version": { - "major": 0, - "minor": 1 - }, - "next": null, - "api": [ - { - "name": "godot_videodecoder_file_read", - "return_type": "godot_int", - "arguments": [ - [ - "void *", - "file_ptr" - ], - [ - "uint8_t *", - "buf" - ], - [ - "int", - "buf_size" - ] - ] - }, - { - "name": "godot_videodecoder_file_seek", - "return_type": "int64_t", - "arguments": [ - [ - "void *", - "file_ptr" - ], - [ - "int64_t", - "pos" - ], - [ - "int", - "whence" - ] - ] - }, - { - "name": "godot_videodecoder_register_decoder", - "return_type": "void", - "arguments": [ - [ - "const godot_videodecoder_interface_gdnative *", - "p_interface" - ] - ] - } - ] - } - ] -} diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py deleted file mode 100644 index 6c96e23426..0000000000 --- a/modules/gdnative/gdnative_builders.py +++ /dev/null @@ -1,263 +0,0 @@ -"""Functions used to generate source files during build time - -All such functions are invoked in a subprocess on Windows to prevent build flakiness. - -""" -import json -from platform_methods import subprocess_main - - -def _spaced(e): - return e if e[-1] == "*" else e + " " - - -def _build_gdnative_api_struct_header(api): - out = [ - "/* THIS FILE IS GENERATED DO NOT EDIT */", - "#ifndef GODOT_GDNATIVE_API_STRUCT_H", - "#define GODOT_GDNATIVE_API_STRUCT_H", - "", - "#include <gdnative/gdnative.h>", - "#include <android/godot_android.h>", - "#include <nativescript/godot_nativescript.h>", - "#include <pluginscript/godot_pluginscript.h>", - "#include <videodecoder/godot_videodecoder.h>", - "", - "#ifdef __cplusplus", - 'extern "C" {', - "#endif", - "", - "enum GDNATIVE_API_TYPES {", - "\tGDNATIVE_" + api["core"]["type"] + ",", - ] - - for ext in api["extensions"]: - out += ["\tGDNATIVE_EXT_" + ext["type"] + ","] - - out += ["};", ""] - - def generate_extension_struct(name, ext, include_version=True): - ret_val = [] - if ext["next"]: - ret_val += generate_extension_struct(name, ext["next"]) - - ret_val += [ - "typedef struct godot_gdnative_ext_" - + name - + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) - + "_api_struct {", - "\tunsigned int type;", - "\tgodot_gdnative_api_version version;", - "\tconst godot_gdnative_api_struct *next;", - ] - - for funcdef in ext["api"]: - args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) - ret_val.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) - - ret_val += [ - "} godot_gdnative_ext_" - + name - + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) - + "_api_struct;", - "", - ] - - return ret_val - - def generate_core_extension_struct(core): - ret_val = [] - if core["next"]: - ret_val += generate_core_extension_struct(core["next"]) - - ret_val += [ - "typedef struct godot_gdnative_core_" - + "{0}_{1}".format(core["version"]["major"], core["version"]["minor"]) - + "_api_struct {", - "\tunsigned int type;", - "\tgodot_gdnative_api_version version;", - "\tconst godot_gdnative_api_struct *next;", - ] - - for funcdef in core["api"]: - args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) - ret_val.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) - - ret_val += [ - "} godot_gdnative_core_" - + "{0}_{1}".format(core["version"]["major"], core["version"]["minor"]) - + "_api_struct;", - "", - ] - - return ret_val - - for ext in api["extensions"]: - name = ext["name"] - out += generate_extension_struct(name, ext, False) - - if api["core"]["next"]: - out += generate_core_extension_struct(api["core"]["next"]) - - out += [ - "typedef struct godot_gdnative_core_api_struct {", - "\tunsigned int type;", - "\tgodot_gdnative_api_version version;", - "\tconst godot_gdnative_api_struct *next;", - "\tunsigned int num_extensions;", - "\tconst godot_gdnative_api_struct **extensions;", - ] - - for funcdef in api["core"]["api"]: - args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]]) - out.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args)) - - out += [ - "} godot_gdnative_core_api_struct;", - "", - "#ifdef __cplusplus", - "}", - "#endif", - "", - "#endif // GODOT_GDNATIVE_API_STRUCT_H", - "", - ] - return "\n".join(out) - - -def _build_gdnative_api_struct_source(api): - out = ["/* THIS FILE IS GENERATED DO NOT EDIT */", "", "#include <gdnative_api_struct.gen.h>", ""] - - def get_extension_struct_name(name, ext, include_version=True): - return ( - "godot_gdnative_ext_" - + name - + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) - + "_api_struct" - ) - - def get_extension_struct_instance_name(name, ext, include_version=True): - return ( - "api_extension_" - + name - + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"]))) - + "_struct" - ) - - def get_extension_struct_definition(name, ext, include_version=True): - - ret_val = [] - - if ext["next"]: - ret_val += get_extension_struct_definition(name, ext["next"]) - - ret_val += [ - "extern const " - + get_extension_struct_name(name, ext, include_version) - + " " - + get_extension_struct_instance_name(name, ext, include_version) - + " = {", - "\tGDNATIVE_EXT_" + ext["type"] + ",", - "\t{" + str(ext["version"]["major"]) + ", " + str(ext["version"]["minor"]) + "},", - "\t" - + ( - "nullptr" - if not ext["next"] - else ("(const godot_gdnative_api_struct *)&" + get_extension_struct_instance_name(name, ext["next"])) - ) - + ",", - ] - - for funcdef in ext["api"]: - ret_val.append("\t%s," % funcdef["name"]) - - ret_val += ["};\n"] - - return ret_val - - def get_core_struct_definition(core): - ret_val = [] - - if core["next"]: - ret_val += get_core_struct_definition(core["next"]) - - ret_val += [ - "extern const godot_gdnative_core_" - + "{0}_{1}_api_struct api_{0}_{1}".format(core["version"]["major"], core["version"]["minor"]) - + " = {", - "\tGDNATIVE_" + core["type"] + ",", - "\t{" + str(core["version"]["major"]) + ", " + str(core["version"]["minor"]) + "},", - "\t" - + ( - "nullptr" - if not core["next"] - else ( - "(const godot_gdnative_api_struct *)& api_{0}_{1}".format( - core["next"]["version"]["major"], core["next"]["version"]["minor"] - ) - ) - ) - + ",", - ] - - for funcdef in core["api"]: - ret_val.append("\t%s," % funcdef["name"]) - - ret_val += ["};\n"] - - return ret_val - - for ext in api["extensions"]: - name = ext["name"] - out += get_extension_struct_definition(name, ext, False) - - out += ["", "const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {"] - - for ext in api["extensions"]: - name = ext["name"] - out += ["\t(godot_gdnative_api_struct *)&api_extension_" + name + "_struct,"] - - out += ["};\n"] - - if api["core"]["next"]: - out += get_core_struct_definition(api["core"]["next"]) - - out += [ - "extern const godot_gdnative_core_api_struct api_struct = {", - "\tGDNATIVE_" + api["core"]["type"] + ",", - "\t{" + str(api["core"]["version"]["major"]) + ", " + str(api["core"]["version"]["minor"]) + "},", - "\t" - + ( - "nullptr, " - if not api["core"]["next"] - else ( - "(const godot_gdnative_api_struct *)& api_{0}_{1},".format( - api["core"]["next"]["version"]["major"], api["core"]["next"]["version"]["minor"] - ) - ) - ), - "\t" + str(len(api["extensions"])) + ",", - "\tgdnative_extensions_pointers,", - ] - - for funcdef in api["core"]["api"]: - out.append("\t%s," % funcdef["name"]) - out.append("};\n") - - return "\n".join(out) - - -def build_gdnative_api_struct(target, source, env): - - with open(source[0], "r") as fd: - api = json.load(fd) - - header, source = target - with open(header, "w") as fd: - fd.write(_build_gdnative_api_struct_header(api)) - with open(source, "w") as fd: - fd.write(_build_gdnative_api_struct_source(api)) - - -if __name__ == "__main__": - subprocess_main(globals()) diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp deleted file mode 100644 index df3c37f730..0000000000 --- a/modules/gdnative/gdnative_library_editor_plugin.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/*************************************************************************/ -/* gdnative_library_editor_plugin.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 "gdnative_library_editor_plugin.h" -#include "gdnative.h" - -#include "editor/editor_scale.h" - -void GDNativeLibraryEditor::edit(Ref<GDNativeLibrary> p_library) { - library = p_library; - Ref<ConfigFile> config = p_library->get_config_file(); - - for (KeyValue<String, NativePlatformConfig> &E : platforms) { - for (List<String>::Element *it = E.value.entries.front(); it; it = it->next()) { - String target = E.key + "." + it->get(); - TargetConfig ecfg; - ecfg.library = config->get_value("entry", target, ""); - ecfg.dependencies = config->get_value("dependencies", target, Array()); - entry_configs[target] = ecfg; - } - } - - _update_tree(); -} - -void GDNativeLibraryEditor::_bind_methods() { -} - -void GDNativeLibraryEditor::_update_tree() { - tree->clear(); - TreeItem *root = tree->create_item(); - - PopupMenu *filter_list = filter->get_popup(); - String text = ""; - for (int i = 0; i < filter_list->get_item_count(); i++) { - if (!filter_list->is_item_checked(i)) { - continue; - } - Map<String, NativePlatformConfig>::Element *E = platforms.find(filter_list->get_item_metadata(i)); - if (!text.is_empty()) { - text += ", "; - } - text += E->get().name; - - TreeItem *platform = tree->create_item(root); - platform->set_text(0, E->get().name); - platform->set_metadata(0, E->get().library_extension); - - platform->set_custom_bg_color(0, get_theme_color(SNAME("prop_category"), SNAME("Editor"))); - platform->set_custom_bg_color(1, get_theme_color(SNAME("prop_category"), SNAME("Editor"))); - platform->set_custom_bg_color(2, get_theme_color(SNAME("prop_category"), SNAME("Editor"))); - platform->set_selectable(0, false); - platform->set_expand_right(0, true); - - for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) { - String target = E->key() + "." + it->get(); - TreeItem *bit = tree->create_item(platform); - - bit->set_text(0, it->get()); - bit->set_metadata(0, target); - bit->set_selectable(0, false); - bit->set_custom_bg_color(0, get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); - - bit->add_button(1, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), BUTTON_SELECT_LIBRARY, false, TTR("Select the dynamic library for this entry")); - String file = entry_configs[target].library; - if (!file.is_empty()) { - bit->add_button(1, get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), BUTTON_CLEAR_LIBRARY, false, TTR("Clear")); - } - bit->set_text(1, file); - - bit->add_button(2, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), BUTTON_SELECT_DEPENDENCES, false, TTR("Select dependencies of the library for this entry")); - Array files = entry_configs[target].dependencies; - if (files.size()) { - bit->add_button(2, get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), BUTTON_CLEAR_DEPENDENCES, false, TTR("Clear")); - } - bit->set_text(2, Variant(files)); - - bit->add_button(3, get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), BUTTON_MOVE_UP, false, TTR("Move Up")); - bit->add_button(3, get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")), BUTTON_MOVE_DOWN, false, TTR("Move Down")); - bit->add_button(3, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_ERASE_ENTRY, false, TTR("Remove current entry")); - } - - TreeItem *new_arch = tree->create_item(platform); - new_arch->set_text(0, TTR("Double click to create a new entry")); - new_arch->set_text_alignment(0, HORIZONTAL_ALIGNMENT_CENTER); - new_arch->set_custom_color(0, get_theme_color(SNAME("accent_color"), SNAME("Editor"))); - new_arch->set_expand_right(0, true); - new_arch->set_metadata(1, E->key()); - - platform->set_collapsed(collapsed_items.find(E->get().name) != nullptr); - } - filter->set_text(text); -} - -void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) { - String target = Object::cast_to<TreeItem>(item)->get_metadata(0); - String platform = target.substr(0, target.find(".")); - String entry = target.substr(platform.length() + 1, target.length()); - String section = (id == BUTTON_SELECT_DEPENDENCES || id == BUTTON_CLEAR_DEPENDENCES) ? "dependencies" : "entry"; - - if (id == BUTTON_SELECT_LIBRARY || id == BUTTON_SELECT_DEPENDENCES) { - TreeItem *treeItem = Object::cast_to<TreeItem>(item)->get_parent(); - 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" || treeItem->get_text(0) == "macOS") { - mode = EditorFileDialog::FILE_MODE_OPEN_ANY; - } - - file_dialog->set_meta("target", target); - file_dialog->set_meta("section", section); - file_dialog->clear_filters(); - - String filter_string = treeItem->get_metadata(0); - Vector<String> filters = filter_string.split(",", false, 0); - for (int i = 0; i < filters.size(); i++) { - file_dialog->add_filter(filters[i]); - } - - file_dialog->set_file_mode(mode); - file_dialog->popup_file_dialog(); - - } else if (id == BUTTON_CLEAR_LIBRARY) { - _set_target_value(section, target, ""); - } else if (id == BUTTON_CLEAR_DEPENDENCES) { - _set_target_value(section, target, Array()); - } else if (id == BUTTON_ERASE_ENTRY) { - _erase_entry(platform, entry); - } else if (id == BUTTON_MOVE_UP || id == BUTTON_MOVE_DOWN) { - _move_entry(platform, entry, id); - } -} - -void GDNativeLibraryEditor::_on_library_selected(const String &file) { - _set_target_value(file_dialog->get_meta("section"), file_dialog->get_meta("target"), file); -} - -void GDNativeLibraryEditor::_on_dependencies_selected(const PackedStringArray &files) { - _set_target_value(file_dialog->get_meta("section"), file_dialog->get_meta("target"), files); -} - -void GDNativeLibraryEditor::_on_filter_selected(int index) { - PopupMenu *filter_list = filter->get_popup(); - filter_list->set_item_checked(index, !filter_list->is_item_checked(index)); - _update_tree(); -} - -void GDNativeLibraryEditor::_on_item_collapsed(Object *p_item) { - TreeItem *item = Object::cast_to<TreeItem>(p_item); - String name = item->get_text(0); - - if (item->is_collapsed()) { - collapsed_items.insert(name); - } else if (Set<String>::Element *e = collapsed_items.find(name)) { - collapsed_items.erase(e); - } -} - -void GDNativeLibraryEditor::_on_item_activated() { - TreeItem *item = tree->get_selected(); - if (item && tree->get_selected_column() == 0 && item->get_metadata(0).get_type() == Variant::NIL) { - new_architecture_dialog->set_meta("platform", item->get_metadata(1)); - new_architecture_dialog->popup_centered(); - } -} - -void GDNativeLibraryEditor::_on_create_new_entry() { - String platform = new_architecture_dialog->get_meta("platform"); - String entry = new_architecture_input->get_text().strip_edges(); - if (!entry.is_empty()) { - platforms[platform].entries.push_back(entry); - _update_tree(); - } -} - -void GDNativeLibraryEditor::_set_target_value(const String §ion, const String &target, Variant file) { - if (section == "entry") { - entry_configs[target].library = file; - } else if (section == "dependencies") { - entry_configs[target].dependencies = file; - } - _translate_to_config_file(); - _update_tree(); -} - -void GDNativeLibraryEditor::_erase_entry(const String &platform, const String &entry) { - if (platforms.has(platform)) { - if (List<String>::Element *E = platforms[platform].entries.find(entry)) { - String target = platform + "." + entry; - - platforms[platform].entries.erase(E); - _set_target_value("entry", target, ""); - _set_target_value("dependencies", target, Array()); - _translate_to_config_file(); - _update_tree(); - } - } -} - -void GDNativeLibraryEditor::_move_entry(const String &platform, const String &entry, int dir) { - if (List<String>::Element *E = platforms[platform].entries.find(entry)) { - if (E->prev() && dir == BUTTON_MOVE_UP) { - platforms[platform].entries.insert_before(E->prev(), E->get()); - platforms[platform].entries.erase(E); - } else if (E->next() && dir == BUTTON_MOVE_DOWN) { - platforms[platform].entries.insert_after(E->next(), E->get()); - platforms[platform].entries.erase(E); - } - _translate_to_config_file(); - _update_tree(); - } -} - -void GDNativeLibraryEditor::_translate_to_config_file() { - if (!library.is_null()) { - Ref<ConfigFile> config = library->get_config_file(); - config->erase_section("entry"); - config->erase_section("dependencies"); - - for (KeyValue<String, NativePlatformConfig> &E : platforms) { - for (List<String>::Element *it = E.value.entries.front(); it; it = it->next()) { - String target = E.key + "." + it->get(); - if (entry_configs[target].library.is_empty() && entry_configs[target].dependencies.is_empty()) { - continue; - } - - config->set_value("entry", target, entry_configs[target].library); - config->set_value("dependencies", target, entry_configs[target].dependencies); - } - } - - library->notify_property_list_changed(); - } -} - -GDNativeLibraryEditor::GDNativeLibraryEditor() { - { // Define platforms - NativePlatformConfig platform_windows; - platform_windows.name = "Windows"; - platform_windows.entries.push_back("64"); - platform_windows.entries.push_back("32"); - platform_windows.library_extension = "*.dll"; - platforms["Windows"] = platform_windows; - - NativePlatformConfig platform_linux; - platform_linux.name = "Linux/X11"; - platform_linux.entries.push_back("64"); - platform_linux.entries.push_back("32"); - platform_linux.library_extension = "*.so"; - platforms["X11"] = platform_linux; - - NativePlatformConfig platform_osx; - platform_osx.name = "macOS"; - platform_osx.entries.push_back("64"); - platform_osx.library_extension = "*.framework; Framework, *.dylib; Dynamic Library"; - platforms["macOS"] = platform_osx; - - NativePlatformConfig platform_haiku; - platform_haiku.name = "Haiku"; - platform_haiku.entries.push_back("64"); - platform_haiku.entries.push_back("32"); - platform_haiku.library_extension = "*.so"; - platforms["Haiku"] = platform_haiku; - - NativePlatformConfig platform_uwp; - platform_uwp.name = "UWP"; - platform_uwp.entries.push_back("arm"); - platform_uwp.entries.push_back("32"); - platform_uwp.entries.push_back("64"); - platform_uwp.library_extension = "*.dll"; - platforms["UWP"] = platform_uwp; - - NativePlatformConfig platform_android; - platform_android.name = "Android"; - platform_android.entries.push_back("armeabi-v7a"); - platform_android.entries.push_back("arm64-v8a"); - platform_android.entries.push_back("x86"); - platform_android.entries.push_back("x86_64"); - platform_android.library_extension = "*.so"; - platforms["Android"] = platform_android; - - NativePlatformConfig platform_html5; - platform_html5.name = "HTML5"; - platform_html5.entries.push_back("wasm32"); - platform_html5.library_extension = "*.wasm"; - platforms["HTML5"] = platform_html5; - - NativePlatformConfig platform_ios; - platform_ios.name = "iOS"; - platform_ios.entries.push_back("armv7"); - platform_ios.entries.push_back("arm64"); - platform_ios.entries.push_back("x86_64"); - // iOS can use both Static and Dynamic libraries. - // Frameworks is actually a folder with files. - platform_ios.library_extension = "*.framework; Framework, *.xcframework; Binary Framework, *.a; Static Library, *.dylib; Dynamic Library"; - platforms["iOS"] = platform_ios; - } - - VBoxContainer *container = memnew(VBoxContainer); - add_child(container); - container->set_anchors_and_offsets_preset(PRESET_WIDE); - - HBoxContainer *hbox = memnew(HBoxContainer); - container->add_child(hbox); - Label *label = memnew(Label); - label->set_text(TTR("Platform:")); - hbox->add_child(label); - filter = memnew(MenuButton); - filter->set_h_size_flags(SIZE_EXPAND_FILL); - filter->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); - hbox->add_child(filter); - PopupMenu *filter_list = filter->get_popup(); - filter_list->set_hide_on_checkable_item_selection(false); - - int idx = 0; - for (const KeyValue<String, NativePlatformConfig> &E : platforms) { - filter_list->add_check_item(E.value.name, idx); - filter_list->set_item_metadata(idx, E.key); - filter_list->set_item_checked(idx, true); - idx += 1; - } - filter_list->connect("index_pressed", callable_mp(this, &GDNativeLibraryEditor::_on_filter_selected)); - - tree = memnew(Tree); - container->add_child(tree); - tree->set_v_size_flags(SIZE_EXPAND_FILL); - tree->set_hide_root(true); - tree->set_column_titles_visible(true); - tree->set_columns(4); - tree->set_column_expand(0, false); - 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_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)); - - file_dialog = memnew(EditorFileDialog); - file_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); - //file_dialog->set_resizable(true); - add_child(file_dialog); - file_dialog->connect("file_selected", callable_mp(this, &GDNativeLibraryEditor::_on_library_selected)); - file_dialog->connect("dir_selected", callable_mp(this, &GDNativeLibraryEditor::_on_library_selected)); - file_dialog->connect("files_selected", callable_mp(this, &GDNativeLibraryEditor::_on_dependencies_selected)); - - new_architecture_dialog = memnew(ConfirmationDialog); - add_child(new_architecture_dialog); - new_architecture_dialog->set_title(TTR("Add an architecture entry")); - new_architecture_input = memnew(LineEdit); - new_architecture_dialog->add_child(new_architecture_input); - // new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE); - new_architecture_input->set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE); - new_architecture_dialog->get_ok_button()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry)); -} - -void GDNativeLibraryEditorPlugin::edit(Object *p_node) { - Ref<GDNativeLibrary> new_library = Object::cast_to<GDNativeLibrary>(p_node); - if (new_library.is_valid()) { - library_editor->edit(new_library); - } -} - -bool GDNativeLibraryEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("GDNativeLibrary"); -} - -void GDNativeLibraryEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - button->show(); - EditorNode::get_singleton()->make_bottom_panel_item_visible(library_editor); - - } else { - if (library_editor->is_visible_in_tree()) { - EditorNode::get_singleton()->hide_bottom_panel(); - } - button->hide(); - } -} - -GDNativeLibraryEditorPlugin::GDNativeLibraryEditorPlugin(EditorNode *p_node) { - library_editor = memnew(GDNativeLibraryEditor); - library_editor->set_custom_minimum_size(Size2(0, 250 * EDSCALE)); - button = p_node->add_bottom_panel_item(TTR("GDNativeLibrary"), library_editor); - button->hide(); -} - -#endif diff --git a/modules/gdnative/gdnative_library_editor_plugin.h b/modules/gdnative/gdnative_library_editor_plugin.h deleted file mode 100644 index 61afb1aaaa..0000000000 --- a/modules/gdnative/gdnative_library_editor_plugin.h +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************/ -/* gdnative_library_editor_plugin.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 GDNATIVE_LIBRARY_EDITOR_PLUGIN_H -#define GDNATIVE_LIBRARY_EDITOR_PLUGIN_H - -#ifdef TOOLS_ENABLED -#include "editor/editor_node.h" -#include "gdnative.h" - -class GDNativeLibraryEditor : public Control { - GDCLASS(GDNativeLibraryEditor, Control); - - struct NativePlatformConfig { - String name; - String library_extension; - List<String> entries; - }; - - struct TargetConfig { - String library; - Array dependencies; - }; - - enum ItemButton { - BUTTON_SELECT_LIBRARY, - BUTTON_CLEAR_LIBRARY, - BUTTON_SELECT_DEPENDENCES, - BUTTON_CLEAR_DEPENDENCES, - BUTTON_ERASE_ENTRY, - BUTTON_MOVE_UP, - BUTTON_MOVE_DOWN, - }; - - Tree *tree; - MenuButton *filter; - EditorFileDialog *file_dialog; - ConfirmationDialog *new_architecture_dialog; - LineEdit *new_architecture_input; - Set<String> collapsed_items; - - String showing_platform; - Ref<GDNativeLibrary> library; - Map<String, NativePlatformConfig> platforms; - Map<String, TargetConfig> entry_configs; - -protected: - static void _bind_methods(); - void _update_tree(); - void _on_item_button(Object *item, int column, int id); - void _on_library_selected(const String &file); - void _on_dependencies_selected(const PackedStringArray &files); - void _on_filter_selected(int id); - void _on_item_collapsed(Object *p_item); - void _on_item_activated(); - void _on_create_new_entry(); - void _set_target_value(const String §ion, const String &target, Variant file); - void _erase_entry(const String &platform, const String &entry); - void _move_entry(const String &platform, const String &entry, int dir); - void _translate_to_config_file(); - -public: - void edit(Ref<GDNativeLibrary> p_library); - - GDNativeLibraryEditor(); -}; - -class GDNativeLibraryEditorPlugin : public EditorPlugin { - GDCLASS(GDNativeLibraryEditorPlugin, EditorPlugin); - - GDNativeLibraryEditor *library_editor = nullptr; - EditorNode *editor = nullptr; - Button *button = nullptr; - -public: - virtual String get_name() const override { return "GDNativeLibrary"; } - bool has_main_screen() const override { return false; } - virtual void edit(Object *p_node) override; - virtual bool handles(Object *p_node) const override; - virtual void make_visible(bool p_visible) override; - - GDNativeLibraryEditorPlugin(EditorNode *p_node); -}; -#endif -#endif // GDNATIVE_LIBRARY_EDITOR_PLUGIN_H diff --git a/modules/gdnative/gdnative_library_singleton_editor.cpp b/modules/gdnative/gdnative_library_singleton_editor.cpp deleted file mode 100644 index f1b4a9a81b..0000000000 --- a/modules/gdnative/gdnative_library_singleton_editor.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/*************************************************************************/ -/* gdnative_library_singleton_editor.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 "gdnative_library_singleton_editor.h" -#include "gdnative.h" - -#include "editor/editor_node.h" - -Set<String> GDNativeLibrarySingletonEditor::_find_singletons_recursive(EditorFileSystemDirectory *p_dir) { - Set<String> file_paths; - - // check children - - for (int i = 0; i < p_dir->get_file_count(); i++) { - String file_name = p_dir->get_file(i); - String file_type = p_dir->get_file_type(i); - - if (file_type != "GDNativeLibrary") { - continue; - } - - Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i)); - if (lib.is_valid() && lib->is_singleton()) { - file_paths.insert(p_dir->get_file_path(i)); - } - } - - // check subdirectories - for (int i = 0; i < p_dir->get_subdir_count(); i++) { - Set<String> paths = _find_singletons_recursive(p_dir->get_subdir(i)); - - for (Set<String>::Element *E = paths.front(); E; E = E->next()) { - file_paths.insert(E->get()); - } - } - - return file_paths; -} - -void GDNativeLibrarySingletonEditor::_discover_singletons() { - EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->get_filesystem(); - - Set<String> file_paths = _find_singletons_recursive(dir); - - bool changed = false; - Array current_files; - if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) { - current_files = ProjectSettings::get_singleton()->get("gdnative/singletons"); - } - Array files; - for (Set<String>::Element *E = file_paths.front(); E; E = E->next()) { - if (!current_files.has(E->get())) { - changed = true; - } - files.append(E->get()); - } - - // Check for removed files - if (!changed) { - // Removed singleton - for (int j = 0; j < current_files.size(); j++) { - if (!files.has(current_files[j])) { - changed = true; - break; - } - } - } - - if (changed) { - ProjectSettings::get_singleton()->set("gdnative/singletons", files); - _update_libraries(); // So singleton options (i.e. disabled) updates too - ProjectSettings::get_singleton()->save(); - } -} - -void GDNativeLibrarySingletonEditor::_update_libraries() { - updating = true; - libraries->clear(); - libraries->create_item(); // root item - - Array singletons; - if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) { - singletons = ProjectSettings::get_singleton()->get("gdnative/singletons"); - } - Array singletons_disabled; - if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons_disabled")) { - singletons_disabled = ProjectSettings::get_singleton()->get("gdnative/singletons_disabled"); - } - - Array updated_disabled; - for (int i = 0; i < singletons.size(); i++) { - bool enabled = true; - String path = singletons[i]; - if (singletons_disabled.has(path)) { - enabled = false; - updated_disabled.push_back(path); - } - TreeItem *ti = libraries->create_item(libraries->get_root()); - ti->set_text(0, path.get_file()); - ti->set_tooltip(0, path); - ti->set_metadata(0, path); - ti->set_cell_mode(1, TreeItem::CELL_MODE_RANGE); - ti->set_text(1, "Disabled,Enabled"); - ti->set_range(1, enabled ? 1 : 0); - ti->set_custom_color(1, enabled ? Color(0, 1, 0) : Color(1, 0, 0)); - ti->set_editable(1, true); - } - - // The singletons list changed, we must update the settings - if (updated_disabled.size() != singletons_disabled.size()) { - ProjectSettings::get_singleton()->set("gdnative/singletons_disabled", updated_disabled); - } - - updating = false; -} - -void GDNativeLibrarySingletonEditor::_item_edited() { - if (updating) { - return; - } - - TreeItem *item = libraries->get_edited(); - if (!item) { - return; - } - - bool enabled = item->get_range(1); - String path = item->get_metadata(0); - - Array disabled_paths; - Array undo_paths; - if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons_disabled")) { - disabled_paths = ProjectSettings::get_singleton()->get("gdnative/singletons_disabled"); - // Duplicate so redo works (not a reference) - disabled_paths = disabled_paths.duplicate(); - // For undo, so we can reset the property. - undo_paths = disabled_paths.duplicate(); - } - - if (enabled) { - disabled_paths.erase(path); - } else { - if (disabled_paths.find(path) == -1) { - disabled_paths.push_back(path); - } - } - - undo_redo->create_action(enabled ? TTR("Enabled GDNative Singleton") : TTR("Disabled GDNative Singleton")); - undo_redo->add_do_property(ProjectSettings::get_singleton(), "gdnative/singletons_disabled", disabled_paths); - undo_redo->add_do_method(this, "_update_libraries"); - undo_redo->add_undo_property(ProjectSettings::get_singleton(), "gdnative/singletons_disabled", undo_paths); - undo_redo->add_undo_method(this, "_update_libraries"); - undo_redo->commit_action(); -} - -void GDNativeLibrarySingletonEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (is_visible_in_tree()) { - _update_libraries(); - } - } -} - -void GDNativeLibrarySingletonEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_libraries"), &GDNativeLibrarySingletonEditor::_update_libraries); -} - -GDNativeLibrarySingletonEditor::GDNativeLibrarySingletonEditor() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); - libraries = memnew(Tree); - libraries->set_columns(2); - libraries->set_column_titles_visible(true); - libraries->set_column_title(0, TTR("Library")); - libraries->set_column_title(1, TTR("Status")); - libraries->set_hide_root(true); - add_margin_child(TTR("Libraries: "), libraries, true); - updating = false; - libraries->connect("item_edited", callable_mp(this, &GDNativeLibrarySingletonEditor::_item_edited)); - EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &GDNativeLibrarySingletonEditor::_discover_singletons)); -} - -#endif // TOOLS_ENABLED diff --git a/modules/gdnative/icons/GDNativeLibrary.svg b/modules/gdnative/icons/GDNativeLibrary.svg deleted file mode 100644 index 0ddfd4e6f2..0000000000 --- a/modules/gdnative/icons/GDNativeLibrary.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2l2.2578.56445a5 5 0 0 0 .2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 .68555.28516l.5625 2.2539v-5.2695a2 2 0 0 1 -1-1.7305 2 2 0 0 1 1-1.7285v-.27148h1 4.5762a5 5 0 0 0 -.11328-.25195l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm2 7v1 5 1h5c.55228 0 1-.4477 1-1v-5c0-.5523-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#e0e0e0"/></svg> diff --git a/modules/gdnative/icons/NativeScript.svg b/modules/gdnative/icons/NativeScript.svg deleted file mode 100644 index 2224b36b29..0000000000 --- a/modules/gdnative/icons/NativeScript.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625h3v1 1h2v-.95117a2 2 0 0 1 0-.048828 2 2 0 0 1 2-2 2 2 0 0 1 2 2v1h5v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-6 7v4 4h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm6 0v2h2v-2zm3 2v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm-7 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm4 0v4h2v-4z" fill="#e0e0e0"/></svg> diff --git a/modules/gdnative/include/android/godot_android.h b/modules/gdnative/include/android/godot_android.h deleted file mode 100644 index 867ef9e03a..0000000000 --- a/modules/gdnative/include/android/godot_android.h +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************/ -/* godot_android.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 GODOT_ANDROID_GDN_H -#define GODOT_ANDROID_GDN_H - -#include <gdnative/gdnative.h> - -#ifdef __ANDROID__ -#include <jni.h> -#else -#define JNIEnv void -#define jobject void * -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -JNIEnv *GDAPI godot_android_get_env(); -jobject GDAPI godot_android_get_activity(); -jobject GDAPI godot_android_get_surface(); -bool GDAPI godot_android_is_activity_resumed(); - -#ifdef __cplusplus -} -#endif - -#endif /* !GODOT_ANDROID_GDN_H */ diff --git a/modules/gdnative/include/gdnative/aabb.h b/modules/gdnative/include/gdnative/aabb.h deleted file mode 100644 index 860675065d..0000000000 --- a/modules/gdnative/include/gdnative/aabb.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* aabb.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 GODOT_AABB_H -#define GODOT_AABB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_AABB_SIZE (sizeof(godot_real_t) * 6) - -#ifndef GODOT_CORE_API_GODOT_AABB_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_AABB_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_AABB_SIZE]; -} godot_aabb; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_aabb_new(godot_aabb *p_self); -void GDAPI godot_aabb_new_copy(godot_aabb *r_dest, const godot_aabb *p_src); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_AABB_H diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h deleted file mode 100644 index bf4b852449..0000000000 --- a/modules/gdnative/include/gdnative/array.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* array.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 GODOT_ARRAY_H -#define GODOT_ARRAY_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -#define GODOT_ARRAY_SIZE sizeof(void *) - -#ifndef GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_ARRAY_SIZE]; -} godot_array; -#endif - -#include <gdnative/gdnative.h> -#include <gdnative/variant_struct.h> - -void GDAPI godot_array_new(godot_array *p_self); -void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src); -void GDAPI godot_array_destroy(godot_array *p_self); -godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, godot_int p_index); -const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_ARRAY_H diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h deleted file mode 100644 index 5477dbf811..0000000000 --- a/modules/gdnative/include/gdnative/basis.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* basis.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 GODOT_BASIS_H -#define GODOT_BASIS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_BASIS_SIZE (sizeof(godot_real_t) * 9) - -#ifndef GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_BASIS_SIZE]; -} godot_basis; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_basis_new(godot_basis *p_self); -void GDAPI godot_basis_new_copy(godot_basis *r_dest, const godot_basis *p_src); -godot_vector3 GDAPI *godot_basis_operator_index(godot_basis *p_self, godot_int p_index); -const godot_vector3 GDAPI *godot_basis_operator_index_const(const godot_basis *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_BASIS_H diff --git a/modules/gdnative/include/gdnative/callable.h b/modules/gdnative/include/gdnative/callable.h deleted file mode 100644 index 1d52ca7a68..0000000000 --- a/modules/gdnative/include/gdnative/callable.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* callable.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 GODOT_CALLABLE_H -#define GODOT_CALLABLE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -// Alignment hardcoded in `core/variant/callable.h`. -#define GODOT_CALLABLE_SIZE (16) - -#ifndef GODOT_CORE_API_GODOT_CALLABLE_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_CALLABLE_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_CALLABLE_SIZE]; -} godot_callable; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_callable_new(godot_callable *p_self); -void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src); -void GDAPI godot_callable_destroy(godot_callable *p_self); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h deleted file mode 100644 index 3334013147..0000000000 --- a/modules/gdnative/include/gdnative/color.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* color.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 GODOT_COLOR_H -#define GODOT_COLOR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -// Colors should always use 32-bit floats, so don't use real_t here. -#define GODOT_COLOR_SIZE (sizeof(float) * 4) - -#ifndef GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_COLOR_SIZE]; -} godot_color; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_color_new(godot_color *p_self); -void GDAPI godot_color_new_copy(godot_color *r_dest, const godot_color *p_src); -float GDAPI *godot_color_operator_index(godot_color *p_self, godot_int p_index); -const float GDAPI *godot_color_operator_index_const(const godot_color *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_COLOR_H diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h deleted file mode 100644 index b9525fb5e6..0000000000 --- a/modules/gdnative/include/gdnative/dictionary.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* dictionary.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 GODOT_DICTIONARY_H -#define GODOT_DICTIONARY_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -#define GODOT_DICTIONARY_SIZE sizeof(void *) - -#ifndef GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_DICTIONARY_SIZE]; -} godot_dictionary; -#endif - -#include <gdnative/gdnative.h> -#include <gdnative/variant_struct.h> - -void GDAPI godot_dictionary_new(godot_dictionary *p_self); -void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src); -void GDAPI godot_dictionary_destroy(godot_dictionary *p_self); -godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key); -const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_DICTIONARY_H diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h deleted file mode 100644 index d8c290f6bd..0000000000 --- a/modules/gdnative/include/gdnative/gdnative.h +++ /dev/null @@ -1,287 +0,0 @@ -/*************************************************************************/ -/* gdnative.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 GODOT_GDNATIVE_H -#define GODOT_GDNATIVE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_WIN32) || defined(__ANDROID__) -#define GDCALLINGCONV -#define GDAPI GDCALLINGCONV -#elif defined(__APPLE__) -#include "TargetConditionals.h" -#if TARGET_OS_IPHONE -#define GDCALLINGCONV __attribute__((visibility("default"))) -#define GDAPI GDCALLINGCONV -#elif TARGET_OS_MAC -#define GDCALLINGCONV __attribute__((sysv_abi)) -#define GDAPI GDCALLINGCONV -#endif -#else // !_WIN32 && !__APPLE__ -#define GDCALLINGCONV __attribute__((sysv_abi)) -#define GDAPI GDCALLINGCONV -#endif - -// This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!! -#ifdef __GNUC__ -#define GDN_EXPORT __attribute__((visibility("default"))) -#elif defined(_WIN32) -#define GDN_EXPORT __declspec(dllexport) -#else -#define GDN_EXPORT -#endif - -#include <stdbool.h> -#include <stdint.h> - -////// Error - -typedef enum { - GODOT_OK, // (0) - GODOT_FAILED, ///< Generic fail error - GODOT_ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable - GODOT_ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet - GODOT_ERR_UNAUTHORIZED, ///< Missing credentials for requested resource - GODOT_ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5) - GODOT_ERR_OUT_OF_MEMORY, ///< Out of memory - GODOT_ERR_FILE_NOT_FOUND, - GODOT_ERR_FILE_BAD_DRIVE, - GODOT_ERR_FILE_BAD_PATH, - GODOT_ERR_FILE_NO_PERMISSION, // (10) - GODOT_ERR_FILE_ALREADY_IN_USE, - GODOT_ERR_FILE_CANT_OPEN, - GODOT_ERR_FILE_CANT_WRITE, - GODOT_ERR_FILE_CANT_READ, - GODOT_ERR_FILE_UNRECOGNIZED, // (15) - GODOT_ERR_FILE_CORRUPT, - GODOT_ERR_FILE_MISSING_DEPENDENCIES, - GODOT_ERR_FILE_EOF, - GODOT_ERR_CANT_OPEN, ///< Can't open a resource/socket/file - GODOT_ERR_CANT_CREATE, // (20) - GODOT_ERR_QUERY_FAILED, - GODOT_ERR_ALREADY_IN_USE, - GODOT_ERR_LOCKED, ///< resource is locked - GODOT_ERR_TIMEOUT, - GODOT_ERR_CANT_CONNECT, // (25) - GODOT_ERR_CANT_RESOLVE, - GODOT_ERR_CONNECTION_ERROR, - GODOT_ERR_CANT_ACQUIRE_RESOURCE, - GODOT_ERR_CANT_FORK, - GODOT_ERR_INVALID_DATA, ///< Data passed is invalid (30) - GODOT_ERR_INVALID_PARAMETER, ///< Parameter passed is invalid - GODOT_ERR_ALREADY_EXISTS, ///< When adding, item already exists - GODOT_ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist - GODOT_ERR_DATABASE_CANT_READ, ///< database is full - GODOT_ERR_DATABASE_CANT_WRITE, ///< database is full (35) - GODOT_ERR_COMPILATION_FAILED, - GODOT_ERR_METHOD_NOT_FOUND, - GODOT_ERR_LINK_FAILED, - GODOT_ERR_SCRIPT_FAILED, - GODOT_ERR_CYCLIC_LINK, // (40) - GODOT_ERR_INVALID_DECLARATION, - GODOT_ERR_DUPLICATE_SYMBOL, - GODOT_ERR_PARSE_ERROR, - GODOT_ERR_BUSY, - GODOT_ERR_SKIP, // (45) - GODOT_ERR_HELP, ///< user requested help!! - GODOT_ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. - GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames -} godot_error; - -/////// Object (forward declared) -typedef void godot_object; - -/////// String - -#include <gdnative/string.h> - -/////// String name - -#include <gdnative/string_name.h> - -////// Vector2 & Vector2i - -#include <gdnative/vector2.h> - -////// Rect2 & Rect2i - -#include <gdnative/rect2.h> - -////// Vector3 & Vector3i - -#include <gdnative/vector3.h> - -////// Transform2D - -#include <gdnative/transform2d.h> - -/////// Plane - -#include <gdnative/plane.h> - -/////// Quaternion - -#include <gdnative/quaternion.h> - -/////// AABB - -#include <gdnative/aabb.h> - -/////// Basis - -#include <gdnative/basis.h> - -/////// Transform3D - -#include <gdnative/transform_3d.h> - -/////// Color - -#include <gdnative/color.h> - -/////// NodePath - -#include <gdnative/node_path.h> - -/////// RID - -#include <gdnative/rid.h> - -/////// Callable & Signal - -#include <gdnative/callable.h> - -/////// Dictionary - -#include <gdnative/dictionary.h> - -/////// Array - -#include <gdnative/array.h> - -// single API file for Packed*Array -#include <gdnative/packed_arrays.h> - -void GDAPI godot_object_destroy(godot_object *p_o); - -////// Variant - -#include <gdnative/variant.h> - -////// Singleton API - -godot_object GDAPI *godot_global_get_singleton(char *p_name); // Result shouldn't be freed. - -////// MethodBind API - -typedef struct { - uint8_t _dont_touch_that[1]; // TODO -} godot_method_bind; - -godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname); -void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret); -godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error); -////// Script API - -typedef struct godot_gdnative_api_version { - unsigned int major; - unsigned int minor; -} godot_gdnative_api_version; - -typedef struct godot_gdnative_api_struct godot_gdnative_api_struct; - -struct godot_gdnative_api_struct { - unsigned int type; - godot_gdnative_api_version version; - const godot_gdnative_api_struct *next; -}; - -#define GDNATIVE_VERSION_COMPATIBLE(want, have) (want.major == have.major && want.minor <= have.minor) - -typedef struct { - godot_bool in_editor; - uint64_t core_api_hash; - uint64_t editor_api_hash; - uint64_t no_api_hash; - void (*report_version_mismatch)(const godot_object *p_library, const char *p_what, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have); - void (*report_loading_error)(const godot_object *p_library, const char *p_what); - godot_object *gd_native_library; // pointer to GDNativeLibrary that is being initialized - const struct godot_gdnative_core_api_struct *api_struct; - const godot_string *active_library_path; -} godot_gdnative_init_options; - -typedef struct { - godot_bool in_editor; -} godot_gdnative_terminate_options; - -// Calling convention? -typedef godot_object *(*godot_class_constructor)(); - -godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname); - -godot_dictionary GDAPI godot_get_global_constants(); - -////// GDNative procedure types -typedef void (*godot_gdnative_init_fn)(godot_gdnative_init_options *); -typedef void (*godot_gdnative_terminate_fn)(godot_gdnative_terminate_options *); -typedef godot_variant (*godot_gdnative_procedure_fn)(godot_array *); - -////// System Functions - -typedef godot_variant (*native_call_cb)(void *, godot_array *); -void GDAPI godot_register_native_call_type(const char *p_call_type, native_call_cb p_callback); - -//using these will help Godot track how much memory is in use in debug mode -void GDAPI *godot_alloc(int p_bytes); -void GDAPI *godot_realloc(void *p_ptr, int p_bytes); -void GDAPI godot_free(void *p_ptr); - -// Helper print functions. -void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line); -void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line); -void GDAPI godot_print_script_error(const char *p_description, const char *p_function, const char *p_file, int p_line); - -//tags used for safe dynamic casting -void GDAPI *godot_get_class_tag(const godot_string_name *p_class); -godot_object GDAPI *godot_object_cast_to(const godot_object *p_object, void *p_class_tag); - -// equivalent of GDScript's instance_from_id -godot_object GDAPI *godot_instance_from_id(uint64_t p_instance_id); - -uint64_t GDAPI godot_object_get_instance_id(const godot_object *p_object); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_GDNATIVE_H diff --git a/modules/gdnative/include/gdnative/math_defs.h b/modules/gdnative/include/gdnative/math_defs.h deleted file mode 100644 index b5cf389506..0000000000 --- a/modules/gdnative/include/gdnative/math_defs.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************/ -/* math_defs.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 GODOT_GDNATIVE_MATH_DEFS_H -#define GODOT_GDNATIVE_MATH_DEFS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdbool.h> -#include <stdint.h> - -////// bool - -typedef bool godot_bool; - -#define GODOT_TRUE 1 -#define GODOT_FALSE 0 - -/////// int - -typedef int64_t godot_int; - -/////// float - -typedef double godot_float; - -#ifdef REAL_T_IS_DOUBLE -typedef double godot_real_t; -#else -typedef float godot_real_t; -#endif - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_C_H diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h deleted file mode 100644 index a4607c0152..0000000000 --- a/modules/gdnative/include/gdnative/node_path.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* node_path.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 GODOT_NODE_PATH_H -#define GODOT_NODE_PATH_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -#define GODOT_NODE_PATH_SIZE sizeof(void *) - -#ifndef GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_NODE_PATH_SIZE]; -} godot_node_path; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_node_path_new(godot_node_path *p_self); -void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src); -void GDAPI godot_node_path_destroy(godot_node_path *p_self); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_NODE_PATH_H diff --git a/modules/gdnative/include/gdnative/packed_arrays.h b/modules/gdnative/include/gdnative/packed_arrays.h deleted file mode 100644 index f9e4ba3a8d..0000000000 --- a/modules/gdnative/include/gdnative/packed_arrays.h +++ /dev/null @@ -1,255 +0,0 @@ -/*************************************************************************/ -/* packed_arrays.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 GODOT_PACKED_ARRAYS_H -#define GODOT_PACKED_ARRAYS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -/////// PackedByteArray - -#define GODOT_PACKED_BYTE_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_BYTE_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_BYTE_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_BYTE_ARRAY_SIZE]; -} godot_packed_byte_array; -#endif - -/////// PackedInt32Array - -#define GODOT_PACKED_INT32_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_INT32_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_INT32_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_INT32_ARRAY_SIZE]; -} godot_packed_int32_array; -#endif - -/////// PackedInt64Array - -#define GODOT_PACKED_INT64_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_INT64_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_INT64_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_INT64_ARRAY_SIZE]; -} godot_packed_int64_array; -#endif - -/////// PackedFloat32Array - -#define GODOT_PACKED_FLOAT32_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_FLOAT32_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_FLOAT32_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_FLOAT32_ARRAY_SIZE]; -} godot_packed_float32_array; -#endif - -/////// PackedFloat64Array - -#define GODOT_PACKED_FLOAT64_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_FLOAT64_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_FLOAT64_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_FLOAT64_ARRAY_SIZE]; -} godot_packed_float64_array; -#endif - -/////// PackedStringArray - -#define GODOT_PACKED_STRING_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_STRING_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_STRING_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_STRING_ARRAY_SIZE]; -} godot_packed_string_array; -#endif - -/////// PackedVector2Array - -#define GODOT_PACKED_VECTOR2_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_VECTOR2_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_VECTOR2_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_VECTOR2_ARRAY_SIZE]; -} godot_packed_vector2_array; -#endif - -/////// PackedVector2iArray - -#define GODOT_PACKED_VECTOR2I_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_VECTOR2I_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_VECTOR2I_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_VECTOR2I_ARRAY_SIZE]; -} godot_packed_vector2i_array; -#endif - -/////// PackedVector3Array - -#define GODOT_PACKED_VECTOR3_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_VECTOR3_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_VECTOR3_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_VECTOR3_ARRAY_SIZE]; -} godot_packed_vector3_array; -#endif - -/////// PackedVector3iArray - -#define GODOT_PACKED_VECTOR3I_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_VECTOR3I_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_VECTOR3I_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_VECTOR3I_ARRAY_SIZE]; -} godot_packed_vector3i_array; -#endif - -/////// PackedColorArray - -#define GODOT_PACKED_COLOR_ARRAY_SIZE (2 * sizeof(void *)) - -#ifndef GODOT_CORE_API_GODOT_PACKED_COLOR_ARRAY_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PACKED_COLOR_ARRAY_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PACKED_COLOR_ARRAY_SIZE]; -} godot_packed_color_array; -#endif - -#include <gdnative/gdnative.h> - -// Byte. - -void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self); -void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src); -void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self); -uint8_t GDAPI *godot_packed_byte_array_operator_index(godot_packed_byte_array *p_self, godot_int p_index); -const uint8_t GDAPI *godot_packed_byte_array_operator_index_const(const godot_packed_byte_array *p_self, godot_int p_index); - -// Int32. - -void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self); -void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src); -void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self); -int32_t GDAPI *godot_packed_int32_array_operator_index(godot_packed_int32_array *p_self, godot_int p_index); -const int32_t GDAPI *godot_packed_int32_array_operator_index_const(const godot_packed_int32_array *p_self, godot_int p_index); - -// Int64. - -void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self); -void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src); -void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self); -int64_t GDAPI *godot_packed_int64_array_operator_index(godot_packed_int64_array *p_self, godot_int p_index); -const int64_t GDAPI *godot_packed_int64_array_operator_index_const(const godot_packed_int64_array *p_self, godot_int p_index); - -// Float32. - -void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self); -void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src); -void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self); -float GDAPI *godot_packed_float32_array_operator_index(godot_packed_float32_array *p_self, godot_int p_index); -const float GDAPI *godot_packed_float32_array_operator_index_const(const godot_packed_float32_array *p_self, godot_int p_index); - -// Float64. - -void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self); -void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src); -void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self); -double GDAPI *godot_packed_float64_array_operator_index(godot_packed_float64_array *p_self, godot_int p_index); -const double GDAPI *godot_packed_float64_array_operator_index_const(const godot_packed_float64_array *p_self, godot_int p_index); - -// String. - -void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self); -void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src); -void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self); -godot_string GDAPI *godot_packed_string_array_operator_index(godot_packed_string_array *p_self, godot_int p_index); -const godot_string GDAPI *godot_packed_string_array_operator_index_const(const godot_packed_string_array *p_self, godot_int p_index); - -// Vector2. - -void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self); -void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src); -void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self); -godot_vector2 GDAPI *godot_packed_vector2_array_operator_index(godot_packed_vector2_array *p_self, godot_int p_index); -const godot_vector2 GDAPI *godot_packed_vector2_array_operator_index_const(const godot_packed_vector2_array *p_self, godot_int p_index); - -// Vector2i. - -void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self); -void GDAPI godot_packed_vector2i_array_new_copy(godot_packed_vector2i_array *r_dest, const godot_packed_vector2i_array *p_src); -void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self); -godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index(godot_packed_vector2i_array *p_self, godot_int p_index); -const godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index_const(const godot_packed_vector2i_array *p_self, godot_int p_index); - -// Vector3. - -void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self); -void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src); -void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self); -godot_vector3 GDAPI *godot_packed_vector3_array_operator_index(godot_packed_vector3_array *p_self, godot_int p_index); -const godot_vector3 GDAPI *godot_packed_vector3_array_operator_index_const(const godot_packed_vector3_array *p_self, godot_int p_index); - -// Vector3i. - -void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self); -void GDAPI godot_packed_vector3i_array_new_copy(godot_packed_vector3i_array *r_dest, const godot_packed_vector3i_array *p_src); -void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self); -godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index(godot_packed_vector3i_array *p_self, godot_int p_index); -const godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index_const(const godot_packed_vector3i_array *p_self, godot_int p_index); - -// Color. - -void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self); -void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src); -void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self); -godot_color GDAPI *godot_packed_color_array_operator_index(godot_packed_color_array *p_self, godot_int p_index); -const godot_color GDAPI *godot_packed_color_array_operator_index_const(const godot_packed_color_array *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_PACKED_ARRAYS_H diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h deleted file mode 100644 index 6cd0ed6307..0000000000 --- a/modules/gdnative/include/gdnative/plane.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* plane.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 GODOT_PLANE_H -#define GODOT_PLANE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_PLANE_SIZE (sizeof(godot_real_t) * 4) - -#ifndef GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_PLANE_SIZE]; -} godot_plane; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_plane_new(godot_plane *p_self); -void GDAPI godot_plane_new_copy(godot_plane *r_dest, const godot_plane *p_src); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_PLANE_H diff --git a/modules/gdnative/include/gdnative/quaternion.h b/modules/gdnative/include/gdnative/quaternion.h deleted file mode 100644 index 75754e6ab5..0000000000 --- a/modules/gdnative/include/gdnative/quaternion.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* quaternion.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 GODOT_QUATERNION_H -#define GODOT_QUATERNION_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_QUATERNION_SIZE (sizeof(godot_real_t) * 4) - -#ifndef GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_QUATERNION_SIZE]; -} godot_quaternion; -#endif - -#include <gdnative/gdnative.h> - -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_QUATERNION_H diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h deleted file mode 100644 index 326462be43..0000000000 --- a/modules/gdnative/include/gdnative/rect2.h +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************/ -/* rect2.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 GODOT_RECT2_H -#define GODOT_RECT2_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_RECT2_SIZE (sizeof(godot_real_t) * 4) - -#ifndef GODOT_CORE_API_GODOT_RECT2_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_RECT2_TYPE_DEFINED -typedef struct godot_rect2 { - uint8_t _dont_touch_that[GODOT_RECT2_SIZE]; -} godot_rect2; -#endif - -#define GODOT_RECT2I_SIZE (sizeof(int32_t) * 4) - -#ifndef GODOT_CORE_API_GODOT_RECT2I_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_RECT2I_TYPE_DEFINED -typedef struct godot_rect2i { - uint8_t _dont_touch_that[GODOT_RECT2I_SIZE]; -} godot_rect2i; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_rect2_new(godot_rect2 *p_self); -void GDAPI godot_rect2_new_copy(godot_rect2 *r_dest, const godot_rect2 *p_src); -void GDAPI godot_rect2i_new(godot_rect2i *p_self); -void GDAPI godot_rect2i_new_copy(godot_rect2i *r_dest, const godot_rect2i *p_src); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_RECT2_H diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h deleted file mode 100644 index bc832fbeb9..0000000000 --- a/modules/gdnative/include/gdnative/rid.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* rid.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 GODOT_RID_H -#define GODOT_RID_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -#define GODOT_RID_SIZE sizeof(uint64_t) - -#ifndef GODOT_CORE_API_GODOT_RID_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_RID_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_RID_SIZE]; -} godot_rid; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_rid_new(godot_rid *p_self); -void GDAPI godot_rid_new_copy(godot_rid *r_dest, const godot_rid *p_src); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_RID_H diff --git a/modules/gdnative/include/gdnative/signal.h b/modules/gdnative/include/gdnative/signal.h deleted file mode 100644 index 41a76d0510..0000000000 --- a/modules/gdnative/include/gdnative/signal.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* signal.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 GODOT_SIGNAL_H -#define GODOT_SIGNAL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -// Alignment hardcoded in `core/variant/callable.h`. -#define GODOT_SIGNAL_SIZE (16) - -#ifndef GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_SIGNAL_SIZE]; -} godot_signal; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_signal_new(godot_signal *p_self); -void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src); -void GDAPI godot_signal_destroy(godot_signal *p_self); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h deleted file mode 100644 index 79de52c80f..0000000000 --- a/modules/gdnative/include/gdnative/string.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************/ -/* string.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 GODOT_STRING_H -#define GODOT_STRING_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stddef.h> -#include <stdint.h> - -#ifndef __cplusplus -typedef uint16_t char16_t; -typedef uint32_t char32_t; -#endif - -typedef char32_t godot_char_type; - -#define GODOT_STRING_SIZE sizeof(void *) - -#ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_STRING_SIZE]; -} godot_string; -#endif - -#include <gdnative/gdnative.h> -#include <gdnative/math_defs.h> - -void GDAPI godot_string_new(godot_string *r_dest); -void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src); -void GDAPI godot_string_destroy(godot_string *p_self); - -void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents); -void GDAPI godot_string_new_with_utf8_chars(godot_string *r_dest, const char *p_contents); -void GDAPI godot_string_new_with_utf16_chars(godot_string *r_dest, const char16_t *p_contents); -void GDAPI godot_string_new_with_utf32_chars(godot_string *r_dest, const char32_t *p_contents); -void GDAPI godot_string_new_with_wide_chars(godot_string *r_dest, const wchar_t *p_contents); - -void GDAPI godot_string_new_with_latin1_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size); -void GDAPI godot_string_new_with_utf8_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size); -void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const char16_t *p_contents, const int p_size); -void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size); -void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size); - -const char GDAPI *godot_string_to_latin1_chars(const godot_string *p_self); -const char GDAPI *godot_string_to_utf8_chars(const godot_string *p_self); -const char16_t GDAPI *godot_string_to_utf16_chars(const godot_string *p_self); -const char32_t GDAPI *godot_string_to_utf32_chars(const godot_string *p_self); -const wchar_t GDAPI *godot_string_to_wide_chars(const godot_string *p_self); - -char32_t GDAPI *godot_string_operator_index(godot_string *p_self, godot_int p_index); -const char32_t GDAPI *godot_string_operator_index_const(const godot_string *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_STRING_H diff --git a/modules/gdnative/include/gdnative/string_name.h b/modules/gdnative/include/gdnative/string_name.h deleted file mode 100644 index 346f626e81..0000000000 --- a/modules/gdnative/include/gdnative/string_name.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* string_name.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 GODOT_STRING_NAME_H -#define GODOT_STRING_NAME_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> -#include <wchar.h> - -#define GODOT_STRING_NAME_SIZE sizeof(void *) - -#ifndef GODOT_CORE_API_GODOT_STRING_NAME_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_STRING_NAME_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_STRING_NAME_SIZE]; -} godot_string_name; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_string_name_new(godot_string_name *r_dest); -void GDAPI godot_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src); -void GDAPI godot_string_name_destroy(godot_string_name *p_self); - -void GDAPI godot_string_name_new_with_latin1_chars(godot_string_name *r_dest, const char *p_contents); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_STRING_NAME_H diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h deleted file mode 100644 index 5acb172081..0000000000 --- a/modules/gdnative/include/gdnative/transform2d.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* transform2d.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 GODOT_TRANSFORM2D_H -#define GODOT_TRANSFORM2D_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_TRANSFORM2D_SIZE (sizeof(godot_real_t) * 6) - -#ifndef GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_TRANSFORM2D_SIZE]; -} godot_transform2d; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_transform2d_new(godot_transform2d *p_self); -void GDAPI godot_transform2d_new_copy(godot_transform2d *r_dest, const godot_transform2d *p_src); -godot_vector2 GDAPI *godot_transform2d_operator_index(godot_transform2d *p_self, godot_int p_index); -const godot_vector2 GDAPI *godot_transform2d_operator_index_const(const godot_transform2d *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_TRANSFORM2D_H diff --git a/modules/gdnative/include/gdnative/transform_3d.h b/modules/gdnative/include/gdnative/transform_3d.h deleted file mode 100644 index 97ad451e9b..0000000000 --- a/modules/gdnative/include/gdnative/transform_3d.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* transform_3d.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 GODOT_TRANSFORM3D_H -#define GODOT_TRANSFORM3D_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_TRANSFORM3D_SIZE (sizeof(godot_real_t) * 12) - -#ifndef GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_TRANSFORM3D_SIZE]; -} godot_transform3d; -#endif - -#include <gdnative/gdnative.h> - -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_TRANSFORM3D_H diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h deleted file mode 100644 index a88bd2878a..0000000000 --- a/modules/gdnative/include/gdnative/variant.h +++ /dev/null @@ -1,425 +0,0 @@ -/*************************************************************************/ -/* variant.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 GODOT_VARIANT_H -#define GODOT_VARIANT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> -#include <gdnative/variant_struct.h> - -typedef enum godot_variant_type { - GODOT_VARIANT_TYPE_NIL, - - // atomic types - GODOT_VARIANT_TYPE_BOOL, - GODOT_VARIANT_TYPE_INT, - GODOT_VARIANT_TYPE_FLOAT, - GODOT_VARIANT_TYPE_STRING, - - // math types - GODOT_VARIANT_TYPE_VECTOR2, - GODOT_VARIANT_TYPE_VECTOR2I, - GODOT_VARIANT_TYPE_RECT2, - GODOT_VARIANT_TYPE_RECT2I, - GODOT_VARIANT_TYPE_VECTOR3, - GODOT_VARIANT_TYPE_VECTOR3I, - GODOT_VARIANT_TYPE_TRANSFORM2D, - GODOT_VARIANT_TYPE_PLANE, - GODOT_VARIANT_TYPE_QUATERNION, - GODOT_VARIANT_TYPE_AABB, - GODOT_VARIANT_TYPE_BASIS, - GODOT_VARIANT_TYPE_TRANSFORM3D, - - // misc types - GODOT_VARIANT_TYPE_COLOR, - GODOT_VARIANT_TYPE_STRING_NAME, - GODOT_VARIANT_TYPE_NODE_PATH, - GODOT_VARIANT_TYPE_RID, - GODOT_VARIANT_TYPE_OBJECT, - GODOT_VARIANT_TYPE_CALLABLE, - GODOT_VARIANT_TYPE_SIGNAL, - GODOT_VARIANT_TYPE_DICTIONARY, - GODOT_VARIANT_TYPE_ARRAY, - - // arrays - GODOT_VARIANT_TYPE_PACKED_BYTE_ARRAY, - GODOT_VARIANT_TYPE_PACKED_INT32_ARRAY, - GODOT_VARIANT_TYPE_PACKED_INT64_ARRAY, - GODOT_VARIANT_TYPE_PACKED_FLOAT32_ARRAY, - GODOT_VARIANT_TYPE_PACKED_FLOAT64_ARRAY, - GODOT_VARIANT_TYPE_PACKED_STRING_ARRAY, - GODOT_VARIANT_TYPE_PACKED_VECTOR2_ARRAY, - GODOT_VARIANT_TYPE_PACKED_VECTOR3_ARRAY, - GODOT_VARIANT_TYPE_PACKED_COLOR_ARRAY, -} godot_variant_type; - -typedef enum godot_variant_call_error_error { - GODOT_CALL_ERROR_CALL_OK, - GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD, - GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT, - GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS, - GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS, - GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL, -} godot_variant_call_error_error; - -typedef struct godot_variant_call_error { - godot_variant_call_error_error error; - int argument; - godot_variant_type expected; -} godot_variant_call_error; - -typedef enum godot_variant_operator { - // comparison - GODOT_VARIANT_OP_EQUAL, - GODOT_VARIANT_OP_NOT_EQUAL, - GODOT_VARIANT_OP_LESS, - GODOT_VARIANT_OP_LESS_EQUAL, - GODOT_VARIANT_OP_GREATER, - GODOT_VARIANT_OP_GREATER_EQUAL, - - // mathematic - GODOT_VARIANT_OP_ADD, - GODOT_VARIANT_OP_SUBTRACT, - GODOT_VARIANT_OP_MULTIPLY, - GODOT_VARIANT_OP_DIVIDE, - GODOT_VARIANT_OP_NEGATE, - GODOT_VARIANT_OP_POSITIVE, - GODOT_VARIANT_OP_MODULE, - GODOT_VARIANT_OP_STRING_CONCAT, - - // bitwise - GODOT_VARIANT_OP_SHIFT_LEFT, - GODOT_VARIANT_OP_SHIFT_RIGHT, - GODOT_VARIANT_OP_BIT_AND, - GODOT_VARIANT_OP_BIT_OR, - GODOT_VARIANT_OP_BIT_XOR, - GODOT_VARIANT_OP_BIT_NEGATE, - - // logic - GODOT_VARIANT_OP_AND, - GODOT_VARIANT_OP_OR, - GODOT_VARIANT_OP_XOR, - GODOT_VARIANT_OP_NOT, - - // containment - GODOT_VARIANT_OP_IN, - - GODOT_VARIANT_OP_MAX, -} godot_variant_operator; - -typedef enum godot_variant_utility_function_type { - GODOT_UTILITY_FUNC_TYPE_MATH, - GODOT_UTILITY_FUNC_TYPE_RANDOM, - GODOT_UTILITY_FUNC_TYPE_GENERAL, -} godot_variant_utility_function_type; - -// Types for function pointers. -typedef void (*godot_validated_operator_evaluator)(const godot_variant *p_left, const godot_variant *p_right, godot_variant *r_result); -typedef void (*godot_ptr_operator_evaluator)(const void *p_left, const void *p_right, void *r_result); -typedef void (*godot_validated_builtin_method)(godot_variant *p_base, const godot_variant **p_args, int p_argument_count, godot_variant *r_return); -typedef void (*godot_ptr_builtin_method)(void *p_base, const void **p_args, void *r_return, int p_argument_count); -typedef void (*godot_validated_constructor)(godot_variant *p_base, const godot_variant **p_args); -typedef void (*godot_ptr_constructor)(void *p_base, const void **p_args); -typedef void (*godot_validated_setter)(godot_variant *p_base, const godot_variant *p_value); -typedef void (*godot_validated_getter)(const godot_variant *p_base, godot_variant *r_value); -typedef void (*godot_ptr_setter)(void *p_base, const void *p_value); -typedef void (*godot_ptr_getter)(const void *p_base, void *r_value); -typedef void (*godot_validated_indexed_setter)(godot_variant *p_base, godot_int p_index, const godot_variant *p_value, bool *r_oob); -typedef void (*godot_validated_indexed_getter)(const godot_variant *p_base, godot_int p_index, godot_variant *r_value, bool *r_oob); -typedef void (*godot_ptr_indexed_setter)(void *p_base, godot_int p_index, const void *p_value); -typedef void (*godot_ptr_indexed_getter)(const void *p_base, godot_int p_index, void *r_value); -typedef void (*godot_validated_keyed_setter)(godot_variant *p_base, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid); -typedef void (*godot_validated_keyed_getter)(const godot_variant *p_base, const godot_variant *p_key, godot_variant *r_value, bool *r_valid); -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 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); - -#include <gdnative/aabb.h> -#include <gdnative/array.h> -#include <gdnative/basis.h> -#include <gdnative/callable.h> -#include <gdnative/color.h> -#include <gdnative/dictionary.h> -#include <gdnative/node_path.h> -#include <gdnative/packed_arrays.h> -#include <gdnative/plane.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/transform2d.h> -#include <gdnative/transform_3d.h> -#include <gdnative/variant.h> -#include <gdnative/vector2.h> -#include <gdnative/vector3.h> - -#include <gdnative/gdnative.h> - -// Memory. - -void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_src); - -void GDAPI godot_variant_new_nil(godot_variant *r_dest); -void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b); -void GDAPI godot_variant_new_int(godot_variant *r_dest, const godot_int p_i); -void GDAPI godot_variant_new_float(godot_variant *r_dest, const godot_float p_f); -void GDAPI godot_variant_new_string(godot_variant *r_dest, const godot_string *p_s); -void GDAPI godot_variant_new_vector2(godot_variant *r_dest, const godot_vector2 *p_v2); -void GDAPI godot_variant_new_vector2i(godot_variant *r_dest, const godot_vector2i *p_v2); -void GDAPI godot_variant_new_rect2(godot_variant *r_dest, const godot_rect2 *p_rect2); -void GDAPI godot_variant_new_rect2i(godot_variant *r_dest, const godot_rect2i *p_rect2); -void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3 *p_v3); -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_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_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); -void GDAPI godot_variant_new_rid(godot_variant *r_dest, const godot_rid *p_rid); -void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj); -void GDAPI godot_variant_new_callable(godot_variant *r_dest, const godot_callable *p_callable); -void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p_signal); -void GDAPI godot_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict); -void GDAPI godot_variant_new_array(godot_variant *r_dest, const godot_array *p_arr); -void GDAPI godot_variant_new_packed_byte_array(godot_variant *r_dest, const godot_packed_byte_array *p_pba); -void GDAPI godot_variant_new_packed_int32_array(godot_variant *r_dest, const godot_packed_int32_array *p_pia); -void GDAPI godot_variant_new_packed_int64_array(godot_variant *r_dest, const godot_packed_int64_array *p_pia); -void GDAPI godot_variant_new_packed_float32_array(godot_variant *r_dest, const godot_packed_float32_array *p_pra); -void GDAPI godot_variant_new_packed_float64_array(godot_variant *r_dest, const godot_packed_float64_array *p_pra); -void GDAPI godot_variant_new_packed_string_array(godot_variant *r_dest, const godot_packed_string_array *p_psa); -void GDAPI godot_variant_new_packed_vector2_array(godot_variant *r_dest, const godot_packed_vector2_array *p_pv2a); -void GDAPI godot_variant_new_packed_vector3_array(godot_variant *r_dest, const godot_packed_vector3_array *p_pv3a); -void GDAPI godot_variant_new_packed_color_array(godot_variant *r_dest, const godot_packed_color_array *p_pca); - -godot_bool GDAPI godot_variant_as_bool(const godot_variant *p_self); -godot_int GDAPI godot_variant_as_int(const godot_variant *p_self); -godot_float GDAPI godot_variant_as_float(const godot_variant *p_self); -godot_string GDAPI godot_variant_as_string(const godot_variant *p_self); -godot_vector2 GDAPI godot_variant_as_vector2(const godot_variant *p_self); -godot_vector2i GDAPI godot_variant_as_vector2i(const godot_variant *p_self); -godot_rect2 GDAPI godot_variant_as_rect2(const godot_variant *p_self); -godot_rect2i GDAPI godot_variant_as_rect2i(const godot_variant *p_self); -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_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_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); -godot_rid GDAPI godot_variant_as_rid(const godot_variant *p_self); -godot_object GDAPI *godot_variant_as_object(const godot_variant *p_self); -godot_callable GDAPI godot_variant_as_callable(const godot_variant *p_self); -godot_signal GDAPI godot_variant_as_signal(const godot_variant *p_self); -godot_dictionary GDAPI godot_variant_as_dictionary(const godot_variant *p_self); -godot_array GDAPI godot_variant_as_array(const godot_variant *p_self); -godot_packed_byte_array GDAPI godot_variant_as_packed_byte_array(const godot_variant *p_self); -godot_packed_int32_array GDAPI godot_variant_as_packed_int32_array(const godot_variant *p_self); -godot_packed_int64_array GDAPI godot_variant_as_packed_int64_array(const godot_variant *p_self); -godot_packed_float32_array GDAPI godot_variant_as_packed_float32_array(const godot_variant *p_self); -godot_packed_float64_array GDAPI godot_variant_as_packed_float64_array(const godot_variant *p_self); -godot_packed_string_array GDAPI godot_variant_as_packed_string_array(const godot_variant *p_self); -godot_packed_vector2_array GDAPI godot_variant_as_packed_vector2_array(const godot_variant *p_self); -godot_packed_vector3_array GDAPI godot_variant_as_packed_vector3_array(const godot_variant *p_self); -godot_packed_color_array GDAPI godot_variant_as_packed_color_array(const godot_variant *p_self); - -void GDAPI godot_variant_destroy(godot_variant *p_self); - -// Dynamic interaction. - -void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error); -void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error); -void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error); -void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error); -void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid); -void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid); -void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid); -void GDAPI godot_variant_set_named_with_cstring(godot_variant *p_self, const char *p_name, const godot_variant *p_value, bool *r_valid); -void GDAPI godot_variant_set_keyed(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid); -void GDAPI godot_variant_set_indexed(godot_variant *p_self, godot_int p_index, const godot_variant *p_value, bool *r_valid, bool *r_oob); -godot_variant GDAPI godot_variant_get(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid); -godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const godot_string_name *p_key, bool *r_valid); -godot_variant GDAPI godot_variant_get_named_with_cstring(const godot_variant *p_self, const char *p_key, bool *r_valid); -godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid); -godot_variant GDAPI godot_variant_get_indexed(const godot_variant *p_self, godot_int p_index, bool *r_valid, bool *r_oob); -/// Iteration. -bool GDAPI godot_variant_iter_init(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid); -bool GDAPI godot_variant_iter_next(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid); -godot_variant GDAPI godot_variant_iter_get(const godot_variant *p_self, godot_variant *r_iter, bool *r_valid); - -/// Variant functions. -godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const godot_variant *p_other); -godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self); -void GDAPI godot_variant_blend(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst); -void GDAPI godot_variant_interpolate(const godot_variant *p_a, const godot_variant *p_b, float p_c, godot_variant *r_dst); -godot_variant GDAPI godot_variant_duplicate(const godot_variant *p_self, godot_bool p_deep); -godot_string GDAPI godot_variant_stringify(const godot_variant *p_self); - -// Discovery API. - -/// Operators. -godot_validated_operator_evaluator GDAPI godot_variant_get_validated_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b); -godot_ptr_operator_evaluator GDAPI godot_variant_get_ptr_operator_evaluator(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b); -godot_variant_type GDAPI godot_variant_get_operator_return_type(godot_variant_operator p_operator, godot_variant_type p_type_a, godot_variant_type p_type_b); -godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_operator); - -/// Built-in methods. -bool GDAPI godot_variant_has_builtin_method(godot_variant_type p_type, const godot_string_name *p_method); -bool GDAPI godot_variant_has_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method); -godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method(godot_variant_type p_type, const godot_string_name *p_method); -godot_validated_builtin_method GDAPI godot_variant_get_validated_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method); -godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method(godot_variant_type p_type, const godot_string_name *p_method); -godot_ptr_builtin_method GDAPI godot_variant_get_ptr_builtin_method_with_cstring(godot_variant_type p_type, const char *p_method); -int GDAPI godot_variant_get_builtin_method_argument_count(godot_variant_type p_type, const godot_string_name *p_method); -int GDAPI godot_variant_get_builtin_method_argument_count_with_cstring(godot_variant_type p_type, const char *p_method); -godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type(godot_variant_type p_type, const godot_string_name *p_method, int p_argument); -godot_variant_type GDAPI godot_variant_get_builtin_method_argument_type_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument); -godot_string GDAPI godot_variant_get_builtin_method_argument_name(godot_variant_type p_type, const godot_string_name *p_method, int p_argument); -godot_string GDAPI godot_variant_get_builtin_method_argument_name_with_cstring(godot_variant_type p_type, const char *p_method, int p_argument); -bool GDAPI godot_variant_has_builtin_method_return_value(godot_variant_type p_type, const godot_string_name *p_method); -bool GDAPI godot_variant_has_builtin_method_return_value_with_cstring(godot_variant_type p_type, const char *p_method); -godot_variant_type GDAPI godot_variant_get_builtin_method_return_type(godot_variant_type p_type, const godot_string_name *p_method); -godot_variant_type GDAPI godot_variant_get_builtin_method_return_type_with_cstring(godot_variant_type p_type, const char *p_method); -bool GDAPI godot_variant_is_builtin_method_const(godot_variant_type p_type, const godot_string_name *p_method); -bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type p_type, const char *p_method); -bool GDAPI godot_variant_is_builtin_method_static(godot_variant_type p_type, const godot_string_name *p_method); -bool GDAPI godot_variant_is_builtin_method_static_with_cstring(godot_variant_type p_type, const char *p_method); -bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method); -bool GDAPI godot_variant_is_builtin_method_vararg_with_cstring(godot_variant_type p_type, const char *p_method); -int GDAPI godot_variant_get_builtin_method_count(godot_variant_type p_type); -void GDAPI godot_variant_get_builtin_method_list(godot_variant_type p_type, godot_string_name *r_list); - -/// Constructors. -int GDAPI godot_variant_get_constructor_count(godot_variant_type p_type); -godot_validated_constructor GDAPI godot_variant_get_validated_constructor(godot_variant_type p_type, int p_constructor); -godot_ptr_constructor GDAPI godot_variant_get_ptr_constructor(godot_variant_type p_type, int p_constructor); -int GDAPI godot_variant_get_constructor_argument_count(godot_variant_type p_type, int p_constructor); -godot_variant_type GDAPI godot_variant_get_constructor_argument_type(godot_variant_type p_type, int p_constructor, int p_argument); -godot_string GDAPI godot_variant_get_constructor_argument_name(godot_variant_type p_type, int p_constructor, int p_argument); -void GDAPI godot_variant_construct(godot_variant_type p_type, godot_variant *p_base, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error); - -/// Properties. -godot_variant_type GDAPI godot_variant_get_member_type(godot_variant_type p_type, const godot_string_name *p_member); -godot_variant_type GDAPI godot_variant_get_member_type_with_cstring(godot_variant_type p_type, const char *p_member); -int GDAPI godot_variant_get_member_count(godot_variant_type p_type); -void GDAPI godot_variant_get_member_list(godot_variant_type p_type, godot_string_name *r_list); -godot_validated_setter GDAPI godot_variant_get_validated_setter(godot_variant_type p_type, const godot_string_name *p_member); -godot_validated_setter GDAPI godot_variant_get_validated_setter_with_cstring(godot_variant_type p_type, const char *p_member); -godot_validated_getter GDAPI godot_variant_get_validated_getter(godot_variant_type p_type, const godot_string_name *p_member); -godot_validated_getter GDAPI godot_variant_get_validated_getter_with_cstring(godot_variant_type p_type, const char *p_member); -godot_ptr_setter GDAPI godot_variant_get_ptr_setter(godot_variant_type p_type, const godot_string_name *p_member); -godot_ptr_setter GDAPI godot_variant_get_ptr_setter_with_cstring(godot_variant_type p_type, const char *p_member); -godot_ptr_getter GDAPI godot_variant_get_ptr_getter(godot_variant_type p_type, const godot_string_name *p_member); -godot_ptr_getter GDAPI godot_variant_get_ptr_getter_with_cstring(godot_variant_type p_type, const char *p_member); - -/// Indexing. -bool GDAPI godot_variant_has_indexing(godot_variant_type p_type); -godot_variant_type GDAPI godot_variant_get_indexed_element_type(godot_variant_type p_type); -godot_validated_indexed_setter GDAPI godot_variant_get_validated_indexed_setter(godot_variant_type p_type); -godot_validated_indexed_getter GDAPI godot_variant_get_validated_indexed_getter(godot_variant_type p_type); -godot_ptr_indexed_setter GDAPI godot_variant_get_ptr_indexed_setter(godot_variant_type p_type); -godot_ptr_indexed_getter GDAPI godot_variant_get_ptr_indexed_getter(godot_variant_type p_type); -uint64_t GDAPI godot_variant_get_indexed_size(const godot_variant *p_self); - -/// Keying. -bool GDAPI godot_variant_is_keyed(godot_variant_type p_type); -godot_validated_keyed_setter GDAPI godot_variant_get_validated_keyed_setter(godot_variant_type p_type); -godot_validated_keyed_getter GDAPI godot_variant_get_validated_keyed_getter(godot_variant_type p_type); -godot_validated_keyed_checker GDAPI godot_variant_get_validated_keyed_checker(godot_variant_type p_type); -godot_ptr_keyed_setter GDAPI godot_variant_get_ptr_keyed_setter(godot_variant_type p_type); -godot_ptr_keyed_getter GDAPI godot_variant_get_ptr_keyed_getter(godot_variant_type p_type); -godot_ptr_keyed_checker GDAPI godot_variant_get_ptr_keyed_checker(godot_variant_type p_type); - -/// Constants. -int GDAPI godot_variant_get_constants_count(godot_variant_type p_type); -void GDAPI godot_variant_get_constants_list(godot_variant_type p_type, godot_string_name *r_list); -bool GDAPI godot_variant_has_constant(godot_variant_type p_type, const godot_string_name *p_constant); -bool GDAPI godot_variant_has_constant_with_cstring(godot_variant_type p_type, const char *p_constant); -godot_variant GDAPI godot_variant_get_constant_value(godot_variant_type p_type, const godot_string_name *p_constant); -godot_variant GDAPI godot_variant_get_constant_value_with_cstring(godot_variant_type p_type, const char *p_constant); - -/// Utilities. -bool GDAPI godot_variant_has_utility_function(const godot_string_name *p_function); -bool GDAPI godot_variant_has_utility_function_with_cstring(const char *p_function); -void GDAPI godot_variant_call_utility_function(const godot_string_name *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error); -void GDAPI godot_variant_call_utility_function_with_cstring(const char *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error); -godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function(const godot_string_name *p_function); -godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function_with_cstring(const char *p_function); -godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function(const godot_string_name *p_function); -godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function_with_cstring(const char *p_function); -godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type(const godot_string_name *p_function); -godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type_with_cstring(const char *p_function); -int GDAPI godot_variant_get_utility_function_argument_count(const godot_string_name *p_function); -int GDAPI godot_variant_get_utility_function_argument_count_with_cstring(const char *p_function); -godot_variant_type GDAPI godot_variant_get_utility_function_argument_type(const godot_string_name *p_function, int p_argument); -godot_variant_type GDAPI godot_variant_get_utility_function_argument_type_with_cstring(const char *p_function, int p_argument); -godot_string GDAPI godot_variant_get_utility_function_argument_name(const godot_string_name *p_function, int p_argument); -godot_string GDAPI godot_variant_get_utility_function_argument_name_with_cstring(const char *p_function, int p_argument); -bool GDAPI godot_variant_has_utility_function_return_value(const godot_string_name *p_function); -bool GDAPI godot_variant_has_utility_function_return_value_with_cstring(const char *p_function); -godot_variant_type GDAPI godot_variant_get_utility_function_return_type(const godot_string_name *p_function); -godot_variant_type GDAPI godot_variant_get_utility_function_return_type_with_cstring(const char *p_function); -bool GDAPI godot_variant_is_utility_function_vararg(const godot_string_name *p_function); -bool GDAPI godot_variant_is_utility_function_vararg_with_cstring(const char *p_function); -int GDAPI godot_variant_get_utility_function_count(); -void GDAPI godot_variant_get_utility_function_list(godot_string_name *r_functions); - -// Introspection. - -godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_self); -bool GDAPI godot_variant_has_method(const godot_variant *p_self, const godot_string_name *p_method); -bool GDAPI godot_variant_has_member(godot_variant_type p_type, const godot_string_name *p_member); -bool GDAPI godot_variant_has_key(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid); - -godot_string GDAPI godot_variant_get_type_name(godot_variant_type p_type); -bool GDAPI godot_variant_can_convert(godot_variant_type p_from, godot_variant_type p_to); -bool GDAPI godot_variant_can_convert_strict(godot_variant_type p_from, godot_variant_type p_to); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/gdnative/include/gdnative/variant_struct.h b/modules/gdnative/include/gdnative/variant_struct.h deleted file mode 100644 index 321c76c206..0000000000 --- a/modules/gdnative/include/gdnative/variant_struct.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************/ -/* variant_struct.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 GODOT_VARIANT_STRUCT_H -#define GODOT_VARIANT_STRUCT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_VARIANT_SIZE (sizeof(godot_real_t) * 4 + sizeof(int64_t)) - -#ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_VARIANT_SIZE]; -} godot_variant; -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h deleted file mode 100644 index 00faffbad7..0000000000 --- a/modules/gdnative/include/gdnative/vector2.h +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************/ -/* vector2.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 GODOT_VECTOR2_H -#define GODOT_VECTOR2_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_VECTOR2_SIZE (sizeof(godot_real_t) * 2) - -#ifndef GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_VECTOR2_SIZE]; -} godot_vector2; -#endif - -#define GODOT_VECTOR2I_SIZE (sizeof(int32_t) * 2) - -#ifndef GODOT_CORE_API_GODOT_VECTOR2I_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_VECTOR2I_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_VECTOR2I_SIZE]; -} godot_vector2i; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_vector2_new(godot_vector2 *p_self); -void GDAPI godot_vector2_new_copy(godot_vector2 *r_dest, const godot_vector2 *p_src); -void GDAPI godot_vector2i_new(godot_vector2i *p_self); -void GDAPI godot_vector2i_new_copy(godot_vector2i *r_dest, const godot_vector2i *p_src); -godot_real_t GDAPI *godot_vector2_operator_index(godot_vector2 *p_self, godot_int p_index); -const godot_real_t GDAPI *godot_vector2_operator_index_const(const godot_vector2 *p_self, godot_int p_index); -int32_t GDAPI *godot_vector2i_operator_index(godot_vector2i *p_self, godot_int p_index); -const int32_t GDAPI *godot_vector2i_operator_index_const(const godot_vector2i *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_VECTOR2_H diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h deleted file mode 100644 index 7db093ce52..0000000000 --- a/modules/gdnative/include/gdnative/vector3.h +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************/ -/* vector3.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 GODOT_VECTOR3_H -#define GODOT_VECTOR3_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <gdnative/math_defs.h> - -#define GODOT_VECTOR3_SIZE (sizeof(godot_real_t) * 3) - -#ifndef GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_VECTOR3_SIZE]; -} godot_vector3; -#endif - -#define GODOT_VECTOR3I_SIZE (sizeof(int32_t) * 3) - -#ifndef GODOT_CORE_API_GODOT_VECTOR3I_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_VECTOR3I_TYPE_DEFINED -typedef struct { - uint8_t _dont_touch_that[GODOT_VECTOR3I_SIZE]; -} godot_vector3i; -#endif - -#include <gdnative/gdnative.h> - -void GDAPI godot_vector3_new(godot_vector3 *p_self); -void GDAPI godot_vector3_new_copy(godot_vector3 *r_dest, const godot_vector3 *p_src); -void GDAPI godot_vector3i_new(godot_vector3i *p_self); -void GDAPI godot_vector3i_new_copy(godot_vector3i *r_dest, const godot_vector3i *p_src); -godot_real_t GDAPI *godot_vector3_operator_index(godot_vector3 *p_self, godot_int p_index); -const godot_real_t GDAPI *godot_vector3_operator_index_const(const godot_vector3 *p_self, godot_int p_index); -int32_t GDAPI *godot_vector3i_operator_index(godot_vector3i *p_self, godot_int p_index); -const int32_t GDAPI *godot_vector3i_operator_index_const(const godot_vector3i *p_self, godot_int p_index); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_VECTOR3_H diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h deleted file mode 100644 index bc53a4001d..0000000000 --- a/modules/gdnative/include/nativescript/godot_nativescript.h +++ /dev/null @@ -1,232 +0,0 @@ -/*************************************************************************/ -/* godot_nativescript.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 GODOT_NATIVESCRIPT_H -#define GODOT_NATIVESCRIPT_H - -#include <gdnative/gdnative.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - GODOT_METHOD_RPC_MODE_DISABLED, - GODOT_METHOD_RPC_MODE_ANY_PEER, - GODOT_METHOD_RPC_MODE_AUTHORITY, -} godot_nativescript_method_rpc_mode; - -typedef enum { - GODOT_PROPERTY_HINT_NONE, ///< no hint provided. - GODOT_PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional" - GODOT_PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit - GODOT_PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" - GODOT_PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) - GODOT_PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) - GODOT_PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) - GODOT_PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) - GODOT_PROPERTY_HINT_LAYERS_2D_RENDER, - GODOT_PROPERTY_HINT_LAYERS_2D_PHYSICS, - GODOT_PROPERTY_HINT_LAYERS_2D_NAVIGATION, - GODOT_PROPERTY_HINT_LAYERS_3D_RENDER, - GODOT_PROPERTY_HINT_LAYERS_3D_PHYSICS, - GODOT_PROPERTY_HINT_LAYERS_3D_NAVIGATION, - GODOT_PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc," - GODOT_PROPERTY_HINT_DIR, ///< a directory path must be passed - GODOT_PROPERTY_HINT_GLOBAL_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc," - GODOT_PROPERTY_HINT_GLOBAL_DIR, ///< a directory path must be passed - GODOT_PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type - GODOT_PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines - GODOT_PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties - GODOT_PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color - GODOT_PROPERTY_HINT_IMAGE_COMPRESS_LOSSY, - GODOT_PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS, - GODOT_PROPERTY_HINT_OBJECT_ID, - GODOT_PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose - GODOT_PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts) - GODOT_PROPERTY_HINT_METHOD_OF_VARIANT_TYPE, ///< a method of a type - GODOT_PROPERTY_HINT_METHOD_OF_BASE_TYPE, ///< a method of a base type - GODOT_PROPERTY_HINT_METHOD_OF_INSTANCE, ///< a method of an instance - GODOT_PROPERTY_HINT_METHOD_OF_SCRIPT, ///< a method of a script & base - GODOT_PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, ///< a property of a type - GODOT_PROPERTY_HINT_PROPERTY_OF_BASE_TYPE, ///< a property of a base type - GODOT_PROPERTY_HINT_PROPERTY_OF_INSTANCE, ///< a property of an instance - GODOT_PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base - GODOT_PROPERTY_HINT_MAX, -} godot_nativescript_property_hint; - -typedef enum { - GODOT_PROPERTY_USAGE_STORAGE = 1, - GODOT_PROPERTY_USAGE_EDITOR = 2, - GODOT_PROPERTY_USAGE_NETWORK = 4, - GODOT_PROPERTY_USAGE_EDITOR_HELPER = 8, - GODOT_PROPERTY_USAGE_CHECKABLE = 16, //used for editing global variables - GODOT_PROPERTY_USAGE_CHECKED = 32, //used for editing global variables - GODOT_PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings - GODOT_PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor - GODOT_PROPERTY_USAGE_CATEGORY = 256, - GODOT_PROPERTY_USAGE_SUBGROUP = 512, - GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE = 2048, - GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED = 4096, - GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE = 8192, - GODOT_PROPERTY_USAGE_STORE_IF_NULL = 16384, - GODOT_PROPERTY_USAGE_ANIMATE_AS_TRIGGER = 32768, - GODOT_PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 65536, - - GODOT_PROPERTY_USAGE_DEFAULT = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_EDITOR | GODOT_PROPERTY_USAGE_NETWORK, - GODOT_PROPERTY_USAGE_DEFAULT_INTL = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_EDITOR | GODOT_PROPERTY_USAGE_NETWORK | GODOT_PROPERTY_USAGE_INTERNATIONALIZED, - GODOT_PROPERTY_USAGE_NO_EDITOR = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_NETWORK, -} godot_nativescript_property_usage_flags; - -typedef struct { - godot_nativescript_method_rpc_mode rset_type; - - godot_int type; - godot_nativescript_property_hint hint; - godot_string hint_string; - godot_nativescript_property_usage_flags usage; - godot_variant default_value; -} godot_nativescript_property_attributes; - -typedef struct { - // instance pointer, method_data - return user data - GDCALLINGCONV void *(*create_func)(godot_object *, void *); - void *method_data; - GDCALLINGCONV void (*free_func)(void *); -} godot_nativescript_instance_create_func; - -typedef struct { - // instance pointer, method data, user data - GDCALLINGCONV void (*destroy_func)(godot_object *, void *, void *); - void *method_data; - GDCALLINGCONV void (*free_func)(void *); -} godot_nativescript_instance_destroy_func; - -void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_nativescript_instance_create_func p_create_func, godot_nativescript_instance_destroy_func p_destroy_func); - -void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_nativescript_instance_create_func p_create_func, godot_nativescript_instance_destroy_func p_destroy_func); - -typedef struct { - godot_nativescript_method_rpc_mode rpc_type; -} godot_nativescript_method_attributes; - -typedef struct { - godot_string name; - - godot_variant_type type; - godot_nativescript_property_hint hint; - godot_string hint_string; -} godot_nativescript_method_argument; - -typedef struct { - // instance pointer, method data, user data, num args, args - return result as varaint - GDCALLINGCONV godot_variant (*method)(godot_object *, void *, void *, int, godot_variant **); - void *method_data; - GDCALLINGCONV void (*free_func)(void *); -} godot_nativescript_instance_method; - -void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_nativescript_method_attributes p_attr, godot_nativescript_instance_method p_method); -void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_nativescript_method_argument *p_args); - -typedef struct { - // instance pointer, method data, user data, value - GDCALLINGCONV void (*set_func)(godot_object *, void *, void *, godot_variant *); - void *method_data; - GDCALLINGCONV void (*free_func)(void *); -} godot_nativescript_property_set_func; - -typedef struct { - // instance pointer, method data, user data, value - GDCALLINGCONV godot_variant (*get_func)(godot_object *, void *, void *); - void *method_data; - GDCALLINGCONV void (*free_func)(void *); -} godot_nativescript_property_get_func; - -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); - -typedef struct { - godot_string name; - godot_int type; - godot_nativescript_property_hint hint; - godot_string hint_string; - godot_nativescript_property_usage_flags usage; - godot_variant default_value; -} godot_nativescript_signal_argument; - -typedef struct { - godot_string name; - int num_args; - godot_nativescript_signal_argument *args; - int num_default_args; - godot_variant *default_args; -} godot_nativescript_signal; - -void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const char *p_name, const godot_nativescript_signal *p_signal); - -void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance); - -// documentation - -void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation); -void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation); -void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation); -void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation); - -// type tag API - -void GDAPI godot_nativescript_set_global_type_tag(int p_idx, const char *p_name, const void *p_type_tag); -const void GDAPI *godot_nativescript_get_global_type_tag(int p_idx, const char *p_name); - -void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag); -const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object); - -// instance binding API - -typedef struct { - GDCALLINGCONV void *(*alloc_instance_binding_data)(void *, const void *, godot_object *); - GDCALLINGCONV void (*free_instance_binding_data)(void *, void *); - GDCALLINGCONV void (*refcount_incremented_instance_binding)(void *, godot_object *); - GDCALLINGCONV bool (*refcount_decremented_instance_binding)(void *, godot_object *); - void *data; - GDCALLINGCONV void (*free_func)(void *); -} godot_nativescript_instance_binding_functions; - -int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_nativescript_instance_binding_functions p_binding_functions); -void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx); - -void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object); - -void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h deleted file mode 100644 index 02ee4066d0..0000000000 --- a/modules/gdnative/include/pluginscript/godot_pluginscript.h +++ /dev/null @@ -1,171 +0,0 @@ -/*************************************************************************/ -/* godot_pluginscript.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 GODOT_PLUGINSCRIPT_H -#define GODOT_PLUGINSCRIPT_H - -#include <gdnative/gdnative.h> -#include <nativescript/godot_nativescript.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void godot_pluginscript_instance_data; -typedef void godot_pluginscript_script_data; -typedef void godot_pluginscript_language_data; - -// --- Instance --- - -typedef struct { - godot_pluginscript_instance_data *(*init)(godot_pluginscript_script_data *p_data, godot_object *p_owner); - void (*finish)(godot_pluginscript_instance_data *p_data); - - godot_bool (*set_prop)(godot_pluginscript_instance_data *p_data, const godot_string_name *p_name, const godot_variant *p_value); - godot_bool (*get_prop)(godot_pluginscript_instance_data *p_data, const godot_string_name *p_name, godot_variant *r_ret); - - godot_variant (*call_method)(godot_pluginscript_instance_data *p_data, - const godot_string_name *p_method, const godot_variant **p_args, - 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. - 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; - -// --- Script --- - -typedef struct { - godot_pluginscript_script_data *data; - godot_string_name name; - godot_bool is_tool; - godot_string_name base; - godot_string icon_path; - - // Member lines format: {<string>: <int>} - godot_dictionary member_lines; - // Method info dictionary format - // { - // name: <string> - // args: [<dict:property>] - // default_args: [<variant>] - // return: <dict:property> - // flags: <int> - // rpc_mode: <int:godot_method_rpc_mode> - // } - godot_array methods; - // Same format than for methods - godot_array signals; - // Property info dictionary format - // { - // name: <string> - // type: <int:godot_variant_type> - // hint: <int:godot_property_hint> - // hint_string: <string> - // usage: <int:godot_property_usage_flags> - // default_value: <variant> - // rset_mode: <int:godot_method_rpc_mode> - // } - godot_array properties; -} godot_pluginscript_script_manifest; - -typedef struct { - godot_pluginscript_script_manifest (*init)(godot_pluginscript_language_data *p_data, const godot_string *p_path, const godot_string *p_source, godot_error *r_error); - void (*finish)(godot_pluginscript_script_data *p_data); - godot_pluginscript_instance_desc instance_desc; -} godot_pluginscript_script_desc; - -// --- Language --- - -typedef struct { - godot_string_name signature; - godot_int call_count; - godot_int total_time; // In microseconds - godot_int self_time; // In microseconds -} godot_pluginscript_profiling_data; - -typedef struct { - const char *name; - const char *type; - const char *extension; - 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 - 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, 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); - void (*auto_indent_code)(godot_pluginscript_language_data *p_data, godot_string *p_code, int p_from_line, int p_to_line); - - void (*add_global_constant)(godot_pluginscript_language_data *p_data, const godot_string_name *p_variable, const godot_variant *p_value); - godot_string (*debug_get_error)(godot_pluginscript_language_data *p_data); - int (*debug_get_stack_level_count)(godot_pluginscript_language_data *p_data); - int (*debug_get_stack_level_line)(godot_pluginscript_language_data *p_data, int p_level); - godot_string (*debug_get_stack_level_function)(godot_pluginscript_language_data *p_data, int p_level); - godot_string (*debug_get_stack_level_source)(godot_pluginscript_language_data *p_data, int p_level); - void (*debug_get_stack_level_locals)(godot_pluginscript_language_data *p_data, int p_level, godot_packed_string_array *p_locals, godot_array *p_values, int p_max_subitems, int p_max_depth); - void (*debug_get_stack_level_members)(godot_pluginscript_language_data *p_data, int p_level, godot_packed_string_array *p_members, godot_array *p_values, int p_max_subitems, int p_max_depth); - void (*debug_get_globals)(godot_pluginscript_language_data *p_data, godot_packed_string_array *p_locals, godot_array *p_values, int p_max_subitems, int p_max_depth); - godot_string (*debug_parse_stack_level_expression)(godot_pluginscript_language_data *p_data, int p_level, const godot_string *p_expression, int p_max_subitems, int p_max_depth); - - // TODO: could this stuff be moved to the godot_pluginscript_language_desc ? - void (*get_public_functions)(godot_pluginscript_language_data *p_data, godot_array *r_functions); - void (*get_public_constants)(godot_pluginscript_language_data *p_data, godot_dictionary *r_constants); - - void (*profiling_start)(godot_pluginscript_language_data *p_data); - void (*profiling_stop)(godot_pluginscript_language_data *p_data); - int (*profiling_get_accumulated_data)(godot_pluginscript_language_data *p_data, godot_pluginscript_profiling_data *r_info, int p_info_max); - int (*profiling_get_frame_data)(godot_pluginscript_language_data *p_data, godot_pluginscript_profiling_data *r_info, int p_info_max); - void (*profiling_frame)(godot_pluginscript_language_data *p_data); - - godot_pluginscript_script_desc script_desc; -} godot_pluginscript_language_desc; - -void GDAPI godot_pluginscript_register_language(const godot_pluginscript_language_desc *language_desc); - -#ifdef __cplusplus -} -#endif - -#endif // GODOT_PLUGINSCRIPT_H diff --git a/modules/gdnative/include/videodecoder/godot_videodecoder.h b/modules/gdnative/include/videodecoder/godot_videodecoder.h deleted file mode 100644 index dc2cf5ec07..0000000000 --- a/modules/gdnative/include/videodecoder/godot_videodecoder.h +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************/ -/* godot_videodecoder.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 GODOT_NATIVEVIDEODECODER_H -#define GODOT_NATIVEVIDEODECODER_H - -#include <gdnative/gdnative.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define GODOTAV_API_MAJOR 0 -#define GODOTAV_API_MINOR 1 - -typedef struct -{ - godot_gdnative_api_version version; - void *next; - void *(*constructor)(godot_object *); - void (*destructor)(void *); - const char *(*get_plugin_name)(); - const char **(*get_supported_extensions)(int *count); - godot_bool (*open_file)(void *, void *); // data struct, and a FileAccess pointer - godot_float (*get_length)(const void *); - godot_float (*get_playback_position)(const void *); - void (*seek)(void *, godot_float); - void (*set_audio_track)(void *, godot_int); - void (*update)(void *, godot_float); - godot_packed_byte_array *(*get_videoframe)(void *); - godot_int (*get_audioframe)(void *, float *, int); - godot_int (*get_channels)(const void *); - godot_int (*get_mix_rate)(const void *); - godot_vector2 (*get_texture_size)(const void *); -} godot_videodecoder_interface_gdnative; - -typedef int (*GDNativeAudioMixCallback)(void *, const float *, int); - -// FileAccess wrappers for custom FFmpeg IO -godot_int GDAPI godot_videodecoder_file_read(void *file_ptr, uint8_t *buf, int buf_size); -int64_t GDAPI godot_videodecoder_file_seek(void *file_ptr, int64_t pos, int whence); -void GDAPI godot_videodecoder_register_decoder(const godot_videodecoder_interface_gdnative *p_interface); - -#ifdef __cplusplus -} -#endif - -#endif /* GODOT_NATIVEVIDEODECODER_H */ diff --git a/modules/gdnative/nativescript/SCsub b/modules/gdnative/nativescript/SCsub deleted file mode 100644 index 4212e87a87..0000000000 --- a/modules/gdnative/nativescript/SCsub +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_gdnative") - -env_gdnative.add_source_files(env.modules_sources, "*.cpp") - -if "platform" in env and env["platform"] in ["linuxbsd", "iphone"]: - env.Append(LINKFLAGS=["-rdynamic"]) diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp deleted file mode 100644 index ae16c22849..0000000000 --- a/modules/gdnative/nativescript/api_generator.cpp +++ /dev/null @@ -1,948 +0,0 @@ -/*************************************************************************/ -/* api_generator.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 "api_generator.h" - -#ifdef TOOLS_ENABLED - -#include "core/config/engine.h" -#include "core/core_constants.h" -#include "core/io/file_access.h" -#include "core/object/class_db.h" -#include "core/string/string_builder.h" -#include "core/templates/pair.h" -#include "core/variant/variant_parser.h" - -// helper stuff - -static Error save_file(const String &p_path, const List<String> &p_content) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE); - - ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); - - for (const List<String>::Element *e = p_content.front(); e != nullptr; e = e->next()) { - file->store_string(e->get()); - } - - file->close(); - - return OK; -} - -// helper stuff end - -struct MethodAPI { - String method_name; - String return_type; - - List<String> argument_types; - List<String> argument_names; - - Map<int, Variant> default_arguments; - - int argument_count = 0; - bool has_varargs = false; - bool is_editor = false; - bool is_noscript = false; - bool is_const = false; - bool is_static = false; // For builtin types. - bool is_reverse = false; - bool is_virtual = false; - bool is_from_script = false; -}; - -struct PropertyAPI { - String name; - String getter; - String setter; - String type; - int index = 0; -}; - -struct ConstantAPI { - String constant_name; - int constant_value = 0; - Variant builtin_constant_value; // For builtin types; - String builtin_constant_type; // For builtin types; -}; - -struct SignalAPI { - String name; - List<String> argument_types; - List<String> argument_names; - Map<int, Variant> default_arguments; -}; - -struct EnumAPI { - String name; - List<Pair<int, String>> values; -}; - -struct OperatorAPI { // For builtin types; - String name; - int oper = Variant::OP_MAX; - String other_type; - String return_type; -}; - -struct ClassAPI { - String class_name; - String super_class_name; - - ClassDB::APIType api_type = ClassDB::API_NONE; - - bool is_singleton = false; - String singleton_name; - bool is_instantiable = false; - // @Unclear - 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. - - List<MethodAPI> methods; - List<MethodAPI> constructors; // For builtin types. - List<PropertyAPI> properties; - List<ConstantAPI> constants; - List<SignalAPI> signals_; - List<EnumAPI> enums; - List<OperatorAPI> operators; // For builtin types. -}; - -static String get_type_name(const PropertyInfo &info) { - if (info.type == Variant::INT && (info.usage & PROPERTY_USAGE_CLASS_IS_ENUM)) { - return String("enum.") + String(info.class_name).replace(".", "::"); - } - if (info.class_name != StringName()) { - return info.class_name; - } - if (info.hint == PROPERTY_HINT_RESOURCE_TYPE) { - return info.class_name; - } - if (info.type == Variant::NIL && (info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) { - return "Variant"; - } - if (info.type == Variant::NIL) { - return "void"; - } - return Variant::get_type_name(info.type); -} - -/* - * Some comparison helper functions we need - */ - -struct MethodInfoComparator { - StringName::AlphCompare compare; - bool operator()(const MethodInfo &p_a, const MethodInfo &p_b) const { - return compare(p_a.name, p_b.name); - } -}; - -struct PropertyInfoComparator { - StringName::AlphCompare compare; - bool operator()(const PropertyInfo &p_a, const PropertyInfo &p_b) const { - return compare(p_a.name, p_b.name); - } -}; - -struct ConstantAPIComparator { - NoCaseComparator compare; - bool operator()(const ConstantAPI &p_a, const ConstantAPI &p_b) const { - return compare(p_a.constant_name, p_b.constant_name); - } -}; - -/* - * Reads the entire Godot API to a list - */ -List<ClassAPI> generate_c_api_classes() { - List<ClassAPI> api; - - List<StringName> classes; - ClassDB::get_class_list(&classes); - classes.sort_custom<StringName::AlphCompare>(); - - // Register global constants as a fake CoreConstants singleton class - { - ClassAPI global_constants_api; - global_constants_api.class_name = "CoreConstants"; - global_constants_api.api_type = ClassDB::API_CORE; - global_constants_api.is_singleton = true; - global_constants_api.singleton_name = "CoreConstants"; - global_constants_api.is_instantiable = false; - const int constants_count = CoreConstants::get_global_constant_count(); - - Map<StringName, EnumAPI> enum_api_map; - for (int i = 0; i < constants_count; ++i) { - StringName enum_name = CoreConstants::get_global_constant_enum(i); - String name = String(CoreConstants::get_global_constant_name(i)); - int value = CoreConstants::get_global_constant_value(i); - - if (enum_name == StringName()) { - ConstantAPI constant_api; - constant_api.constant_name = name; - constant_api.constant_value = value; - global_constants_api.constants.push_back(constant_api); - } else { - EnumAPI enum_api; - if (enum_api_map.has(enum_name)) { - enum_api = enum_api_map[enum_name]; - } else { - enum_api.name = String(enum_name); - } - enum_api.values.push_back(Pair(value, name)); - - enum_api_map[enum_name] = enum_api; - } - } - for (const KeyValue<StringName, EnumAPI> &E : enum_api_map) { - global_constants_api.enums.push_back(E.value); - } - global_constants_api.constants.sort_custom<ConstantAPIComparator>(); - api.push_back(global_constants_api); - } - - for (List<StringName>::Element *e = classes.front(); e != nullptr; e = e->next()) { - StringName class_name = e->get(); - - if (!ClassDB::is_class_exposed(class_name)) { - continue; - } - - ClassAPI class_api; - class_api.api_type = ClassDB::get_api_type(e->get()); - class_api.class_name = class_name; - class_api.super_class_name = ClassDB::get_parent_class(class_name); - { - class_api.is_singleton = Engine::get_singleton()->has_singleton(class_name); - if (class_api.is_singleton) { - class_api.singleton_name = class_name; - } - } - class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instantiate(class_name); - - { - List<StringName> inheriters; - ClassDB::get_inheriters_from_class("RefCounted", &inheriters); - bool is_ref_counted = !!inheriters.find(class_name) || class_name == "RefCounted"; - // @Unclear - class_api.is_ref_counted = !class_api.is_singleton && is_ref_counted; - } - - // constants - { - List<String> constant; - ClassDB::get_integer_constant_list(class_name, &constant, true); - constant.sort_custom<NoCaseComparator>(); - for (List<String>::Element *c = constant.front(); c != nullptr; c = c->next()) { - ConstantAPI constant_api; - constant_api.constant_name = c->get(); - constant_api.constant_value = ClassDB::get_integer_constant(class_name, c->get()); - - class_api.constants.push_back(constant_api); - } - } - - // signals - { - List<MethodInfo> signals_; - ClassDB::get_signal_list(class_name, &signals_, true); - signals_.sort_custom<MethodInfoComparator>(); - - for (int i = 0; i < signals_.size(); i++) { - SignalAPI signal; - - MethodInfo method_info = signals_[i]; - signal.name = method_info.name; - - for (int j = 0; j < method_info.arguments.size(); j++) { - PropertyInfo argument = method_info.arguments[j]; - String type; - String name = argument.name; - - if (argument.name.find(":") != -1) { - type = argument.name.get_slice(":", 1); - name = argument.name.get_slice(":", 0); - } else { - type = get_type_name(argument); - } - - signal.argument_names.push_back(name); - signal.argument_types.push_back(type); - } - - Vector<Variant> default_arguments = method_info.default_arguments; - - int default_start = signal.argument_names.size() - default_arguments.size(); - - for (int j = 0; j < default_arguments.size(); j++) { - signal.default_arguments[default_start + j] = default_arguments[j]; - } - - class_api.signals_.push_back(signal); - } - } - - //properties - { - List<PropertyInfo> properties; - ClassDB::get_property_list(class_name, &properties, true); - properties.sort_custom<PropertyInfoComparator>(); - - for (List<PropertyInfo>::Element *p = properties.front(); p != nullptr; p = p->next()) { - PropertyAPI property_api; - - property_api.name = p->get().name; - property_api.getter = ClassDB::get_property_getter(class_name, p->get().name); - property_api.setter = ClassDB::get_property_setter(class_name, p->get().name); - - if (p->get().name.find(":") != -1) { - property_api.type = p->get().name.get_slice(":", 1); - property_api.name = p->get().name.get_slice(":", 0); - } else { - MethodInfo minfo; - ClassDB::get_method_info(class_name, property_api.getter, &minfo, true, false); - property_api.type = get_type_name(minfo.return_val); - } - - property_api.index = ClassDB::get_property_index(class_name, p->get().name); - - if (!property_api.setter.is_empty() || !property_api.getter.is_empty()) { - class_api.properties.push_back(property_api); - } - } - } - - //methods - { - List<MethodInfo> methods; - ClassDB::get_method_list(class_name, &methods, true); - methods.sort_custom<MethodInfoComparator>(); - - for (List<MethodInfo>::Element *m = methods.front(); m != nullptr; m = m->next()) { - MethodAPI method_api; - MethodBind *method_bind = ClassDB::get_method(class_name, m->get().name); - MethodInfo &method_info = m->get(); - - //method name - method_api.method_name = method_info.name; - //method return type - if (method_api.method_name.find(":") != -1) { - method_api.return_type = method_api.method_name.get_slice(":", 1); - method_api.method_name = method_api.method_name.get_slice(":", 0); - } else { - method_api.return_type = get_type_name(m->get().return_val); - } - - method_api.argument_count = method_info.arguments.size(); - method_api.has_varargs = method_bind && method_bind->is_vararg(); - - // Method flags - method_api.is_virtual = false; - if (method_info.flags) { - const uint32_t flags = method_info.flags; - method_api.is_editor = flags & METHOD_FLAG_EDITOR; - method_api.is_noscript = flags & METHOD_FLAG_NOSCRIPT; - method_api.is_const = flags & METHOD_FLAG_CONST; - method_api.is_reverse = flags & METHOD_FLAG_REVERSE; - method_api.is_virtual = flags & METHOD_FLAG_VIRTUAL; - method_api.is_from_script = flags & METHOD_FLAG_FROM_SCRIPT; - } - - method_api.is_virtual = method_api.is_virtual || method_api.method_name[0] == '_'; - - // method argument name and type - - for (int i = 0; i < method_api.argument_count; i++) { - String arg_name; - String arg_type; - PropertyInfo arg_info = method_info.arguments[i]; - - arg_name = arg_info.name; - - if (arg_info.name.find(":") != -1) { - arg_type = arg_info.name.get_slice(":", 1); - arg_name = arg_info.name.get_slice(":", 0); - } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { - arg_type = arg_info.class_name; - } else if (arg_info.type == Variant::NIL) { - arg_type = "Variant"; - } else if (arg_info.type == Variant::OBJECT) { - arg_type = arg_info.class_name; - if (arg_type.is_empty()) { - arg_type = Variant::get_type_name(arg_info.type); - } - } else { - arg_type = get_type_name(arg_info); - } - - method_api.argument_names.push_back(arg_name); - method_api.argument_types.push_back(arg_type); - - if (method_bind && method_bind->has_default_argument(i)) { - method_api.default_arguments[i] = method_bind->get_default_argument(i); - } - } - - class_api.methods.push_back(method_api); - } - } - - // enums - { - List<EnumAPI> enums; - List<StringName> enum_names; - ClassDB::get_enum_list(class_name, &enum_names, true); - for (const StringName &E : enum_names) { - List<StringName> value_names; - EnumAPI enum_api; - enum_api.name = E; - ClassDB::get_enum_constants(class_name, E, &value_names, true); - for (List<StringName>::Element *val_e = value_names.front(); val_e; val_e = val_e->next()) { - int int_val = ClassDB::get_integer_constant(class_name, val_e->get(), nullptr); - enum_api.values.push_back(Pair<int, String>(int_val, val_e->get())); - } - enum_api.values.sort_custom<PairSort<int, String>>(); - class_api.enums.push_back(enum_api); - } - } - - api.push_back(class_api); - } - - return api; -} - -/* - * Reads the builtin Variant API to a list - */ -List<ClassAPI> generate_c_builtin_api_types() { - List<ClassAPI> api; - - // Special class for the utility methods. - { - ClassAPI utility_api; - utility_api.class_name = "Utilities"; - utility_api.is_instantiable = false; - - List<StringName> utility_functions; - Variant::get_utility_function_list(&utility_functions); - for (const StringName &E : utility_functions) { - const StringName &function_name = E; - - MethodAPI function_api; - function_api.method_name = function_name; - function_api.has_varargs = Variant::is_utility_function_vararg(function_name); - function_api.argument_count = function_api.has_varargs ? 0 : Variant::get_utility_function_argument_count(function_name); - function_api.is_const = Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH; - - for (int i = 0; i < function_api.argument_count; i++) { - function_api.argument_names.push_back(Variant::get_utility_function_argument_name(function_name, i)); - Variant::Type arg_type = Variant::get_utility_function_argument_type(function_name, i); - function_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type)); - } - - if (Variant::has_utility_function_return_value(function_name)) { - Variant::Type ret_type = Variant::get_utility_function_return_type(function_name); - function_api.return_type = ret_type == Variant::NIL ? "Variant" : Variant::get_type_name(ret_type); - } else { - function_api.return_type = "void"; - } - - utility_api.methods.push_back(function_api); - } - - api.push_back(utility_api); - } - - for (int t = 0; t < Variant::VARIANT_MAX; t++) { - Variant::Type type = (Variant::Type)t; - - ClassAPI class_api; - class_api.class_name = Variant::get_type_name(type); - class_api.is_instantiable = true; - class_api.has_indexing = Variant::has_indexing(type); - class_api.indexed_type = Variant::get_type_name(Variant::get_indexed_element_type(type)); - class_api.is_keyed = Variant::is_keyed(type); - // Types that are passed by reference. - switch (type) { - case Variant::OBJECT: - case Variant::DICTIONARY: - case Variant::ARRAY: - 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: - class_api.is_ref_counted = true; - break; - default: - class_api.is_ref_counted = false; - break; - } - - // Methods. - - List<StringName> methods; - Variant::get_builtin_method_list(type, &methods); - for (const StringName &E : methods) { - const StringName &method_name = E; - - MethodAPI method_api; - - method_api.method_name = method_name; - method_api.argument_count = Variant::get_builtin_method_argument_count(type, method_name); - method_api.has_varargs = Variant::is_builtin_method_vararg(type, method_name); - method_api.is_const = Variant::is_builtin_method_const(type, method_name); - method_api.is_static = Variant::is_builtin_method_static(type, method_name); - - for (int i = 0; i < method_api.argument_count; i++) { - method_api.argument_names.push_back(Variant::get_builtin_method_argument_name(type, method_name, i)); - Variant::Type arg_type = Variant::get_builtin_method_argument_type(type, method_name, i); - method_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type)); - } - - Vector<Variant> default_arguments = Variant::get_builtin_method_default_arguments(type, method_name); - - int default_start = method_api.argument_names.size() - default_arguments.size(); - - for (int i = 0; i < default_arguments.size(); i++) { - method_api.default_arguments[default_start + i] = default_arguments[i]; - } - - if (Variant::has_builtin_method_return_value(type, method_name)) { - Variant::Type ret_type = Variant::get_builtin_method_return_type(type, method_name); - method_api.return_type = ret_type == Variant::NIL ? "Variant" : Variant::get_type_name(ret_type); - } else { - method_api.return_type = "void"; - } - - class_api.methods.push_back(method_api); - } - - // Constructors. - - for (int c = 0; c < Variant::get_constructor_count(type); c++) { - MethodAPI constructor_api; - - constructor_api.method_name = Variant::get_type_name(type); - constructor_api.argument_count = Variant::get_constructor_argument_count(type, c); - constructor_api.return_type = Variant::get_type_name(type); - - for (int i = 0; i < constructor_api.argument_count; i++) { - constructor_api.argument_names.push_back(Variant::get_constructor_argument_name(type, c, i)); - Variant::Type arg_type = Variant::get_constructor_argument_type(type, c, i); - constructor_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type)); - } - - class_api.constructors.push_back(constructor_api); - } - - // Constants. - - List<StringName> constants; - Variant::get_constants_for_type(type, &constants); - for (const StringName &E : constants) { - const StringName &constant_name = E; - ConstantAPI constant_api; - - constant_api.constant_name = constant_name; - constant_api.builtin_constant_value = Variant::get_constant_value(type, constant_name); - constant_api.builtin_constant_type = Variant::get_type_name(constant_api.builtin_constant_value.get_type()); - - class_api.constants.push_back(constant_api); - } - - // Members. - - List<StringName> members; - Variant::get_member_list(type, &members); - for (const StringName &E : members) { - const StringName &member_name = E; - - PropertyAPI member_api; - member_api.name = member_name; - Variant::Type member_type = Variant::get_member_type(type, member_name); - member_api.type = member_type == Variant::NIL ? "Variant" : Variant::get_type_name(member_type); - - class_api.properties.push_back(member_api); - } - - // Operators. - - for (int op = 0; op < Variant::OP_MAX; op++) { - Variant::Operator oper = (Variant::Operator)op; - - for (int ot = 0; ot < Variant::VARIANT_MAX; ot++) { - Variant::Type other_type = (Variant::Type)ot; - - if (!Variant::get_validated_operator_evaluator(oper, type, other_type)) { - continue; - } - - OperatorAPI oper_api; - oper_api.name = Variant::get_operator_name(oper); - oper_api.oper = oper; - oper_api.other_type = Variant::get_type_name(other_type); - oper_api.return_type = Variant::get_type_name(Variant::get_operator_return_type(oper, type, other_type)); - - class_api.operators.push_back(oper_api); - } - } - - api.push_back(class_api); - } - - return api; -} - -/* - * Generates the JSON source from the API in p_api - */ -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"); - - for (const List<ClassAPI>::Element *c = p_api.front(); c != nullptr; c = c->next()) { - ClassAPI api = c->get(); - - source.push_back("\t{\n"); - - source.push_back("\t\t\"name\": \"" + api.class_name + "\",\n"); - source.push_back("\t\t\"base_class\": \"" + api.super_class_name + "\",\n"); - source.push_back(String("\t\t\"api_type\": \"") + (api.api_type == ClassDB::API_CORE ? "core" : (api.api_type == ClassDB::API_EDITOR ? "tools" : "none")) + "\",\n"); - 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_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()) { - source.push_back("\t\t\t\"" + e->get().constant_name + "\": " + String::num_int64(e->get().constant_value) + (e->next() ? "," : "") + "\n"); - } - source.push_back("\t\t},\n"); - - source.push_back("\t\t\"properties\": [\n"); - for (List<PropertyAPI>::Element *e = api.properties.front(); e; e = e->next()) { - source.push_back("\t\t\t{\n"); - source.push_back("\t\t\t\t\"name\": \"" + e->get().name + "\",\n"); - source.push_back("\t\t\t\t\"type\": \"" + e->get().type + "\",\n"); - source.push_back("\t\t\t\t\"getter\": \"" + e->get().getter + "\",\n"); - source.push_back("\t\t\t\t\"setter\": \"" + e->get().setter + "\",\n"); - source.push_back(String("\t\t\t\t\"index\": ") + itos(e->get().index) + "\n"); - source.push_back(String("\t\t\t}") + (e->next() ? "," : "") + "\n"); - } - source.push_back("\t\t],\n"); - - source.push_back("\t\t\"signals\": [\n"); - for (List<SignalAPI>::Element *e = api.signals_.front(); e; e = e->next()) { - source.push_back("\t\t\t{\n"); - source.push_back("\t\t\t\t\"name\": \"" + e->get().name + "\",\n"); - source.push_back("\t\t\t\t\"arguments\": [\n"); - for (int i = 0; i < e->get().argument_names.size(); i++) { - source.push_back("\t\t\t\t\t{\n"); - 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"); - 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"); - source.push_back(String("\t\t\t}") + (e->next() ? "," : "") + "\n"); - } - source.push_back("\t\t],\n"); - - source.push_back("\t\t\"methods\": [\n"); - for (List<MethodAPI>::Element *e = api.methods.front(); e; e = e->next()) { - source.push_back("\t\t\t{\n"); - source.push_back("\t\t\t\t\"name\": \"" + e->get().method_name + "\",\n"); - source.push_back("\t\t\t\t\"return_type\": \"" + e->get().return_type + "\",\n"); - source.push_back(String("\t\t\t\t\"is_editor\": ") + (e->get().is_editor ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\t\t\"is_noscript\": ") + (e->get().is_noscript ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\t\t\"is_const\": ") + (e->get().is_const ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\t\t\"is_reverse\": ") + (e->get().is_reverse ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\t\t\"is_virtual\": ") + (e->get().is_virtual ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\t\t\"has_varargs\": ") + (e->get().has_varargs ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\t\t\"is_from_script\": ") + (e->get().is_from_script ? "true" : "false") + ",\n"); - source.push_back("\t\t\t\t\"arguments\": [\n"); - for (int i = 0; i < e->get().argument_names.size(); i++) { - source.push_back("\t\t\t\t\t{\n"); - 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"); - 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"); - source.push_back(String("\t\t\t}") + (e->next() ? "," : "") + "\n"); - } - source.push_back("\t\t],\n"); - - source.push_back("\t\t\"enums\": [\n"); - for (List<EnumAPI>::Element *e = api.enums.front(); e; e = e->next()) { - source.push_back("\t\t\t{\n"); - source.push_back("\t\t\t\t\"name\": \"" + e->get().name + "\",\n"); - source.push_back("\t\t\t\t\"values\": {\n"); - for (List<Pair<int, String>>::Element *val_e = e->get().values.front(); val_e; val_e = val_e->next()) { - source.push_back("\t\t\t\t\t\"" + val_e->get().second + "\": " + itos(val_e->get().first)); - source.push_back(String((val_e->next() ? "," : "")) + "\n"); - } - source.push_back("\t\t\t\t}\n"); - source.push_back(String("\t\t\t}") + (e->next() ? "," : "") + "\n"); - } - source.push_back("\t\t]\n"); - - source.push_back(String("\t}") + (c->next() ? "," : "") + "\n"); - } - source.push_back("]"); - - return source; -} - -static int indent_level = 0; - -static void append_indented(StringBuilder &p_source, const String &p_text) { - for (int i = 0; i < indent_level; i++) { - p_source.append("\t"); - } - p_source.append(p_text); - p_source.append("\n"); -} - -static void append_indented(StringBuilder &p_source, const char *p_text) { - for (int i = 0; i < indent_level; i++) { - p_source.append("\t"); - } - p_source.append(p_text); - p_source.append("\n"); -} - -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")); - append_indented(p_source, vformat(R"("is_static": %s,)", p_method.is_static ? "true" : "false")); - append_indented(p_source, vformat(R"("has_varargs": %s,)", p_method.has_varargs ? "true" : "false")); - - append_indented(p_source, R"("arguments": [)"); - indent_level++; - for (int i = 0; i < p_method.argument_count; i++) { - append_indented(p_source, "{"); - indent_level++; - - 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")); - 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 ? "}," : "}"); - } - indent_level--; - append_indented(p_source, "]"); -} - -static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) { - StringBuilder source; - - source.append("[\n"); - - indent_level = 1; - - for (const List<ClassAPI>::Element *C = p_api.front(); C; C = C->next()) { - const ClassAPI &class_api = C->get(); - append_indented(source, "{"); - indent_level++; - - 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_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")); - - // Constructors. - append_indented(source, R"("constructors": [)"); - indent_level++; - for (const List<MethodAPI>::Element *E = class_api.constructors.front(); E; E = E->next()) { - const MethodAPI &constructor = E->get(); - append_indented(source, "{"); - indent_level++; - - write_builtin_method(source, constructor); - - indent_level--; - append_indented(source, E->next() ? "}," : "}"); - } - indent_level--; - append_indented(source, "],"); - - // Constants. - append_indented(source, R"("constants": [)"); - indent_level++; - for (const List<ConstantAPI>::Element *E = class_api.constants.front(); E; E = E->next()) { - const ConstantAPI &constant = E->get(); - append_indented(source, "{"); - indent_level++; - - append_indented(source, vformat(R"("name": "%s",)", constant.constant_name)); - append_indented(source, vformat(R"("type": "%s",)", constant.builtin_constant_type)); - append_indented(source, vformat(R"("value": "%s")", constant.builtin_constant_value.operator String())); - - indent_level--; - append_indented(source, E->next() ? "}," : "}"); - } - indent_level--; - append_indented(source, "],"); - - // Methods. - append_indented(source, R"("methods": [)"); - indent_level++; - for (const List<MethodAPI>::Element *E = class_api.methods.front(); E; E = E->next()) { - const MethodAPI &method = E->get(); - append_indented(source, "{"); - indent_level++; - - write_builtin_method(source, method); - - indent_level--; - append_indented(source, E->next() ? "}," : "}"); - } - indent_level--; - append_indented(source, "],"); - - // Members. - append_indented(source, R"("members": [)"); - indent_level++; - for (const List<PropertyAPI>::Element *E = class_api.properties.front(); E; E = E->next()) { - const PropertyAPI &member = E->get(); - append_indented(source, "{"); - indent_level++; - - append_indented(source, vformat(R"("name": "%s",)", member.name)); - append_indented(source, vformat(R"("type": "%s")", member.type)); - - indent_level--; - append_indented(source, E->next() ? "}," : "}"); - } - indent_level--; - append_indented(source, "],"); - - // Operators. - append_indented(source, R"("operators": [)"); - indent_level++; - for (const List<OperatorAPI>::Element *E = class_api.operators.front(); E; E = E->next()) { - const OperatorAPI &oper = E->get(); - append_indented(source, "{"); - indent_level++; - - append_indented(source, vformat(R"("name": "%s",)", oper.name)); - append_indented(source, vformat(R"("operator": %d,)", oper.oper)); - append_indented(source, vformat(R"("other_type": "%s",)", oper.other_type)); - append_indented(source, vformat(R"("return_type": "%s")", oper.return_type)); - - indent_level--; - append_indented(source, E->next() ? "}," : "}"); - } - indent_level--; - append_indented(source, "]"); - - indent_level--; - append_indented(source, C->next() ? "}," : "}"); - } - - indent_level--; - source.append("]\n"); - - List<String> result; - result.push_back(source.as_string()); - return result; -} - -#endif - -/* - * Saves the whole Godot API to a JSON file located at - * p_path - */ -Error generate_c_api(const String &p_path) { -#ifndef TOOLS_ENABLED - return ERR_BUG; -#else - - List<ClassAPI> api = generate_c_api_classes(); - - List<String> json_source = generate_c_api_json(api); - - return save_file(p_path, json_source); -#endif -} -/* - * Saves the builtin Godot API to a JSON file located at - * p_path - */ -Error generate_c_builtin_api(const String &p_path) { -#ifndef TOOLS_ENABLED - return ERR_BUG; -#else - - List<ClassAPI> api = generate_c_builtin_api_types(); - - List<String> json_source = generate_c_builtin_api_json(api); - - return save_file(p_path, json_source); -#endif -} diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp deleted file mode 100644 index dadd1a9d10..0000000000 --- a/modules/gdnative/nativescript/godot_nativescript.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/*************************************************************************/ -/* godot_nativescript.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 "nativescript/godot_nativescript.h" - -#include "core/config/project_settings.h" -#include "core/core_constants.h" -#include "core/error/error_macros.h" -#include "core/object/class_db.h" -#include "core/variant/variant.h" -#include "gdnative/gdnative.h" -#include <stdint.h> - -#include "nativescript.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern "C" void _native_script_hook() { -} - -#define NSL NativeScriptLanguage::get_singleton() - -// Script API - -void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_nativescript_instance_create_func p_create_func, godot_nativescript_instance_destroy_func p_destroy_func) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc> *classes = &NSL->library_classes[*s]; - - NativeScriptDesc desc; - - desc.create_func = p_create_func; - desc.destroy_func = p_destroy_func; - desc.is_tool = false; - - desc.base = p_base; - - if (classes->has(p_base)) { - desc.base_data = &(*classes)[p_base]; - desc.base_native_type = desc.base_data->base_native_type; - - const NativeScriptDesc *b = desc.base_data; - while (b) { - desc.rpc_methods.append_array(b->rpc_methods); - b = b->base_data; - } - - } else { - desc.base_data = nullptr; - desc.base_native_type = p_base; - } - - classes->insert(p_name, desc); -} - -void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_nativescript_instance_create_func p_create_func, godot_nativescript_instance_destroy_func p_destroy_func) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc> *classes = &NSL->library_classes[*s]; - - NativeScriptDesc desc; - - desc.create_func = p_create_func; - desc.destroy_func = p_destroy_func; - desc.is_tool = true; - desc.base = p_base; - - if (classes->has(p_base)) { - desc.base_data = &(*classes)[p_base]; - desc.base_native_type = desc.base_data->base_native_type; - - const NativeScriptDesc *b = desc.base_data; - while (b) { - desc.rpc_methods.append_array(b->rpc_methods); - b = b->base_data; - } - - } else { - desc.base_data = nullptr; - desc.base_native_type = p_base; - } - - classes->insert(p_name, desc); -} - -void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_nativescript_method_attributes p_attr, godot_nativescript_instance_method p_method) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to register method on non-existent class."); - - NativeScriptDesc::Method method; - method.method = p_method; - method.rpc_mode = p_attr.rpc_type; - method.rpc_method_id = UINT16_MAX; - method.info = MethodInfo(p_function_name); - - E->get().methods.insert(p_function_name, method); - - if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) { - Multiplayer::RPCConfig nd; - nd.name = String(p_name); - nd.rpc_mode = Multiplayer::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) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to register method on non-existent class."); - - NativeScriptDesc::Property property; - property.default_value = *(Variant *)&p_attr->default_value; - property.getter = p_get_func; - property.setter = p_set_func; - property.info = PropertyInfo((Variant::Type)p_attr->type, - p_path, - (PropertyHint)p_attr->hint, - *(String *)&p_attr->hint_string, - (PropertyUsageFlags)p_attr->usage); - - E->get().properties.insert(p_path, property); -} - -void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const char *p_name, const godot_nativescript_signal *p_signal) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to register method on non-existent class."); - - List<PropertyInfo> args; - Vector<Variant> default_args; - - for (int i = 0; i < p_signal->num_args; i++) { - PropertyInfo info; - - godot_nativescript_signal_argument arg = p_signal->args[i]; - - info.hint = (PropertyHint)arg.hint; - info.hint_string = *(String *)&arg.hint_string; - info.name = *(String *)&arg.name; - info.type = (Variant::Type)arg.type; - info.usage = (PropertyUsageFlags)arg.usage; - - args.push_back(info); - } - - for (int i = 0; i < p_signal->num_default_args; i++) { - Variant *v; - godot_nativescript_signal_argument attrib = p_signal->args[i]; - - v = (Variant *)&attrib.default_value; - - default_args.push_back(*v); - } - - MethodInfo method_info; - method_info.name = *(String *)&p_signal->name; - method_info.arguments = args; - method_info.default_arguments = default_args; - - NativeScriptDesc::Signal signal; - signal.signal = method_info; - - E->get().signals_.insert(*(String *)&p_signal->name, signal); -} - -void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) { - Object *instance = (Object *)p_instance; - if (!instance) { - return nullptr; - } - if (instance->get_script_instance() && instance->get_script_instance()->get_language() == NativeScriptLanguage::get_singleton()) { - return ((NativeScriptInstance *)instance->get_script_instance())->userdata; - } - return nullptr; -} - -/* - * - * - * NativeScript 1.1 - * - * - */ - -void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_nativescript_method_argument *p_args) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to add argument information for a method on a non-existent class."); - - Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name); - ERR_FAIL_COND_MSG(!method, "Attempted to add argument information to non-existent method."); - - MethodInfo *method_information = &method->get().info; - - List<PropertyInfo> args; - - for (int i = 0; i < p_num_args; i++) { - godot_nativescript_method_argument arg = p_args[i]; - String name = *(String *)&arg.name; - String hint_string = *(String *)&arg.hint_string; - - Variant::Type type = (Variant::Type)arg.type; - PropertyHint hint = (PropertyHint)arg.hint; - - args.push_back(PropertyInfo(type, p_name, hint, hint_string)); - } - - method_information->arguments = args; -} - -void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to add documentation to a non-existent class."); - - E->get().documentation = *(String *)&p_documentation; -} - -void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to add documentation to a method on a non-existent class."); - - Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name); - ERR_FAIL_COND_MSG(!method, "Attempted to add documentation to non-existent method."); - - method->get().documentation = *(String *)&p_documentation; -} - -void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to add documentation to a property on a non-existent class."); - - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = E->get().properties.find(p_path); - ERR_FAIL_COND_MSG(!property, "Attempted to add documentation to non-existent property."); - - property.get().documentation = *(String *)&p_documentation; -} - -void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to add documentation to a signal on a non-existent class."); - - Map<StringName, NativeScriptDesc::Signal>::Element *signal = E->get().signals_.find(p_signal_name); - ERR_FAIL_COND_MSG(!signal, "Attempted to add documentation to non-existent signal."); - - signal->get().documentation = *(String *)&p_documentation; -} - -void GDAPI godot_nativescript_set_global_type_tag(int p_idx, const char *p_name, const void *p_type_tag) { - NativeScriptLanguage::get_singleton()->set_global_type_tag(p_idx, StringName(p_name), p_type_tag); -} - -const void GDAPI *godot_nativescript_get_global_type_tag(int p_idx, const char *p_name) { - return NativeScriptLanguage::get_singleton()->get_global_type_tag(p_idx, StringName(p_name)); -} - -void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag) { - String *s = (String *)p_gdnative_handle; - - Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); - ERR_FAIL_COND_MSG(!E, "Attempted to set type tag on a non-existent class."); - - E->get().type_tag = p_type_tag; -} - -const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object) { - const Object *o = (Object *)p_object; - - if (!o->get_script_instance()) { - return nullptr; - } else { - NativeScript *script = Object::cast_to<NativeScript>(o->get_script_instance()->get_script().ptr()); - if (!script) { - return nullptr; - } - - if (script->get_script_desc()) { - return script->get_script_desc()->type_tag; - } - } - - return nullptr; -} - -int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_nativescript_instance_binding_functions p_binding_functions) { - return NativeScriptLanguage::get_singleton()->register_binding_functions(p_binding_functions); -} - -void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx) { - NativeScriptLanguage::get_singleton()->unregister_binding_functions(p_idx); -} - -void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) { - return nullptr; -} - -void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time) { - NativeScriptLanguage::get_singleton()->profiling_add_data(StringName(p_signature), p_time); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp deleted file mode 100644 index 075977b60f..0000000000 --- a/modules/gdnative/nativescript/nativescript.cpp +++ /dev/null @@ -1,1780 +0,0 @@ -/*************************************************************************/ -/* nativescript.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 "nativescript.h" - -#include <stdint.h> - -#include "gdnative/gdnative.h" - -#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/os.h" - -#include "main/main.h" - -#include "scene/main/scene_tree.h" -#include "scene/resources/resource_format_text.h" - -#include <stdlib.h> - -#ifndef NO_THREADS -#include "core/os/thread.h" -#endif - -#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) -#include "api_generator.h" -#endif - -#ifdef TOOLS_ENABLED -#include "editor/editor_node.h" -#endif - -void NativeScript::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_class_name", "class_name"), &NativeScript::set_class_name); - ClassDB::bind_method(D_METHOD("get_class_name"), &NativeScript::get_class_name); - - ClassDB::bind_method(D_METHOD("set_library", "library"), &NativeScript::set_library); - ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_library); - - ClassDB::bind_method(D_METHOD("set_script_class_name", "class_name"), &NativeScript::set_script_class_name); - ClassDB::bind_method(D_METHOD("get_script_class_name"), &NativeScript::get_script_class_name); - ClassDB::bind_method(D_METHOD("set_script_class_icon_path", "icon_path"), &NativeScript::set_script_class_icon_path); - ClassDB::bind_method(D_METHOD("get_script_class_icon_path"), &NativeScript::get_script_class_icon_path); - - ClassDB::bind_method(D_METHOD("get_class_documentation"), &NativeScript::get_class_documentation); - ClassDB::bind_method(D_METHOD("get_method_documentation", "method"), &NativeScript::get_method_documentation); - ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation); - ClassDB::bind_method(D_METHOD("get_property_documentation", "path"), &NativeScript::get_property_documentation); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); - ADD_GROUP("Script Class", "script_class_"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path"); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo("new")); -} - -#define NSL NativeScriptLanguage::get_singleton() - -#ifdef TOOLS_ENABLED - -void NativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { - NativeScriptDesc *script_data = get_script_desc(); - - ERR_FAIL_COND(!script_data); - - List<PropertyInfo> info; - get_script_property_list(&info); - Map<StringName, Variant> values; - for (const PropertyInfo &E : info) { - Variant value; - get_property_default_value(E.name, value); - values[E.name] = value; - } - - p_placeholder->update(info, values); -} - -void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - placeholders.erase(p_placeholder); -} - -#endif - -bool NativeScript::inherits_script(const Ref<Script> &p_script) const { - Ref<NativeScript> ns = p_script; - if (ns.is_null()) { - return false; - } - - const NativeScriptDesc *other_s = ns->get_script_desc(); - if (!other_s) { - return false; - } - - const NativeScriptDesc *s = get_script_desc(); - - while (s) { - if (s == other_s) { - return true; - } - s = s->base_data; - } - - return false; -} - -void NativeScript::set_class_name(String p_class_name) { - class_name = p_class_name; -} - -String NativeScript::get_class_name() const { - return class_name; -} - -void NativeScript::set_library(Ref<GDNativeLibrary> p_library) { - if (!library.is_null()) { - WARN_PRINT("Library in NativeScript already set. Do nothing."); - return; - } - if (p_library.is_null()) { - return; - } - library = p_library; - lib_path = library->get_current_library_path(); - -#ifndef NO_THREADS - if (Thread::get_caller_id() != Thread::get_main_id()) { - NSL->defer_init_library(p_library, this); - } else -#endif - { - NSL->init_library(p_library); - NSL->register_script(this); - } -} - -Ref<GDNativeLibrary> NativeScript::get_library() const { - return library; -} - -void NativeScript::set_script_class_name(String p_type) { - script_class_name = p_type; -} - -String NativeScript::get_script_class_name() const { - return script_class_name; -} - -void NativeScript::set_script_class_icon_path(String p_icon_path) { - script_class_icon_path = p_icon_path; -} - -String NativeScript::get_script_class_icon_path() const { - return script_class_icon_path; -} - -bool NativeScript::can_instantiate() const { - NativeScriptDesc *script_data = get_script_desc(); - -#ifdef TOOLS_ENABLED - // Only valid if this is either a tool script or a "regular" script. - // (so, an environment where scripting is disabled (and not the editor) would not - // create objects). - return script_data && (is_tool() || ScriptServer::is_scripting_enabled()); -#else - return script_data; -#endif -} - -Ref<Script> NativeScript::get_base_script() const { - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - return Ref<Script>(); - } - - NativeScript *script = (NativeScript *)NSL->create_script(); - Ref<NativeScript> ns = Ref<NativeScript>(script); - ERR_FAIL_COND_V(!ns.is_valid(), Ref<Script>()); - - ns->set_class_name(script_data->base); - ns->set_library(get_library()); - return ns; -} - -StringName NativeScript::get_instance_base_type() const { - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - return ""; - } - - return script_data->base_native_type; -} - -ScriptInstance *NativeScript::instance_create(Object *p_this) { - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - return nullptr; - } - - NativeScriptInstance *nsi = memnew(NativeScriptInstance); - - nsi->owner = p_this; - nsi->script = Ref<NativeScript>(this); - -#ifndef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled()) { - nsi->userdata = nullptr; - } else { - nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); - } -#else - nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); -#endif - - { - MutexLock lock(owners_lock); - - instance_owners.insert(p_this); - } - - return nsi; -} - -PlaceHolderScriptInstance *NativeScript::placeholder_instance_create(Object *p_this) { -#ifdef TOOLS_ENABLED - PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); - placeholders.insert(sins); - - _update_placeholder(sins); - - return sins; -#else - return nullptr; -#endif -} - -bool NativeScript::instance_has(const Object *p_this) const { - return instance_owners.has((Object *)p_this); -} - -bool NativeScript::has_source_code() const { - return false; -} - -String NativeScript::get_source_code() const { - return ""; -} - -void NativeScript::set_source_code(const String &p_code) { -} - -Error NativeScript::reload(bool p_keep_state) { - return FAILED; -} - -bool NativeScript::has_method(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - if (script_data->methods.has(p_method)) { - return true; - } - - script_data = script_data->base_data; - } - return false; -} - -MethodInfo NativeScript::get_method_info(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - return MethodInfo(); - } - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *M = script_data->methods.find(p_method); - - if (M) { - return M->get().info; - } - - script_data = script_data->base_data; - } - return MethodInfo(); -} - -bool NativeScript::is_valid() const { - return true; -} - -bool NativeScript::is_tool() const { - NativeScriptDesc *script_data = get_script_desc(); - - if (script_data) { - return script_data->is_tool; - } - - return false; -} - -ScriptLanguage *NativeScript::get_language() const { - return NativeScriptLanguage::get_singleton(); -} - -bool NativeScript::has_script_signal(const StringName &p_signal) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - if (script_data->signals_.has(p_signal)) { - return true; - } - script_data = script_data->base_data; - } - return false; -} - -void NativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - return; - } - - Set<MethodInfo> signals_; - - while (script_data) { - for (const KeyValue<StringName, NativeScriptDesc::Signal> &S : script_data->signals_) { - signals_.insert(S.value.signal); - } - - script_data = script_data->base_data; - } - - for (Set<MethodInfo>::Element *E = signals_.front(); E; E = E->next()) { - r_signals->push_back(E->get()); - } -} - -bool NativeScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - NativeScriptDesc *script_data = get_script_desc(); - - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P; - while (!P && script_data) { - P = script_data->properties.find(p_property); - script_data = script_data->base_data; - } - if (!P) { - return false; - } - - r_value = P.get().default_value; - return true; -} - -void NativeScript::update_exports() { -} - -void NativeScript::get_script_method_list(List<MethodInfo> *p_list) const { - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - return; - } - - Set<MethodInfo> methods; - - while (script_data) { - for (const KeyValue<StringName, NativeScriptDesc::Method> &E : script_data->methods) { - methods.insert(E.value.info); - } - - script_data = script_data->base_data; - } - - for (Set<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { - NativeScriptDesc *script_data = get_script_desc(); - - Set<StringName> existing_properties; - List<PropertyInfo>::Element *original_back = p_list->back(); - while (script_data) { - List<PropertyInfo>::Element *insert_position = original_back; - - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (!existing_properties.has(E.key())) { - insert_position = p_list->insert_after(insert_position, E.get().info); - existing_properties.insert(E.key()); - } - } - script_data = script_data->base_data; - } -} - -const Vector<Multiplayer::RPCConfig> NativeScript::get_rpc_methods() const { - NativeScriptDesc *script_data = get_script_desc(); - ERR_FAIL_COND_V(!script_data, Vector<Multiplayer::RPCConfig>()); - - return script_data->rpc_methods; -} - -String NativeScript::get_class_documentation() const { - NativeScriptDesc *script_data = get_script_desc(); - - ERR_FAIL_COND_V_MSG(!script_data, "", "Attempt to get class documentation on invalid NativeScript."); - - return script_data->documentation; -} - -String NativeScript::get_method_documentation(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - ERR_FAIL_COND_V_MSG(!script_data, "", "Attempt to get method documentation on invalid NativeScript."); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *method = script_data->methods.find(p_method); - - if (method) { - return method->get().documentation; - } - - script_data = script_data->base_data; - } - - ERR_FAIL_V_MSG("", "Attempt to get method documentation for non-existent method."); -} - -String NativeScript::get_signal_documentation(const StringName &p_signal_name) const { - NativeScriptDesc *script_data = get_script_desc(); - - ERR_FAIL_COND_V_MSG(!script_data, "", "Attempt to get signal documentation on invalid NativeScript."); - - while (script_data) { - Map<StringName, NativeScriptDesc::Signal>::Element *signal = script_data->signals_.find(p_signal_name); - - if (signal) { - return signal->get().documentation; - } - - script_data = script_data->base_data; - } - - ERR_FAIL_V_MSG("", "Attempt to get signal documentation for non-existent signal."); -} - -String NativeScript::get_property_documentation(const StringName &p_path) const { - NativeScriptDesc *script_data = get_script_desc(); - - ERR_FAIL_COND_V_MSG(!script_data, "", "Attempt to get property documentation on invalid NativeScript."); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = script_data->properties.find(p_path); - - if (property) { - return property.get().documentation; - } - - script_data = script_data->base_data; - } - - ERR_FAIL_V_MSG("", "Attempt to get property documentation for non-existent signal."); -} - -Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - if (lib_path.is_empty() || class_name.is_empty() || library.is_null()) { - r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; - return Variant(); - } - - NativeScriptDesc *script_data = get_script_desc(); - - if (!script_data) { - r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; - return Variant(); - } - - r_error.error = Callable::CallError::CALL_OK; - - REF ref; - Object *owner = nullptr; - - if (!(script_data->base_native_type == "")) { - owner = ClassDB::instantiate(script_data->base_native_type); - } else { - owner = memnew(RefCounted); - } - - if (!owner) { - r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; - return Variant(); - } - - RefCounted *r = Object::cast_to<RefCounted>(owner); - if (r) { - ref = REF(r); - } - - NativeScriptInstance *instance = (NativeScriptInstance *)instance_create(owner); - - owner->set_script_instance(instance); - - if (!instance) { - if (ref.is_null()) { - memdelete(owner); //no owner, sorry - } - return Variant(); - } - - if (ref.is_valid()) { - return ref; - } else { - return owner; - } -} - -NativeScript::NativeScript() { - library = Ref<GDNative>(); - lib_path = ""; - class_name = ""; -} - -NativeScript::~NativeScript() { - NSL->unregister_script(this); -} - -#define GET_SCRIPT_DESC() script->get_script_desc() - -void NativeScriptInstance::_ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script_data->base_data) { - _ml_call_reversed(script_data->base_data, p_method, p_args, p_argcount); - } - - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - godot_variant res = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - godot_variant_destroy(&res); - } -} - -bool NativeScriptInstance::set(const StringName &p_name, const Variant &p_value) { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = script_data->properties.find(p_name); - if (P) { - P.get().setter.set_func((godot_object *)owner, - P.get().setter.method_data, - userdata, - (godot_variant *)&p_value); - return true; - } - - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_set"); - if (E) { - Variant name = p_name; - const Variant *args[2] = { &name, &p_value }; - - godot_variant result; - result = E->get().method.method((godot_object *)owner, - E->get().method.method_data, - userdata, - 2, - (godot_variant **)args); - bool handled = *(Variant *)&result; - godot_variant_destroy(&result); - if (handled) { - return true; - } - } - - script_data = script_data->base_data; - } - return false; -} - -bool NativeScriptInstance::get(const StringName &p_name, Variant &r_ret) const { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = script_data->properties.find(p_name); - if (P) { - godot_variant value; - value = P.get().getter.get_func((godot_object *)owner, - P.get().getter.method_data, - userdata); - r_ret = *(Variant *)&value; - godot_variant_destroy(&value); - return true; - } - - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get"); - if (E) { - Variant name = p_name; - const Variant *args[1] = { &name }; - - godot_variant result; - result = E->get().method.method((godot_object *)owner, - E->get().method.method_data, - userdata, - 1, - (godot_variant **)args); - r_ret = *(Variant *)&result; - godot_variant_destroy(&result); - if (r_ret.get_type() != Variant::NIL) { - return true; - } - } - - script_data = script_data->base_data; - } - return false; -} - -void NativeScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { - script->get_script_property_list(p_properties); - - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get_property_list"); - if (E) { - godot_variant result; - result = E->get().method.method((godot_object *)owner, - E->get().method.method_data, - userdata, - 0, - nullptr); - Variant res = *(Variant *)&result; - godot_variant_destroy(&result); - - ERR_FAIL_COND_MSG(res.get_type() != Variant::ARRAY, "_get_property_list must return an array of dictionaries."); - - Array arr = res; - for (int i = 0; i < arr.size(); i++) { - Dictionary d = arr[i]; - - ERR_CONTINUE(!d.has("name")); - ERR_CONTINUE(!d.has("type")); - - PropertyInfo info; - - info.type = Variant::Type(d["type"].operator int64_t()); - ERR_CONTINUE(info.type < 0 || info.type >= Variant::VARIANT_MAX); - - info.name = d["name"]; - ERR_CONTINUE(info.name.is_empty()); - - if (d.has("hint")) { - info.hint = PropertyHint(d["hint"].operator int64_t()); - } - - if (d.has("hint_string")) { - info.hint_string = d["hint_string"]; - } - - if (d.has("usage")) { - info.usage = d["usage"]; - } - - p_properties->push_back(info); - } - } - - script_data = script_data->base_data; - } - return; -} - -Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = script_data->properties.find(p_name); - if (P) { - *r_is_valid = true; - return P.get().info.type; - } - - script_data = script_data->base_data; - } - return Variant::NIL; -} - -void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - script->get_script_method_list(p_list); -} - -bool NativeScriptInstance::has_method(const StringName &p_method) const { - return script->has_method(p_method); -} - -Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - godot_variant result; - -#ifdef DEBUG_ENABLED - current_method_call = p_method; -#endif - - result = E->get().method.method((godot_object *)owner, - E->get().method.method_data, - userdata, - p_argcount, - (godot_variant **)p_args); - -#ifdef DEBUG_ENABLED - current_method_call = ""; -#endif - - Variant res = *(Variant *)&result; - godot_variant_destroy(&result); - r_error.error = Callable::CallError::CALL_OK; - return res; - } - - script_data = script_data->base_data; - } - - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); -} - -void NativeScriptInstance::notification(int p_notification) { -#ifdef DEBUG_ENABLED - if (p_notification == MainLoop::NOTIFICATION_CRASH) { - if (current_method_call != StringName("")) { - ERR_PRINT("NativeScriptInstance detected crash on method: " + current_method_call); - current_method_call = ""; - } - } -#endif - - Variant value = p_notification; - const Variant *args[1] = { &value }; - Callable::CallError error; - call("_notification", args, 1, error); -} - -String NativeScriptInstance::to_string(bool *r_valid) { - if (has_method(CoreStringNames::get_singleton()->_to_string)) { - Callable::CallError ce; - Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); - if (ce.error == Callable::CallError::CALL_OK) { - if (ret.get_type() != Variant::STRING) { - if (r_valid) { - *r_valid = false; - } - ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String."); - } - if (r_valid) { - *r_valid = true; - } - return ret.operator String(); - } - } - if (r_valid) { - *r_valid = false; - } - return String(); -} - -void NativeScriptInstance::refcount_incremented() { - Callable::CallError err; - call("_refcount_incremented", nullptr, 0, err); - if (err.error != Callable::CallError::CALL_OK && err.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) { - ERR_PRINT("Failed to invoke _refcount_incremented - should not happen"); - } -} - -bool NativeScriptInstance::refcount_decremented() { - Callable::CallError err; - Variant ret = call("_refcount_decremented", nullptr, 0, err); - if (err.error != Callable::CallError::CALL_OK && err.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) { - ERR_PRINT("Failed to invoke _refcount_decremented - should not happen"); - return true; // assume we can destroy the object - } - if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { - // the method does not exist, default is true - return true; - } - return ret; -} - -Ref<Script> NativeScriptInstance::get_script() const { - return script; -} - -const Vector<Multiplayer::RPCConfig> NativeScriptInstance::get_rpc_methods() const { - return script->get_rpc_methods(); -} - -ScriptLanguage *NativeScriptInstance::get_language() { - return NativeScriptLanguage::get_singleton(); -} - -NativeScriptInstance::~NativeScriptInstance() { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - if (!script_data) { - return; - } - - script_data->destroy_func.destroy_func((godot_object *)owner, script_data->destroy_func.method_data, userdata); - - if (owner) { - MutexLock lock(script->owners_lock); - - script->instance_owners.erase(owner); - } -} - -NativeScriptLanguage *NativeScriptLanguage::singleton; - -void NativeScriptLanguage::_unload_stuff(bool p_reload) { - Map<String, Ref<GDNative>> erase_and_unload; - - for (KeyValue<String, Map<StringName, NativeScriptDesc>> &L : library_classes) { - String lib_path = L.key; - Map<StringName, NativeScriptDesc> classes = L.value; - - if (p_reload) { - Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path); - Ref<GDNative> gdn; - - if (E) { - gdn = E->get(); - } - - bool should_reload = false; - - if (gdn.is_valid()) { - Ref<GDNativeLibrary> lib = gdn->get_library(); - if (lib.is_valid()) { - should_reload = lib->is_reloadable(); - } - } - - if (!should_reload) { - continue; - } - } - - Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path); - Ref<GDNative> gdn; - - if (E) { - gdn = E->get(); - } - - for (KeyValue<StringName, NativeScriptDesc> &C : classes) { - // free property stuff first - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C.value.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 (const KeyValue<StringName, NativeScriptDesc::Method> &M : C.value.methods) { - if (M.value.method.free_func) { - M.value.method.free_func(M.value.method.method_data); - } - } - - // free constructor/destructor - if (C.value.create_func.free_func) { - C.value.create_func.free_func(C.value.create_func.method_data); - } - - if (C.value.destroy_func.free_func) { - C.value.destroy_func.free_func(C.value.destroy_func.method_data); - } - } - - erase_and_unload.insert(lib_path, gdn); - } - - for (KeyValue<String, Ref<GDNative>> &E : erase_and_unload) { - String lib_path = E.key; - Ref<GDNative> gdn = E.value; - - library_classes.erase(lib_path); - - if (gdn.is_valid() && gdn->get_library().is_valid()) { - Ref<GDNativeLibrary> lib = gdn->get_library(); - void *terminate_fn; - Error err = gdn->get_symbol(lib->get_symbol_prefix() + _terminate_call_name, terminate_fn, true); - - if (err == OK) { - void (*terminate)(void *) = (void (*)(void *))terminate_fn; - - terminate((void *)&lib_path); - } - } - } -} - -NativeScriptLanguage::NativeScriptLanguage() { - NativeScriptLanguage::singleton = this; - - _init_call_type = "nativescript_init"; - _init_call_name = "nativescript_init"; - _terminate_call_name = "nativescript_terminate"; - _noarg_call_type = "nativescript_no_arg"; - _frame_call_name = "nativescript_frame"; -#ifndef NO_THREADS - _thread_enter_call_name = "nativescript_thread_enter"; - _thread_exit_call_name = "nativescript_thread_exit"; -#endif -} - -NativeScriptLanguage::~NativeScriptLanguage() { - for (KeyValue<String, Ref<GDNative>> &L : NSL->library_gdnatives) { - Ref<GDNative> lib = L.value; - // only shut down valid libs, duh! - if (lib.is_valid()) { - // If it's a singleton-library then the gdnative module - // manages the destruction at engine shutdown, not NativeScript. - if (!lib->get_library()->is_singleton()) { - lib->terminate(); - } - } - } - - NSL->library_classes.clear(); - NSL->library_gdnatives.clear(); - NSL->library_script_users.clear(); -} - -String NativeScriptLanguage::get_name() const { - return "NativeScript"; -} - -void _add_reload_node() { -#ifdef TOOLS_ENABLED - NativeReloadNode *rn = memnew(NativeReloadNode); - EditorNode::get_singleton()->add_child(rn); -#endif -} - -void NativeScriptLanguage::init() { -#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) - - List<String> args = OS::get_singleton()->get_cmdline_args(); - - List<String>::Element *E = args.find("--gdnative-generate-json-api"); - - if (E && E->next()) { - if (generate_c_api(E->next()->get()) != OK) { - ERR_PRINT("Failed to generate C API\n"); - } - Main::cleanup(true); - exit(0); - } - - E = args.find("--gdnative-generate-json-builtin-api"); - - if (E && E->next()) { - if (generate_c_builtin_api(E->next()->get()) != OK) { - ERR_PRINT("Failed to generate C builtin API\n"); - } - Main::cleanup(true); - exit(0); - } -#endif - -#ifdef TOOLS_ENABLED - EditorNode::add_init_callback(&_add_reload_node); -#endif -} - -String NativeScriptLanguage::get_type() const { - return "NativeScript"; -} - -String NativeScriptLanguage::get_extension() const { - return "gdns"; -} - -Error NativeScriptLanguage::execute_file(const String &p_path) { - return OK; // Qué? -} - -void NativeScriptLanguage::finish() { - _unload_stuff(); -} - -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 { -} - -void NativeScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { -} - -Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - NativeScript *s = memnew(NativeScript); - s->set_class_name(p_class_name); - return Ref<NativeScript>(s); -} - -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; -} - -Script *NativeScriptLanguage::create_script() const { - NativeScript *script = memnew(NativeScript); - return script; -} - -bool NativeScriptLanguage::has_named_classes() const { - return true; -} - -bool NativeScriptLanguage::supports_builtin_mode() const { - return true; -} - -int NativeScriptLanguage::find_function(const String &p_function, const String &p_code) const { - return -1; -} - -String NativeScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const { - return ""; -} - -void NativeScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { -} - -void NativeScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { -} - -// Debugging stuff here. Not used for now. -String NativeScriptLanguage::debug_get_error() const { - return ""; -} - -int NativeScriptLanguage::debug_get_stack_level_count() const { - return -1; -} - -int NativeScriptLanguage::debug_get_stack_level_line(int p_level) const { - return -1; -} - -String NativeScriptLanguage::debug_get_stack_level_function(int p_level) const { - return ""; -} - -String NativeScriptLanguage::debug_get_stack_level_source(int p_level) const { - return ""; -} - -void NativeScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { -} - -void NativeScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { -} - -void NativeScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { -} - -String NativeScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - return ""; -} - -// Debugging stuff end. - -void NativeScriptLanguage::reload_all_scripts() { -} - -void NativeScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { -} - -void NativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdns"); -} - -void NativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { -} - -void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const { -} - -void NativeScriptLanguage::profiling_start() { -#ifdef DEBUG_ENABLED - MutexLock lock(mutex); - - profile_data.clear(); -#endif -} - -void NativeScriptLanguage::profiling_stop() { -#ifdef DEBUG_ENABLED - MutexLock lock(mutex); -#endif -} - -int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { -#ifdef DEBUG_ENABLED - MutexLock lock(mutex); - - int current = 0; - - for (const KeyValue<StringName, ProfileData> &d : profile_data) { - if (current >= p_info_max) { - break; - } - - p_info_arr[current].call_count = d.value.call_count; - p_info_arr[current].self_time = d.value.self_time; - p_info_arr[current].total_time = d.value.total_time; - p_info_arr[current].signature = d.value.signature; - current++; - } - - return current; -#else - return 0; -#endif -} - -int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { -#ifdef DEBUG_ENABLED - MutexLock lock(mutex); - - int current = 0; - - for (const KeyValue<StringName, ProfileData> &d : profile_data) { - if (current >= p_info_max) { - break; - } - - if (d.value.last_frame_call_count) { - p_info_arr[current].call_count = d.value.last_frame_call_count; - p_info_arr[current].self_time = d.value.last_frame_self_time; - p_info_arr[current].total_time = d.value.last_frame_total_time; - p_info_arr[current].signature = d.value.signature; - current++; - } - } - - return current; -#else - return 0; -#endif -} - -void NativeScriptLanguage::profiling_add_data(StringName p_signature, uint64_t p_time) { -#ifdef DEBUG_ENABLED - MutexLock lock(mutex); - - Map<StringName, ProfileData>::Element *d = profile_data.find(p_signature); - if (d) { - d->get().call_count += 1; - d->get().total_time += p_time; - d->get().frame_call_count += 1; - d->get().frame_total_time += p_time; - } else { - ProfileData data; - - data.signature = p_signature; - data.call_count = 1; - data.self_time = 0; - data.total_time = p_time; - data.frame_call_count = 1; - data.frame_self_time = 0; - data.frame_total_time = p_time; - data.last_frame_call_count = 0; - data.last_frame_self_time = 0; - data.last_frame_total_time = 0; - - profile_data.insert(p_signature, data); - } -#endif -} - -int NativeScriptLanguage::register_binding_functions(godot_nativescript_instance_binding_functions p_binding_functions) { - // find index - - int idx = -1; - - for (int i = 0; i < binding_functions.size(); i++) { - if (!binding_functions[i].first) { - // free, we'll take it - idx = i; - break; - } - } - - if (idx == -1) { - idx = binding_functions.size(); - binding_functions.resize(idx + 1); - } - - // set the functions - binding_functions.write[idx].first = true; - binding_functions.write[idx].second = p_binding_functions; - - return idx; -} - -void NativeScriptLanguage::unregister_binding_functions(int p_idx) { - ERR_FAIL_INDEX(p_idx, binding_functions.size()); - - for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) { - Vector<void *> &binding_data = *E->get(); - - if (p_idx < binding_data.size() && binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data) { - binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]); - } - } - - binding_functions.write[p_idx].first = false; - - if (binding_functions[p_idx].second.free_func) { - binding_functions[p_idx].second.free_func(binding_functions[p_idx].second.data); - } -} - -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."); - - Vector<void *> *binding_data = (Vector<void *> *)p_object->get_script_instance_binding(lang_idx); - - if (!binding_data) { - return nullptr; // should never happen. - } - - if (binding_data->size() <= p_idx) { - // okay, add new elements here. - int old_size = binding_data->size(); - - binding_data->resize(p_idx + 1); - - for (int i = old_size; i <= p_idx; i++) { - (*binding_data).write[i] = nullptr; - } - } - - if (!(*binding_data)[p_idx]) { - const void *global_type_tag = get_global_type_tag(p_idx, p_object->get_class_name()); - - // no binding data yet, soooooo alloc new one \o/ - (*binding_data).write[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, global_type_tag, (godot_object *)p_object); - } - - 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()); - - for (int i = 0; i < binding_functions.size(); i++) { - (*binding_data).write[i] = nullptr; - } - - 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; - } - - Vector<void *> &binding_data = *(Vector<void *> *)p_data; - - for (int i = 0; i < binding_data.size(); i++) { - if (!binding_data[i]) { - continue; - } - - if (binding_functions[i].first && binding_functions[i].second.free_instance_binding_data) { - binding_functions[i].second.free_instance_binding_data(binding_functions[i].second.data, binding_data[i]); - } - } - - 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) { - return; - } - - Vector<void *> &binding_data = *(Vector<void *> *)data; - - for (int i = 0; i < binding_data.size(); i++) { - if (!binding_data[i]) { - continue; - } - - if (!binding_functions[i].first) { - continue; - } - - if (binding_functions[i].second.refcount_incremented_instance_binding) { - 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) { - return true; - } - - Vector<void *> &binding_data = *(Vector<void *> *)data; - - bool can_die = true; - - for (int i = 0; i < binding_data.size(); i++) { - if (!binding_data[i]) { - continue; - } - - if (!binding_functions[i].first) { - continue; - } - - if (binding_functions[i].second.refcount_decremented_instance_binding) { - can_die = can_die && binding_functions[i].second.refcount_decremented_instance_binding(binding_data[i], p_object); - } - } - - return can_die; -#endif - return false; -} - -void NativeScriptLanguage::set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag) { - if (!global_type_tags.has(p_idx)) { - global_type_tags.insert(p_idx, HashMap<StringName, const void *>()); - } - - HashMap<StringName, const void *> &tags = global_type_tags[p_idx]; - - tags.set(p_class_name, p_type_tag); -} - -const void *NativeScriptLanguage::get_global_type_tag(int p_idx, StringName p_class_name) const { - if (!global_type_tags.has(p_idx)) { - return nullptr; - } - - const HashMap<StringName, const void *> &tags = global_type_tags[p_idx]; - - if (!tags.has(p_class_name)) { - return nullptr; - } - - const void *tag = tags.get(p_class_name); - - return tag; -} - -#ifndef NO_THREADS -void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) { - MutexLock lock(mutex); - libs_to_init.insert(lib); - scripts_to_register.insert(script); - has_objects_to_register.set(); -} -#endif - -void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { - MutexLock lock(mutex); - - // See if this library was "registered" already. - const String &lib_path = lib->get_current_library_path(); - ERR_FAIL_COND_MSG(lib_path.length() == 0, lib->get_name() + " does not have a library for the current platform."); - Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path); - - if (!E) { - Ref<GDNative> gdn; - gdn.instantiate(); - gdn->set_library(lib); - - // TODO check the return value? - gdn->initialize(); - - library_gdnatives.insert(lib_path, gdn); - - library_classes.insert(lib_path, Map<StringName, NativeScriptDesc>()); - - if (!library_script_users.has(lib_path)) { - library_script_users.insert(lib_path, Set<NativeScript *>()); - } - - void *proc_ptr; - - Error err = gdn->get_symbol(lib->get_symbol_prefix() + _init_call_name, proc_ptr); - - if (err != OK) { - ERR_PRINT(String("No " + _init_call_name + " in \"" + lib_path + "\" found").utf8().get_data()); - } else { - ((void (*)(godot_string *))proc_ptr)((godot_string *)&lib_path); - } - } else { - // already initialized. Nice. - } -} - -void NativeScriptLanguage::register_script(NativeScript *script) { - MutexLock lock(mutex); - - library_script_users[script->lib_path].insert(script); -} - -void NativeScriptLanguage::unregister_script(NativeScript *script) { - MutexLock lock(mutex); - - Map<String, Set<NativeScript *>>::Element *S = library_script_users.find(script->lib_path); - if (S) { - S->get().erase(script); - if (S->get().size() == 0) { - library_script_users.erase(S); - - 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 (KeyValue<StringName, NativeScriptDesc> &C : classes) { - // free property stuff first - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C.value.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 (const KeyValue<StringName, NativeScriptDesc::Method> &M : C.value.methods) { - if (M.value.method.free_func) { - M.value.method.free_func(M.value.method.method_data); - } - } - - // free constructor/destructor - if (C.value.create_func.free_func) { - C.value.create_func.free_func(C.value.create_func.method_data); - } - - if (C.value.destroy_func.free_func) { - C.value.destroy_func.free_func(C.value.destroy_func.method_data); - } - } - - library_classes.erase(script->lib_path); - } - - // now unload the library - G->get()->terminate(); - library_gdnatives.erase(G); - } - } - } -#ifndef NO_THREADS - scripts_to_register.erase(script); -#endif -} - -void NativeScriptLanguage::call_libraries_cb(const StringName &name) { - // library_gdnatives is modified only from the main thread, so it's safe not to use mutex here - for (KeyValue<String, Ref<GDNative>> &L : library_gdnatives) { - if (L.value.is_null()) { - continue; - } - - if (L.value->is_initialized()) { - void *proc_ptr; - Error err = L.value->get_symbol(L.value->get_library()->get_symbol_prefix() + name, proc_ptr); - - if (!err) { - ((void (*)())proc_ptr)(); - } - } - } -} - -void NativeScriptLanguage::frame() { -#ifndef NO_THREADS - if (has_objects_to_register.is_set()) { - MutexLock lock(mutex); - for (Set<Ref<GDNativeLibrary>>::Element *L = libs_to_init.front(); L; L = L->next()) { - init_library(L->get()); - } - libs_to_init.clear(); - for (Set<NativeScript *>::Element *S = scripts_to_register.front(); S; S = S->next()) { - register_script(S->get()); - } - scripts_to_register.clear(); - has_objects_to_register.clear(); - } -#endif - -#ifdef DEBUG_ENABLED - { - MutexLock lock(mutex); - - for (KeyValue<StringName, ProfileData> &d : profile_data) { - d.value.last_frame_call_count = d.value.frame_call_count; - d.value.last_frame_self_time = d.value.frame_self_time; - d.value.last_frame_total_time = d.value.frame_total_time; - d.value.frame_call_count = 0; - d.value.frame_self_time = 0; - d.value.frame_total_time = 0; - } - } -#endif - - call_libraries_cb(_frame_call_name); -} - -#ifndef NO_THREADS - -void NativeScriptLanguage::thread_enter() { - call_libraries_cb(_thread_enter_call_name); -} - -void NativeScriptLanguage::thread_exit() { - call_libraries_cb(_thread_exit_call_name); -} - -#endif // NO_THREADS - -bool NativeScriptLanguage::handles_global_class_type(const String &p_type) const { - return p_type == "NativeScript"; -} - -String NativeScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { - if (!p_path.is_empty()) { - Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript"); - if (script.is_valid()) { - if (r_base_type) { - *r_base_type = script->get_instance_base_type(); - } - if (r_icon_path) { - *r_icon_path = script->get_script_class_icon_path(); - } - return script->get_script_class_name(); - } - if (r_base_type) { - *r_base_type = String(); - } - if (r_icon_path) { - *r_icon_path = String(); - } - } - return String(); -} - -void NativeReloadNode::_bind_methods() { - ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification); -} - -void NativeReloadNode::_notification(int p_what) { -#ifdef TOOLS_ENABLED - - switch (p_what) { - case NOTIFICATION_APPLICATION_FOCUS_OUT: { - if (unloaded) { - break; - } - MutexLock lock(NSL->mutex); - NSL->_unload_stuff(true); - - for (KeyValue<String, Ref<GDNative>> &L : NSL->library_gdnatives) { - Ref<GDNative> gdn = L.value; - - if (gdn.is_null()) { - continue; - } - - // Don't unload what should not be reloaded! - if (!gdn->get_library()->is_reloadable()) { - continue; - } - - // singleton libraries might have alive pointers living inside the - // editor. Also reloading a singleton library would mean that - // the singleton entry will not be called again, as this only - // happens at engine startup. - if (gdn->get_library()->is_singleton()) { - continue; - } - - gdn->terminate(); - } - - unloaded = true; - - } break; - - case NOTIFICATION_APPLICATION_FOCUS_IN: { - if (!unloaded) { - break; - } - MutexLock lock(NSL->mutex); - - Set<StringName> libs_to_remove; - for (KeyValue<String, Ref<GDNative>> &L : NSL->library_gdnatives) { - Ref<GDNative> gdn = L.value; - - if (gdn.is_null()) { - continue; - } - - if (!gdn->get_library()->is_reloadable()) { - continue; - } - - // since singleton libraries are not unloaded there is no point - // in loading them again. - if (gdn->get_library()->is_singleton()) { - continue; - } - - if (!gdn->initialize()) { - libs_to_remove.insert(L.key); - continue; - } - - NSL->library_classes.insert(L.key, Map<StringName, NativeScriptDesc>()); - - // here the library registers all the classes and stuff. - - void *proc_ptr; - Error err = gdn->get_symbol(gdn->get_library()->get_symbol_prefix() + "nativescript_init", proc_ptr); - if (err != OK) { - ERR_PRINT(String("No godot_nativescript_init in \"" + L.key + "\" found").utf8().get_data()); - } else { - ((void (*)(void *))proc_ptr)((void *)&L.key); - } - - for (KeyValue<String, Set<NativeScript *>> &U : NSL->library_script_users) { - for (Set<NativeScript *>::Element *S = U.value.front(); S; S = S->next()) { - NativeScript *script = S->get(); - - if (script->placeholders.size() == 0) { - continue; - } - - for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) { - script->_update_placeholder(P->get()); - } - } - } - } - - unloaded = false; - - for (Set<StringName>::Element *R = libs_to_remove.front(); R; R = R->next()) { - NSL->library_gdnatives.erase(R->get()); - } - - } break; - default: { - }; - } -#endif -} - -RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_no_cache) { - return ResourceFormatLoaderText::singleton->load(p_path, p_original_path, r_error); -} - -void ResourceFormatLoaderNativeScript::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdns"); -} - -bool ResourceFormatLoaderNativeScript::handles_type(const String &p_type) const { - return (p_type == "Script" || p_type == "NativeScript"); -} - -String ResourceFormatLoaderNativeScript::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "gdns") { - return "NativeScript"; - } - return ""; -} - -Error ResourceFormatSaverNativeScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - ResourceFormatSaverText rfst; - return rfst.save(p_path, p_resource, p_flags); -} - -bool ResourceFormatSaverNativeScript::recognize(const RES &p_resource) const { - return Object::cast_to<NativeScript>(*p_resource) != nullptr; -} - -void ResourceFormatSaverNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (Object::cast_to<NativeScript>(*p_resource)) { - p_extensions->push_back("gdns"); - } -} diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h deleted file mode 100644 index 2364c6c0f6..0000000000 --- a/modules/gdnative/nativescript/nativescript.h +++ /dev/null @@ -1,393 +0,0 @@ -/*************************************************************************/ -/* nativescript.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 NATIVE_SCRIPT_H -#define NATIVE_SCRIPT_H - -#include "core/doc_data.h" -#include "core/io/resource.h" -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/object/script_language.h" -#include "core/os/mutex.h" -#include "core/os/thread_safe.h" -#include "core/templates/oa_hash_map.h" -#include "core/templates/ordered_hash_map.h" -#include "core/templates/safe_refcount.h" -#include "core/templates/self_list.h" -#include "scene/main/node.h" - -#include "modules/gdnative/gdnative.h" - -#include <nativescript/godot_nativescript.h> - -struct NativeScriptDesc { - struct Method { - godot_nativescript_instance_method method; - MethodInfo info; - int rpc_mode = 0; - uint16_t rpc_method_id = 0; - String documentation; - }; - - struct Property { - godot_nativescript_property_set_func setter; - godot_nativescript_property_get_func getter; - PropertyInfo info; - Variant default_value; - String documentation; - }; - - struct Signal { - MethodInfo signal; - String documentation; - }; - - Map<StringName, Method> methods; - Vector<Multiplayer::RPCConfig> rpc_methods; - OrderedHashMap<StringName, Property> properties; - Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals - StringName base; - StringName base_native_type; - NativeScriptDesc *base_data = nullptr; - godot_nativescript_instance_create_func create_func; - godot_nativescript_instance_destroy_func destroy_func; - - String documentation; - - const void *type_tag = nullptr; - - bool is_tool = false; - - inline NativeScriptDesc() { - memset(&create_func, 0, sizeof(godot_nativescript_instance_create_func)); - memset(&destroy_func, 0, sizeof(godot_nativescript_instance_destroy_func)); - } -}; - -class NativeScript : public Script { - GDCLASS(NativeScript, Script); - -#ifdef TOOLS_ENABLED - Set<PlaceHolderScriptInstance *> placeholders; - void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); - virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; -#endif - - friend class NativeScriptInstance; - friend class NativeScriptLanguage; - friend class NativeReloadNode; - friend class GDNativeLibrary; - - Ref<GDNativeLibrary> library; - - String lib_path; - - String class_name; - - String script_class_name; - String script_class_icon_path; - - Mutex owners_lock; - Set<Object *> instance_owners; - -protected: - static void _bind_methods(); - -public: - inline NativeScriptDesc *get_script_desc() const; - - bool inherits_script(const Ref<Script> &p_script) const override; - - void set_class_name(String p_class_name); - String get_class_name() const; - - void set_library(Ref<GDNativeLibrary> p_library); - Ref<GDNativeLibrary> get_library() const; - - void set_script_class_name(String p_type); - String get_script_class_name() const; - void set_script_class_icon_path(String p_icon_path); - String get_script_class_icon_path() const; - - virtual bool can_instantiate() const override; - - virtual Ref<Script> get_base_script() const override; //for script inheritance - - virtual StringName get_instance_base_type() const override; // this may not work in all scripts, will return empty if so - virtual ScriptInstance *instance_create(Object *p_this) override; - virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) override; - virtual bool instance_has(const Object *p_this) const override; - - virtual bool has_source_code() const override; - virtual String get_source_code() const override; - virtual void set_source_code(const String &p_code) override; - virtual Error reload(bool p_keep_state = false) override; - -#ifdef TOOLS_ENABLED - virtual const Vector<DocData::ClassDoc> &get_documentation() const override { - static Vector<DocData::ClassDoc> docs; - return docs; - } -#endif // TOOLS_ENABLED - - virtual bool has_method(const StringName &p_method) const override; - virtual MethodInfo get_method_info(const StringName &p_method) const override; - - virtual bool is_tool() const override; - virtual bool is_valid() const override; - - virtual ScriptLanguage *get_language() const override; - - virtual bool has_script_signal(const StringName &p_signal) const override; - virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override; - - virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const override; - - virtual void update_exports() override; //editor tool - 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 const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; - - String get_class_documentation() const; - String get_method_documentation(const StringName &p_method) const; - String get_signal_documentation(const StringName &p_signal_name) const; - String get_property_documentation(const StringName &p_path) const; - - Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - - NativeScript(); - ~NativeScript(); -}; - -class NativeScriptInstance : public ScriptInstance { - friend class NativeScript; - - Object *owner; - Ref<NativeScript> script; -#ifdef DEBUG_ENABLED - StringName current_method_call; -#endif - - void _ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount); - -public: - void *userdata; - - virtual bool set(const StringName &p_name, const Variant &p_value); - virtual bool get(const StringName &p_name, Variant &r_ret) const; - virtual void get_property_list(List<PropertyInfo> *p_properties) const; - virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const; - virtual void get_method_list(List<MethodInfo> *p_list) const; - virtual bool has_method(const StringName &p_method) const; - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void notification(int p_notification); - String to_string(bool *r_valid); - virtual Ref<Script> get_script() const; - - virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const; - - virtual ScriptLanguage *get_language(); - - virtual void refcount_incremented(); - virtual bool refcount_decremented(); - - ~NativeScriptInstance(); -}; - -class NativeReloadNode; - -class NativeScriptLanguage : public ScriptLanguage { - friend class NativeScript; - friend class NativeScriptInstance; - friend class NativeReloadNode; - -private: - static NativeScriptLanguage *singleton; - int lang_idx = 0; - - void _unload_stuff(bool p_reload = false); - - Mutex mutex; -#ifndef NO_THREADS - Set<Ref<GDNativeLibrary>> libs_to_init; - Set<NativeScript *> scripts_to_register; - SafeFlag has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed - void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script); -#endif - - void init_library(const Ref<GDNativeLibrary> &lib); - void register_script(NativeScript *script); - void unregister_script(NativeScript *script); - - void call_libraries_cb(const StringName &name); - - Vector<Pair<bool, godot_nativescript_instance_binding_functions>> binding_functions; - Set<Vector<void *> *> binding_instances; - - Map<int, HashMap<StringName, const void *>> global_type_tags; - - struct ProfileData { - StringName signature; - uint64_t call_count = 0; - uint64_t self_time = 0; - uint64_t total_time = 0; - uint64_t frame_call_count = 0; - uint64_t frame_self_time = 0; - uint64_t frame_total_time = 0; - uint64_t last_frame_call_count = 0; - uint64_t last_frame_self_time = 0; - uint64_t last_frame_total_time = 0; - }; - - Map<StringName, ProfileData> profile_data; - -public: - // These two maps must only be touched on the main thread - Map<String, Map<StringName, NativeScriptDesc>> library_classes; - Map<String, Ref<GDNative>> library_gdnatives; - - Map<String, Set<NativeScript *>> library_script_users; - - StringName _init_call_type; - StringName _init_call_name; - StringName _terminate_call_name; - StringName _noarg_call_type; - StringName _frame_call_name; -#ifndef NO_THREADS - StringName _thread_enter_call_name; - StringName _thread_exit_call_name; -#endif - - NativeScriptLanguage(); - ~NativeScriptLanguage(); - - inline static NativeScriptLanguage *get_singleton() { - return singleton; - } - - _FORCE_INLINE_ void set_language_index(int p_idx) { lang_idx = p_idx; } - -#ifndef NO_THREADS - virtual void thread_enter(); - virtual void thread_exit(); -#endif - - virtual void frame(); - - virtual String get_name() const; - virtual void init(); - virtual String get_type() const; - virtual String get_extension() const; - 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, 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; - virtual int find_function(const String &p_function, const String &p_code) const; - virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; - virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; - virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); - virtual String debug_get_error() const; - virtual int debug_get_stack_level_count() const; - virtual int debug_get_stack_level_line(int p_level) const; - virtual String debug_get_stack_level_function(int p_level) const; - virtual String debug_get_stack_level_source(int p_level) const; - virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth); - virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth); - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth); - virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth); - virtual void reload_all_scripts(); - virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual void get_public_functions(List<MethodInfo> *p_functions) const; - virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const; - virtual void profiling_start(); - virtual void profiling_stop(); - virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); - virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); - - int register_binding_functions(godot_nativescript_instance_binding_functions p_binding_functions); - void unregister_binding_functions(int p_idx); - - void *get_instance_binding_data(int p_idx, Object *p_object); - - virtual void *alloc_instance_binding_data(Object *p_object); - virtual void free_instance_binding_data(void *p_data); - virtual void refcount_incremented_instance_binding(Object *p_object); - virtual bool refcount_decremented_instance_binding(Object *p_object); - - void set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag); - const void *get_global_type_tag(int p_idx, StringName p_class_name) const; - - virtual bool handles_global_class_type(const String &p_type) const; - virtual String get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const; - - void profiling_add_data(StringName p_signature, uint64_t p_time); -}; - -inline NativeScriptDesc *NativeScript::get_script_desc() const { - Map<StringName, NativeScriptDesc>::Element *E = NativeScriptLanguage::singleton->library_classes[lib_path].find(class_name); - return E ? &E->get() : nullptr; -} - -class NativeReloadNode : public Node { - GDCLASS(NativeReloadNode, Node); - bool unloaded = false; - -public: - static void _bind_methods(); - void _notification(int p_what); - - NativeReloadNode() {} -}; - -class ResourceFormatLoaderNativeScript : 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; -}; - -class ResourceFormatSaverNativeScript : public ResourceFormatSaver { - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual bool recognize(const RES &p_resource) const; - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; -}; - -#endif // GDNATIVE_H diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp deleted file mode 100644 index 82a3459517..0000000000 --- a/modules/gdnative/nativescript/register_types.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" - -#include "nativescript.h" - -#include "core/os/os.h" - -NativeScriptLanguage *native_script_language; - -Ref<ResourceFormatLoaderNativeScript> resource_loader_gdns; -Ref<ResourceFormatSaverNativeScript> resource_saver_gdns; - -void register_nativescript_types() { - native_script_language = memnew(NativeScriptLanguage); - - GDREGISTER_CLASS(NativeScript); - - native_script_language->set_language_index(ScriptServer::get_language_count()); - ScriptServer::register_language(native_script_language); - - resource_saver_gdns.instantiate(); - ResourceSaver::add_resource_format_saver(resource_saver_gdns); - - resource_loader_gdns.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_gdns); -} - -void unregister_nativescript_types() { - ResourceLoader::remove_resource_format_loader(resource_loader_gdns); - resource_loader_gdns.unref(); - - ResourceSaver::remove_resource_format_saver(resource_saver_gdns); - resource_saver_gdns.unref(); - - if (native_script_language) { - ScriptServer::unregister_language(native_script_language); - memdelete(native_script_language); - } -} diff --git a/modules/gdnative/nativescript/register_types.h b/modules/gdnative/nativescript/register_types.h deleted file mode 100644 index d12ac9eda3..0000000000 --- a/modules/gdnative/nativescript/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef NATIVESCRIPT_REGISTER_TYPES_H -#define NATIVESCRIPT_REGISTER_TYPES_H - -void register_nativescript_types(); -void unregister_nativescript_types(); - -#endif // NATIVESCRIPT_REGISTER_TYPES_H diff --git a/modules/gdnative/pluginscript/SCsub b/modules/gdnative/pluginscript/SCsub deleted file mode 100644 index 0b2db3b504..0000000000 --- a/modules/gdnative/pluginscript/SCsub +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_gdnative") - -env_gdnative.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp deleted file mode 100644 index feae81397e..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_instance.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/*************************************************************************/ -/* pluginscript_instance.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 "pluginscript_instance.h" - -// Godot imports -#include "core/os/os.h" -#include "core/variant/variant.h" - -// PluginScript imports -#include "pluginscript_language.h" -#include "pluginscript_script.h" - -bool PluginScriptInstance::set(const StringName &p_name, const Variant &p_value) { - return _desc->set_prop(_data, (const godot_string_name *)&p_name, (const godot_variant *)&p_value); -} - -bool PluginScriptInstance::get(const StringName &p_name, Variant &r_ret) const { - return _desc->get_prop(_data, (const godot_string_name *)&p_name, (godot_variant *)&r_ret); -} - -Ref<Script> PluginScriptInstance::get_script() const { - return _script; -} - -ScriptLanguage *PluginScriptInstance::get_language() { - return _script->get_language(); -} - -Variant::Type PluginScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - if (!_script->has_property(p_name)) { - if (r_is_valid) { - *r_is_valid = false; - } - return Variant::NIL; - } - if (r_is_valid) { - *r_is_valid = true; - } - return _script->get_property_info(p_name).type; -} - -void PluginScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { - _script->get_script_property_list(p_properties); -} - -void PluginScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - _script->get_script_method_list(p_list); -} - -bool PluginScriptInstance::has_method(const StringName &p_method) const { - return _script->has_method(p_method); -} - -Variant PluginScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - // TODO: optimize when calling a Godot method from Godot to avoid param conversion ? - godot_variant ret = _desc->call_method( - _data, (godot_string_name *)&p_method, (const godot_variant **)p_args, - p_argcount, (godot_variant_call_error *)&r_error); - Variant var_ret = *(Variant *)&ret; - godot_variant_destroy(&ret); - return var_ret; -} - -void PluginScriptInstance::notification(int p_notification) { - _desc->notification(_data, p_notification); -} - -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; -} - -const Vector<Multiplayer::RPCConfig> PluginScriptInstance::get_rpc_methods() const { - return _script->get_rpc_methods(); -} - -void PluginScriptInstance::refcount_incremented() { - if (_desc->refcount_decremented) { - _desc->refcount_incremented(_data); - } -} - -bool PluginScriptInstance::refcount_decremented() { - // Return true if it can die - if (_desc->refcount_decremented) { - return _desc->refcount_decremented(_data); - } - return true; -} - -PluginScriptInstance::PluginScriptInstance() { -} - -bool PluginScriptInstance::init(PluginScript *p_script, Object *p_owner) { - _owner = p_owner; - _owner_variant = Variant(p_owner); - _script = Ref<PluginScript>(p_script); - _desc = &p_script->_desc->instance_desc; - _data = _desc->init(p_script->_data, (godot_object *)p_owner); - ERR_FAIL_COND_V(_data == nullptr, false); - p_owner->set_script_instance(this); - return true; -} - -PluginScriptInstance::~PluginScriptInstance() { - _desc->finish(_data); - _script->_language->lock(); - _script->_instances.erase(_owner); - _script->_language->unlock(); -} diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h deleted file mode 100644 index 81e711bafc..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************/ -/* pluginscript_instance.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 PLUGINSCRIPT_INSTANCE_H -#define PLUGINSCRIPT_INSTANCE_H - -// Godot imports -#include "core/object/script_language.h" - -// PluginScript imports -#include <pluginscript/godot_pluginscript.h> - -class PluginScript; - -class PluginScriptInstance : public ScriptInstance { - friend class PluginScript; - -private: - Ref<PluginScript> _script; - Object *_owner = nullptr; - Variant _owner_variant; - godot_pluginscript_instance_data *_data = nullptr; - const godot_pluginscript_instance_desc *_desc = nullptr; - -public: - _FORCE_INLINE_ Object *get_owner() { return _owner; } - - virtual bool set(const StringName &p_name, const Variant &p_value); - virtual bool get(const StringName &p_name, Variant &r_ret) const; - virtual void get_property_list(List<PropertyInfo> *p_properties) const; - virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const; - - virtual void get_method_list(List<MethodInfo> *p_list) const; - virtual bool has_method(const StringName &p_method) const; - - 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; - - virtual ScriptLanguage *get_language(); - - virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const; - - virtual void refcount_incremented(); - virtual bool refcount_decremented(); - - PluginScriptInstance(); - bool init(PluginScript *p_script, Object *p_owner); - virtual ~PluginScriptInstance(); -}; - -#endif // PLUGINSCRIPT_INSTANCE_H diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp deleted file mode 100644 index 79aba342c9..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/*************************************************************************/ -/* pluginscript_language.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. */ -/*************************************************************************/ - -// Godot imports -#include "core/config/project_settings.h" -#include "core/io/file_access.h" -#include "core/os/os.h" -// PluginScript imports -#include "pluginscript_language.h" -#include "pluginscript_script.h" - -String PluginScriptLanguage::get_name() const { - return String(_desc.name); -} - -void PluginScriptLanguage::init() { - _data = _desc.init(); -} - -String PluginScriptLanguage::get_type() const { - // We should use _desc.type here, however the returned type is used to - // query ClassDB which would complain given the type is not registered - // from his point of view... - // To solve this we just use a more generic (but present in ClassDB) type. - return String("PluginScript"); -} - -String PluginScriptLanguage::get_extension() const { - return String(_desc.extension); -} - -Error PluginScriptLanguage::execute_file(const String &p_path) { - // TODO: pretty sure this method is totally deprecated and should be removed... - return OK; -} - -void PluginScriptLanguage::finish() { - _desc.finish(_data); -} - -/* EDITOR FUNCTIONS */ - -void PluginScriptLanguage::get_reserved_words(List<String> *p_words) const { - if (_desc.reserved_words) { - const char **w = _desc.reserved_words; - while (*w) { - p_words->push_back(*w); - w++; - } - } -} - -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; - while (*w) { - p_delimiters->push_back(*w); - w++; - } - } -} - -void PluginScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { - if (_desc.string_delimiters) { - const char **w = _desc.string_delimiters; - while (*w) { - p_delimiters->push_back(*w); - w++; - } - } -} - -Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - Script *ns = create_script(); - Ref<Script> script = Ref<Script>(ns); - if (_desc.get_template_source_code) { - godot_string src = _desc.get_template_source_code(_data, (godot_string *)&p_class_name, (godot_string *)&p_base_class_name); - script->set_source_code(*(String *)&src); - godot_string_destroy(&src); - } - return script; -} - -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, - (godot_string *)&p_path, - (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; -} - -Script *PluginScriptLanguage::create_script() const { - PluginScript *script = memnew(PluginScript()); - // I'm hurting kittens doing this I guess... - script->init(const_cast<PluginScriptLanguage *>(this)); - return script; -} - -bool PluginScriptLanguage::has_named_classes() const { - return _desc.has_named_classes; -} - -bool PluginScriptLanguage::supports_builtin_mode() const { - return _desc.supports_builtin_mode; -} - -bool PluginScriptLanguage::can_inherit_from_file() const { - return _desc.can_inherit_from_file; -} - -int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const { - if (_desc.find_function) { - return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code); - } - return -1; -} - -String PluginScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const { - if (_desc.make_function) { - godot_string tmp = _desc.make_function(_data, (godot_string *)&p_class, (godot_string *)&p_name, (godot_packed_string_array *)&p_args); - String ret = *(String *)&tmp; - godot_string_destroy(&tmp); - return ret; - } - return String(); -} - -Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { - if (_desc.complete_code) { - Array options; - godot_error tmp = _desc.complete_code( - _data, - (godot_string *)&p_code, - (godot_string *)&p_path, - (godot_object *)p_owner, - (godot_array *)&options, - &r_force, - (godot_string *)&r_call_hint); - for (int i = 0; i < options.size(); i++) { - ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - r_options->push_back(option); - } - return (Error)tmp; - } - return ERR_UNAVAILABLE; -} - -void PluginScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { - if (_desc.auto_indent_code) { - _desc.auto_indent_code(_data, (godot_string *)&p_code, p_from_line, p_to_line); - } - return; -} - -void PluginScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { - _desc.add_global_constant(_data, (godot_string_name *)&p_variable, (godot_variant *)&p_value); -} - -/* LOADER FUNCTIONS */ - -void PluginScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { - for (int i = 0; _desc.recognized_extensions[i]; ++i) { - p_extensions->push_back(String(_desc.recognized_extensions[i])); - } -} - -void PluginScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { - // TODO: provide this statically in `godot_pluginscript_language_desc` ? - if (_desc.get_public_functions) { - Array functions; - _desc.get_public_functions(_data, (godot_array *)&functions); - for (int i = 0; i < functions.size(); i++) { - MethodInfo mi = MethodInfo::from_dict(functions[i]); - p_functions->push_back(mi); - } - } -} - -void PluginScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const { - // TODO: provide this statically in `godot_pluginscript_language_desc` ? - if (_desc.get_public_constants) { - Dictionary constants; - _desc.get_public_constants(_data, (godot_dictionary *)&constants); - for (const Variant *key = constants.next(); key; key = constants.next(key)) { - Variant value = constants[*key]; - p_constants->push_back(Pair<String, Variant>(*key, value)); - } - } -} - -void PluginScriptLanguage::profiling_start() { -#ifdef DEBUG_ENABLED - if (_desc.profiling_start) { - lock(); - _desc.profiling_start(_data); - unlock(); - } -#endif -} - -void PluginScriptLanguage::profiling_stop() { -#ifdef DEBUG_ENABLED - if (_desc.profiling_stop) { - lock(); - _desc.profiling_stop(_data); - unlock(); - } -#endif -} - -int PluginScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { - int info_count = 0; -#ifdef DEBUG_ENABLED - if (_desc.profiling_get_accumulated_data) { - godot_pluginscript_profiling_data *info = (godot_pluginscript_profiling_data *)memalloc( - sizeof(godot_pluginscript_profiling_data) * p_info_max); - info_count = _desc.profiling_get_accumulated_data(_data, info, p_info_max); - for (int i = 0; i < info_count; ++i) { - p_info_arr[i].signature = *(StringName *)&info[i].signature; - p_info_arr[i].call_count = info[i].call_count; - p_info_arr[i].total_time = info[i].total_time; - p_info_arr[i].self_time = info[i].self_time; - godot_string_name_destroy(&info[i].signature); - } - } -#endif - return info_count; -} - -int PluginScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { - int info_count = 0; -#ifdef DEBUG_ENABLED - if (_desc.profiling_get_frame_data) { - godot_pluginscript_profiling_data *info = (godot_pluginscript_profiling_data *)memalloc( - sizeof(godot_pluginscript_profiling_data) * p_info_max); - info_count = _desc.profiling_get_frame_data(_data, info, p_info_max); - for (int i = 0; i < info_count; ++i) { - p_info_arr[i].signature = *(StringName *)&info[i].signature; - p_info_arr[i].call_count = info[i].call_count; - p_info_arr[i].total_time = info[i].total_time; - p_info_arr[i].self_time = info[i].self_time; - godot_string_name_destroy(&info[i].signature); - } - } -#endif - return info_count; -} - -void PluginScriptLanguage::frame() { -#ifdef DEBUG_ENABLED - if (_desc.profiling_frame) { - _desc.profiling_frame(_data); - } -#endif -} - -/* DEBUGGER FUNCTIONS */ - -String PluginScriptLanguage::debug_get_error() const { - if (_desc.debug_get_error) { - godot_string tmp = _desc.debug_get_error(_data); - String ret = *(String *)&tmp; - godot_string_destroy(&tmp); - return ret; - } - return String("Nothing"); -} - -int PluginScriptLanguage::debug_get_stack_level_count() const { - if (_desc.debug_get_stack_level_count) { - return _desc.debug_get_stack_level_count(_data); - } - return 1; -} - -int PluginScriptLanguage::debug_get_stack_level_line(int p_level) const { - if (_desc.debug_get_stack_level_line) { - return _desc.debug_get_stack_level_line(_data, p_level); - } - return 1; -} - -String PluginScriptLanguage::debug_get_stack_level_function(int p_level) const { - if (_desc.debug_get_stack_level_function) { - godot_string tmp = _desc.debug_get_stack_level_function(_data, p_level); - String ret = *(String *)&tmp; - godot_string_destroy(&tmp); - return ret; - } - return String("Nothing"); -} - -String PluginScriptLanguage::debug_get_stack_level_source(int p_level) const { - if (_desc.debug_get_stack_level_source) { - godot_string tmp = _desc.debug_get_stack_level_source(_data, p_level); - String ret = *(String *)&tmp; - godot_string_destroy(&tmp); - return ret; - } - return String("Nothing"); -} - -void PluginScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_desc.debug_get_stack_level_locals) { - PackedStringArray locals; - Array values; - _desc.debug_get_stack_level_locals(_data, p_level, (godot_packed_string_array *)&locals, (godot_array *)&values, p_max_subitems, p_max_depth); - for (int i = 0; i < locals.size(); i++) { - p_locals->push_back(locals[i]); - } - for (int i = 0; i < values.size(); i++) { - p_values->push_back(values[i]); - } - } -} - -void PluginScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_desc.debug_get_stack_level_members) { - PackedStringArray members; - Array values; - _desc.debug_get_stack_level_members(_data, p_level, (godot_packed_string_array *)&members, (godot_array *)&values, p_max_subitems, p_max_depth); - for (int i = 0; i < members.size(); i++) { - p_members->push_back(members[i]); - } - for (int i = 0; i < values.size(); i++) { - p_values->push_back(values[i]); - } - } -} - -void PluginScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_desc.debug_get_globals) { - PackedStringArray locals; - Array values; - _desc.debug_get_globals(_data, (godot_packed_string_array *)&locals, (godot_array *)&values, p_max_subitems, p_max_depth); - for (int i = 0; i < locals.size(); i++) { - p_locals->push_back(locals[i]); - } - for (int i = 0; i < values.size(); i++) { - p_values->push_back(values[i]); - } - } -} - -String PluginScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - if (_desc.debug_parse_stack_level_expression) { - godot_string tmp = _desc.debug_parse_stack_level_expression(_data, p_level, (godot_string *)&p_expression, p_max_subitems, p_max_depth); - String ret = *(String *)&tmp; - godot_string_destroy(&tmp); - return ret; - } - return String("Nothing"); -} - -void PluginScriptLanguage::reload_all_scripts() { - // TODO -} - -void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { -#ifdef DEBUG_ENABLED - lock(); - // TODO - unlock(); -#endif -} - -bool PluginScriptLanguage::handles_global_class_type(const String &p_type) const { - return p_type == "PluginScript"; -} - -String PluginScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { - if (!p_path.is_empty()) { - Ref<PluginScript> script = ResourceLoader::load(p_path, "PluginScript"); - if (script.is_valid()) { - if (r_base_type) { - *r_base_type = script->get_instance_base_type(); - } - if (r_icon_path) { - *r_icon_path = script->get_script_class_icon_path(); - } - return script->get_script_class_name(); - } - if (r_base_type) { - *r_base_type = String(); - } - if (r_icon_path) { - *r_icon_path = String(); - } - } - return String(); -} - -void PluginScriptLanguage::lock() { - _lock.lock(); -} - -void PluginScriptLanguage::unlock() { - _lock.unlock(); -} - -PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_desc *desc) : - _desc(*desc) { - _resource_loader = Ref<ResourceFormatLoaderPluginScript>(memnew(ResourceFormatLoaderPluginScript(this))); - _resource_saver = Ref<ResourceFormatSaverPluginScript>(memnew(ResourceFormatSaverPluginScript(this))); -} - -PluginScriptLanguage::~PluginScriptLanguage() { -} diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h deleted file mode 100644 index 26ab4a95e3..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************/ -/* pluginscript_language.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 PLUGINSCRIPT_LANGUAGE_H -#define PLUGINSCRIPT_LANGUAGE_H - -// Godot imports -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/object/script_language.h" -#include "core/templates/map.h" -#include "core/templates/self_list.h" -// PluginScript imports -#include "pluginscript_loader.h" -#include <pluginscript/godot_pluginscript.h> - -class PluginScript; -class PluginScriptInstance; - -class PluginScriptLanguage : public ScriptLanguage { - friend class PluginScript; - friend class PluginScriptInstance; - - Ref<ResourceFormatLoaderPluginScript> _resource_loader; - Ref<ResourceFormatSaverPluginScript> _resource_saver; - const godot_pluginscript_language_desc _desc; - godot_pluginscript_language_data *_data; - - Mutex _lock; - SelfList<PluginScript>::List _script_list; - -public: - virtual String get_name() const; - - _FORCE_INLINE_ Ref<ResourceFormatLoaderPluginScript> get_resource_loader() { return _resource_loader; } - _FORCE_INLINE_ Ref<ResourceFormatSaverPluginScript> get_resource_saver() { return _resource_saver; } - - /* LANGUAGE FUNCTIONS */ - virtual void init(); - virtual String get_type() const; - virtual String get_extension() const; - virtual Error execute_file(const String &p_path); - virtual void finish(); - - /* 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, 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; - virtual bool can_inherit_from_file() const; - virtual int find_function(const String &p_function, const String &p_code) const; - virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; - virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint); - virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; - virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); - - /* MULTITHREAD FUNCTIONS */ - - //some VMs need to be notified of thread creation/exiting to allocate a stack - // void thread_enter() {} - // void thread_exit() {} - - /* DEBUGGER FUNCTIONS */ - - virtual String debug_get_error() const; - virtual int debug_get_stack_level_count() const; - virtual int debug_get_stack_level_line(int p_level) const; - virtual String debug_get_stack_level_function(int p_level) const; - virtual String debug_get_stack_level_source(int p_level) const; - virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); - - // virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); } - - virtual void reload_all_scripts(); - virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); - - /* LOADER FUNCTIONS */ - - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual void get_public_functions(List<MethodInfo> *p_functions) const; - virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const; - - virtual void profiling_start(); - virtual void profiling_stop(); - - virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); - virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); - - virtual void frame(); - - /* GLOBAL CLASSES */ - - virtual bool handles_global_class_type(const String &p_type) const; - virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const; - - void lock(); - void unlock(); - - PluginScriptLanguage(const godot_pluginscript_language_desc *desc); - virtual ~PluginScriptLanguage(); -}; - -#endif // PLUGINSCRIPT_LANGUAGE_H diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp deleted file mode 100644 index 462452a897..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_loader.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/*************************************************************************/ -/* pluginscript_loader.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. */ -/*************************************************************************/ - -// Godot imports -#include "core/io/file_access.h" -// Pythonscript imports -#include "pluginscript_language.h" -#include "pluginscript_loader.h" -#include "pluginscript_script.h" - -ResourceFormatLoaderPluginScript::ResourceFormatLoaderPluginScript(PluginScriptLanguage *language) { - _language = language; -} - -RES ResourceFormatLoaderPluginScript::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_FILE_CANT_OPEN; - } - - PluginScript *script = memnew(PluginScript); - script->init(_language); - - Ref<PluginScript> scriptres(script); - - Error err = script->load_source_code(p_path); - ERR_FAIL_COND_V(err != OK, RES()); - - script->set_path(p_original_path); - - script->reload(); - - if (r_error) { - *r_error = OK; - } - - return scriptres; -} - -void ResourceFormatLoaderPluginScript::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back(_language->get_extension()); -} - -bool ResourceFormatLoaderPluginScript::handles_type(const String &p_type) const { - return p_type == "Script" || p_type == _language->get_type(); -} - -String ResourceFormatLoaderPluginScript::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == _language->get_extension()) { - return _language->get_type(); - } - return ""; -} - -ResourceFormatSaverPluginScript::ResourceFormatSaverPluginScript(PluginScriptLanguage *language) { - _language = language; -} - -Error ResourceFormatSaverPluginScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - Ref<PluginScript> sqscr = p_resource; - ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); - - String source = sqscr->get_source_code(); - - Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(err, err); - - file->store_string(source); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); - return ERR_CANT_CREATE; - } - file->close(); - memdelete(file); - return OK; -} - -void ResourceFormatSaverPluginScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (Object::cast_to<PluginScript>(*p_resource)) { - p_extensions->push_back(_language->get_extension()); - } -} - -bool ResourceFormatSaverPluginScript::recognize(const RES &p_resource) const { - return Object::cast_to<PluginScript>(*p_resource) != nullptr; -} diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h deleted file mode 100644 index e5d665c186..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_loader.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* pluginscript_loader.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 PYTHONSCRIPT_PY_LOADER_H -#define PYTHONSCRIPT_PY_LOADER_H - -// Godot imports -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/object/script_language.h" - -class PluginScriptLanguage; - -class ResourceFormatLoaderPluginScript : public ResourceFormatLoader { - PluginScriptLanguage *_language; - -public: - ResourceFormatLoaderPluginScript(PluginScriptLanguage *language); - 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; -}; - -class ResourceFormatSaverPluginScript : public ResourceFormatSaver { - PluginScriptLanguage *_language; - -public: - ResourceFormatSaverPluginScript(PluginScriptLanguage *language); - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const RES &p_resource) const; -}; - -#endif // PYTHONSCRIPT_PY_LOADER_H diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp deleted file mode 100644 index 5bda9e1d53..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/*************************************************************************/ -/* pluginscript_script.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. */ -/*************************************************************************/ - -// Godot imports -#include "core/io/file_access.h" -// PluginScript imports -#include "pluginscript_instance.h" -#include "pluginscript_script.h" - -#include <stdint.h> - -#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_instantiate(), __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() -#define ASSERT_SCRIPT_VALID_V(ret) -#endif - -void PluginScript::_bind_methods() { - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &PluginScript::_new, MethodInfo("new")); -} - -PluginScriptInstance *PluginScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, Callable::CallError &r_error) { - r_error.error = Callable::CallError::CALL_OK; - - // Create instance - PluginScriptInstance *instance = memnew(PluginScriptInstance()); - - if (instance->init(this, p_owner)) { - _language->lock(); - _instances.insert(instance->get_owner()); - _language->unlock(); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; - memdelete(instance); - ERR_FAIL_V(nullptr); - } - - // Construct - // TODO: Support arguments in the constructor? - // There is currently no way to get the constructor function name of the script. - // instance->call("__init__", p_args, p_argcount, r_error); - if (p_argcount > 0) { - WARN_PRINT("PluginScript doesn't support arguments in the constructor"); - } - - return instance; -} - -Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - r_error.error = Callable::CallError::CALL_OK; - - if (!_valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); - } - - REF ref; - Object *owner = nullptr; - - if (get_instance_base_type() == "") { - owner = memnew(RefCounted); - } else { - owner = ClassDB::instantiate(get_instance_base_type()); - } - - if (!owner) { - r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; - return Variant(); - } - - RefCounted *r = Object::cast_to<RefCounted>(owner); - if (r) { - ref = REF(r); - } - - PluginScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r_error); - - if (!instance) { - if (ref.is_null()) { - memdelete(owner); //no owner, sorry - } - return Variant(); - } - - if (ref.is_valid()) { - return ref; - } else { - return owner; - } -} - -#ifdef TOOLS_ENABLED - -void PluginScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - placeholders.erase(p_placeholder); -} - -#endif - -bool PluginScript::can_instantiate() const { - bool can = _valid || (!_tool && !ScriptServer::is_scripting_enabled()); - return can; -} - -bool PluginScript::inherits_script(const Ref<Script> &p_script) const { - Ref<PluginScript> ps = p_script; - if (ps.is_null()) { - return false; - } - - const PluginScript *s = this; - - while (s) { - if (s == p_script.ptr()) { - return true; - } - s = Object::cast_to<PluginScript>(s->_ref_base_parent.ptr()); - } - - return false; -} - -Ref<Script> PluginScript::get_base_script() const { - if (_ref_base_parent.is_valid()) { - return Ref<PluginScript>(_ref_base_parent); - } else { - return Ref<Script>(); - } -} - -StringName PluginScript::get_instance_base_type() const { - if (_native_parent) { - return _native_parent; - } - if (_ref_base_parent.is_valid()) { - return _ref_base_parent->get_instance_base_type(); - } - return StringName(); -} - -void PluginScript::update_exports() { -#ifdef TOOLS_ENABLED - ASSERT_SCRIPT_VALID(); - if (placeholders.size()) { - //update placeholders if any - Map<StringName, Variant> propdefvalues; - List<PropertyInfo> propinfos; - - get_script_property_list(&propinfos); - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propinfos, _properties_default_values); - } - } -#endif -} - -// TODO: rename p_this "p_owner" ? -ScriptInstance *PluginScript::instance_create(Object *p_this) { - ASSERT_SCRIPT_VALID_V(nullptr); - // TODO check script validity ? - if (!_tool && !ScriptServer::is_scripting_enabled()) { -#ifdef TOOLS_ENABLED - // Instance a fake script for editing the values - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(get_language(), Ref<Script>(this), p_this)); - placeholders.insert(si); - update_exports(); - return si; -#else - return nullptr; -#endif - } - - 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 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); - // } - ERR_FAIL_V_MSG(nullptr, msg); - } - } - - Callable::CallError unchecked_error; - return _create_instance(nullptr, 0, p_this, unchecked_error); -} - -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(); - return hasit; -} - -bool PluginScript::has_source_code() const { - return !_source.is_empty(); -} - -String PluginScript::get_source_code() const { - return _source; -} - -void PluginScript::set_source_code(const String &p_code) { - if (_source == p_code) { - return; - } - _source = p_code; -} - -Error PluginScript::reload(bool p_keep_state) { - ERR_FAIL_COND_V(!_language, ERR_UNCONFIGURED); - - _language->lock(); - ERR_FAIL_COND_V(!p_keep_state && _instances.size(), ERR_ALREADY_IN_USE); - _language->unlock(); - - _valid = false; - String basedir = _path; - - if (basedir.is_empty()) { - basedir = get_path(); - } - - if (!basedir.is_empty()) { - basedir = basedir.get_base_dir(); - } - - if (_data) { - _desc->finish(_data); - } - - Error err; - godot_pluginscript_script_manifest manifest = _desc->init( - _language->_data, - (godot_string *)&_path, - (godot_string *)&_source, - (godot_error *)&err); -// Manifest's attributes must be explicitly freed -#define FREE_SCRIPT_MANIFEST(manifest) \ - { \ - godot_string_name_destroy(&manifest.name); \ - godot_string_name_destroy(&manifest.base); \ - godot_dictionary_destroy(&manifest.member_lines); \ - godot_array_destroy(&manifest.methods); \ - godot_array_destroy(&manifest.signals); \ - godot_array_destroy(&manifest.properties); \ - } - - if (err) { - FREE_SCRIPT_MANIFEST(manifest); - // TODO: GDscript uses `ScriptDebugger` here to jump into the parsing error - return err; - } - - // Script's parent is passed as base_name which can make reference to a - // ClassDB name (i.e. `Node2D`) or a resource path (i.e. `res://foo/bar.gd`) - StringName *base_name = (StringName *)&manifest.base; - if (*base_name) { - if (ClassDB::class_exists(*base_name)) { - _native_parent = *base_name; - } else { - Ref<Script> res = ResourceLoader::load(*base_name); - if (res.is_valid()) { - _ref_base_parent = res; - } else { - String name = *(StringName *)&manifest.name; - FREE_SCRIPT_MANIFEST(manifest); - ERR_FAIL_V_MSG(ERR_PARSE_ERROR, _path + ": Script '" + name + "' has an invalid parent '" + *base_name + "'."); - } - } - } - - _valid = true; - // Use the manifest to configure this script object - _data = manifest.data; - _name = *(StringName *)&manifest.name; - _tool = manifest.is_tool; - _icon_path = *(String *)&manifest.icon_path; - - Dictionary *members = (Dictionary *)&manifest.member_lines; - for (const Variant *key = members->next(); key != nullptr; key = members->next(key)) { - _member_lines[*key] = (*members)[*key]; - } - Array *methods = (Array *)&manifest.methods; - _rpc_methods.clear(); - if (_ref_base_parent.is_valid()) { - /// XXX TODO Should this be _rpc_methods.append_array(...) - _rpc_methods = _ref_base_parent->get_rpc_methods(); - } - for (int i = 0; i < methods->size(); ++i) { - Dictionary v = (*methods)[i]; - MethodInfo mi = MethodInfo::from_dict(v); - _methods_info[mi.name] = mi; - // rpc_mode is passed as an optional field and is not part of MethodInfo - Variant var = v["rpc_mode"]; - if (var != Variant()) { - Multiplayer::RPCConfig nd; - nd.name = mi.name; - nd.rpc_mode = Multiplayer::RPCMode(int(var)); - // TODO Transfer Channel - if (_rpc_methods.find(nd) == -1) { - _rpc_methods.push_back(nd); - } - } - } - - // Sort so we are 100% that they are always the same. - _rpc_methods.sort_custom<Multiplayer::SortRPCConfig>(); - - Array *signals = (Array *)&manifest.signals; - for (int i = 0; i < signals->size(); ++i) { - Variant v = (*signals)[i]; - MethodInfo mi = MethodInfo::from_dict(v); - _signals_info[mi.name] = mi; - } - Array *properties = (Array *)&manifest.properties; - for (int i = 0; i < properties->size(); ++i) { - Dictionary v = (*properties)[i]; - PropertyInfo pi = PropertyInfo::from_dict(v); - _properties_info[pi.name] = pi; - _properties_default_values[pi.name] = v["default_value"]; - } - - FREE_SCRIPT_MANIFEST(manifest); - return OK; -#undef FREE_SCRIPT_MANIFEST -} - -void PluginScript::get_script_method_list(List<MethodInfo> *r_methods) const { - ASSERT_SCRIPT_VALID(); - for (Map<StringName, MethodInfo>::Element *e = _methods_info.front(); e != nullptr; e = e->next()) { - r_methods->push_back(e->get()); - } -} - -void PluginScript::get_script_property_list(List<PropertyInfo> *r_properties) const { - ASSERT_SCRIPT_VALID(); - for (Map<StringName, PropertyInfo>::Element *e = _properties_info.front(); e != nullptr; e = e->next()) { - r_properties->push_back(e->get()); - } -} - -bool PluginScript::has_method(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(false); - return _methods_info.has(p_method); -} - -MethodInfo PluginScript::get_method_info(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(MethodInfo()); - const Map<StringName, MethodInfo>::Element *e = _methods_info.find(p_method); - if (e != nullptr) { - return e->get(); - } else { - return MethodInfo(); - } -} - -bool PluginScript::has_property(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(false); - return _properties_info.has(p_method); -} - -PropertyInfo PluginScript::get_property_info(const StringName &p_property) const { - ASSERT_SCRIPT_VALID_V(PropertyInfo()); - const Map<StringName, PropertyInfo>::Element *e = _properties_info.find(p_property); - if (e != nullptr) { - return e->get(); - } else { - return PropertyInfo(); - } -} - -bool PluginScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - ASSERT_SCRIPT_VALID_V(false); -#ifdef TOOLS_ENABLED - const Map<StringName, Variant>::Element *e = _properties_default_values.find(p_property); - if (e != nullptr) { - r_value = e->get(); - return true; - } else { - return false; - } -#endif - return false; -} - -ScriptLanguage *PluginScript::get_language() const { - return _language; -} - -Error PluginScript::load_source_code(const String &p_path) { - Vector<uint8_t> sourcef; - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + p_path + "'."); - - uint64_t len = f->get_length(); - sourcef.resize(len + 1); - uint8_t *w = sourcef.ptrw(); - uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); - ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); - w[len] = 0; - - String s; - if (s.parse_utf8((const char *)w)) { - ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode."); - } - - _source = s; -#ifdef TOOLS_ENABLED -// source_changed_cache=true; -#endif - _path = p_path; - return OK; -} - -bool PluginScript::has_script_signal(const StringName &p_signal) const { - ASSERT_SCRIPT_VALID_V(false); - return _signals_info.has(p_signal); -} - -void PluginScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - ASSERT_SCRIPT_VALID(); - for (Map<StringName, MethodInfo>::Element *e = _signals_info.front(); e != nullptr; e = e->next()) { - r_signals->push_back(e->get()); - } -} - -int PluginScript::get_member_line(const StringName &p_member) const { -#ifdef TOOLS_ENABLED - if (_member_lines.has(p_member)) { - return _member_lines[p_member]; - } -#endif - return -1; -} - -const Vector<Multiplayer::RPCConfig> PluginScript::get_rpc_methods() const { - return _rpc_methods; -} - -PluginScript::PluginScript() : - _script_list(this) { -} - -void PluginScript::init(PluginScriptLanguage *language) { - _desc = &language->_desc.script_desc; - _language = language; - -#ifdef DEBUG_ENABLED - _language->lock(); - _language->_script_list.add(&_script_list); - _language->unlock(); -#endif -} - -PluginScript::~PluginScript() { - if (_desc && _data) { - _desc->finish(_data); - } - -#ifdef DEBUG_ENABLED - if (_language) { - _language->lock(); - _language->_script_list.remove(&_script_list); - _language->unlock(); - } -#endif -} diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h deleted file mode 100644 index 1a12a130d1..0000000000 --- a/modules/gdnative/pluginscript/pluginscript_script.h +++ /dev/null @@ -1,146 +0,0 @@ -/*************************************************************************/ -/* pluginscript_script.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 PLUGINSCRIPT_SCRIPT_H -#define PLUGINSCRIPT_SCRIPT_H - -// Godot imports - -#include "core/doc_data.h" -#include "core/object/script_language.h" -// PluginScript imports -#include "pluginscript_language.h" -#include <pluginscript/godot_pluginscript.h> - -class PluginScript : public Script { - GDCLASS(PluginScript, Script); - - friend class PluginScriptInstance; - friend class PluginScriptLanguage; - -private: - godot_pluginscript_script_data *_data = nullptr; - const godot_pluginscript_script_desc *_desc = nullptr; - PluginScriptLanguage *_language = nullptr; - bool _tool = false; - bool _valid = false; - - Ref<Script> _ref_base_parent; - StringName _native_parent; - SelfList<PluginScript> _script_list; - - Map<StringName, int> _member_lines; - Map<StringName, Variant> _properties_default_values; - Map<StringName, PropertyInfo> _properties_info; - Map<StringName, MethodInfo> _signals_info; - Map<StringName, MethodInfo> _methods_info; - Vector<Multiplayer::RPCConfig> _rpc_methods; - - Set<Object *> _instances; - //exported members - String _source; - String _path; - StringName _name; - String _icon_path; - -protected: - static void _bind_methods(); - - bool inherits_script(const Ref<Script> &p_script) const override; - - PluginScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, Callable::CallError &r_error); - Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - -#ifdef TOOLS_ENABLED - Set<PlaceHolderScriptInstance *> placeholders; - //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); - virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; -#endif -public: - String get_script_class_name() const { - return _name; - } - - String get_script_class_icon_path() const { - return _icon_path; - } - - virtual bool can_instantiate() const override; - - virtual Ref<Script> get_base_script() const override; //for script inheritance - - virtual StringName get_instance_base_type() const override; // this may not work in all scripts, will return empty if so - virtual ScriptInstance *instance_create(Object *p_this) override; - virtual bool instance_has(const Object *p_this) const override; - - virtual bool has_source_code() const override; - virtual String get_source_code() const override; - virtual void set_source_code(const String &p_code) override; - virtual Error reload(bool p_keep_state = false) override; - // TODO: load_source_code only allow utf-8 file, should handle bytecode as well ? - virtual Error load_source_code(const String &p_path); - -#ifdef TOOLS_ENABLED - virtual const Vector<DocData::ClassDoc> &get_documentation() const override { - static Vector<DocData::ClassDoc> docs; - return docs; - } -#endif // TOOLS_ENABLED - - virtual bool has_method(const StringName &p_method) const override; - virtual MethodInfo get_method_info(const StringName &p_method) const override; - - bool has_property(const StringName &p_method) const; - PropertyInfo get_property_info(const StringName &p_property) const; - - bool is_tool() const override { return _tool; } - bool is_valid() const override { return true; } - - virtual ScriptLanguage *get_language() const override; - - virtual bool has_script_signal(const StringName &p_signal) const override; - virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override; - - virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const override; - - virtual void update_exports() override; - virtual void get_script_method_list(List<MethodInfo> *r_methods) const override; - virtual void get_script_property_list(List<PropertyInfo> *r_properties) const override; - - virtual int get_member_line(const StringName &p_member) const override; - - virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; - - PluginScript(); - void init(PluginScriptLanguage *language); - virtual ~PluginScript(); -}; - -#endif // PLUGINSCRIPT_SCRIPT_H diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp deleted file mode 100644 index c4fbff69f0..0000000000 --- a/modules/gdnative/pluginscript/register_types.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "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/os.h" -#include "scene/main/scene_tree.h" - -#include "pluginscript_language.h" -#include "pluginscript_script.h" -#include <pluginscript/godot_pluginscript.h> - -static List<PluginScriptLanguage *> pluginscript_languages; - -static Error _check_language_desc(const godot_pluginscript_language_desc *desc) { - ERR_FAIL_COND_V(!desc->name, ERR_BUG); - ERR_FAIL_COND_V(!desc->type, ERR_BUG); - ERR_FAIL_COND_V(!desc->extension, ERR_BUG); - ERR_FAIL_COND_V(!desc->recognized_extensions || !desc->recognized_extensions[0], ERR_BUG); - ERR_FAIL_COND_V(!desc->init, ERR_BUG); - ERR_FAIL_COND_V(!desc->finish, ERR_BUG); - - // desc->reserved_words is not mandatory - // desc->comment_delimiters is not mandatory - // desc->string_delimiters is not mandatory - - // desc->get_template_source_code is not mandatory - // desc->validate is not mandatory - - // desc->get_template_source_code is not mandatory - // desc->validate is not mandatory - // desc->find_function is not mandatory - // desc->make_function is not mandatory - // desc->complete_code is not mandatory - // desc->auto_indent_code is not mandatory - ERR_FAIL_COND_V(!desc->add_global_constant, ERR_BUG); - // desc->debug_get_error is not mandatory - // desc->debug_get_stack_level_count is not mandatory - // desc->debug_get_stack_level_line is not mandatory - // desc->debug_get_stack_level_function is not mandatory - // desc->debug_get_stack_level_source is not mandatory - // desc->debug_get_stack_level_locals is not mandatory - // desc->debug_get_stack_level_members is not mandatory - // desc->debug_get_globals is not mandatory - // desc->debug_parse_stack_level_expression is not mandatory - // desc->profiling_start is not mandatory - // desc->profiling_stop is not mandatory - // desc->profiling_get_accumulated_data is not mandatory - // desc->profiling_get_frame_data is not mandatory - // desc->profiling_frame is not mandatory - - ERR_FAIL_COND_V(!desc->script_desc.init, ERR_BUG); - ERR_FAIL_COND_V(!desc->script_desc.finish, ERR_BUG); - - ERR_FAIL_COND_V(!desc->script_desc.instance_desc.init, ERR_BUG); - ERR_FAIL_COND_V(!desc->script_desc.instance_desc.finish, ERR_BUG); - ERR_FAIL_COND_V(!desc->script_desc.instance_desc.set_prop, ERR_BUG); - ERR_FAIL_COND_V(!desc->script_desc.instance_desc.get_prop, ERR_BUG); - ERR_FAIL_COND_V(!desc->script_desc.instance_desc.call_method, ERR_BUG); - ERR_FAIL_COND_V(!desc->script_desc.instance_desc.notification, ERR_BUG); - // desc->script_desc.instance_desc.refcount_incremented is not mandatory - // desc->script_desc.instance_desc.refcount_decremented is not mandatory - return OK; -} - -void GDAPI godot_pluginscript_register_language(const godot_pluginscript_language_desc *language_desc) { - Error ret = _check_language_desc(language_desc); - if (ret) { - ERR_FAIL(); - } - PluginScriptLanguage *language = memnew(PluginScriptLanguage(language_desc)); - ScriptServer::register_language(language); - ResourceLoader::add_resource_format_loader(language->get_resource_loader()); - ResourceSaver::add_resource_format_saver(language->get_resource_saver()); - pluginscript_languages.push_back(language); -} - -void register_pluginscript_types() { - GDREGISTER_CLASS(PluginScript); -} - -void unregister_pluginscript_types() { - for (List<PluginScriptLanguage *>::Element *e = pluginscript_languages.front(); e; e = e->next()) { - PluginScriptLanguage *language = e->get(); - ScriptServer::unregister_language(language); - ResourceLoader::remove_resource_format_loader(language->get_resource_loader()); - ResourceSaver::remove_resource_format_saver(language->get_resource_saver()); - memdelete(language); - } -} diff --git a/modules/gdnative/pluginscript/register_types.h b/modules/gdnative/pluginscript/register_types.h deleted file mode 100644 index 2118f668e9..0000000000 --- a/modules/gdnative/pluginscript/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef PLUGINSCRIPT_REGISTER_TYPES_H -#define PLUGINSCRIPT_REGISTER_TYPES_H - -void register_pluginscript_types(); -void unregister_pluginscript_types(); - -#endif // PLUGINSCRIPT_REGISTER_TYPES_H diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp deleted file mode 100644 index a4ab5663ef..0000000000 --- a/modules/gdnative/register_types.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "gdnative/gdnative.h" - -#include "gdnative.h" - -#include "nativescript/register_types.h" -#include "pluginscript/register_types.h" -#include "videodecoder/register_types.h" - -#include "core/config/engine.h" -#include "core/config/project_settings.h" -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/os/os.h" - -#ifdef TOOLS_ENABLED -#include "editor/editor_export.h" -#include "editor/editor_node.h" -#include "gdnative_library_editor_plugin.h" -#include "gdnative_library_singleton_editor.h" - -class GDNativeExportPlugin : public EditorExportPlugin { -protected: - virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features); -}; - -struct LibrarySymbol { - const char *name; - bool is_required; -}; - -void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { - if (p_type != "GDNativeLibrary") { - return; - } - - Ref<GDNativeLibrary> lib = ResourceLoader::load(p_path); - - if (lib.is_null()) { - return; - } - - Ref<ConfigFile> config = lib->get_config_file(); - - { - List<String> entry_keys; - config->get_section_keys("entry", &entry_keys); - - for (const String &key : entry_keys) { - Vector<String> tags = key.split("."); - - bool skip = false; - for (int i = 0; i < tags.size(); i++) { - bool has_feature = p_features.has(tags[i]); - - if (!has_feature) { - skip = true; - break; - } - } - - if (skip) { - continue; - } - - String entry_lib_path = config->get_value("entry", key); - if (!entry_lib_path.begins_with("res://")) { - print_line("Skipping export of out-of-project library " + entry_lib_path); - continue; - } - - add_shared_object(entry_lib_path, tags); - } - } - - { - List<String> dependency_keys; - config->get_section_keys("dependencies", &dependency_keys); - - for (const String &key : dependency_keys) { - Vector<String> tags = key.split("."); - - bool skip = false; - for (int i = 0; i < tags.size(); i++) { - bool has_feature = p_features.has(tags[i]); - - if (!has_feature) { - skip = true; - break; - } - } - - if (skip) { - continue; - } - - Vector<String> dependency_paths = config->get_value("dependencies", key); - for (int i = 0; i < dependency_paths.size(); i++) { - if (!dependency_paths[i].begins_with("res://")) { - print_line("Skipping export of out-of-project library " + dependency_paths[i]); - continue; - } - add_shared_object(dependency_paths[i], tags); - } - } - } - - // Add symbols for statically linked libraries on iOS - if (p_features.has("iOS")) { - bool should_fake_dynamic = false; - - List<String> entry_keys; - config->get_section_keys("entry", &entry_keys); - - for (const String &key : entry_keys) { - Vector<String> tags = key.split("."); - - bool skip = false; - for (int i = 0; i < tags.size(); i++) { - bool has_feature = p_features.has(tags[i]); - - if (!has_feature) { - skip = true; - break; - } - } - - if (skip) { - continue; - } - - String entry_lib_path = config->get_value("entry", key); - if (entry_lib_path.begins_with("res://") && entry_lib_path.ends_with(".a")) { - // If we find static library that was used for export - // we should add a fake lookup table. - // In case of dynamic library being used, - // this symbols will not cause any issues with library loading. - should_fake_dynamic = true; - break; - } - } - - if (should_fake_dynamic) { - // Register symbols in the "fake" dynamic lookup table, because dlsym does not work well on iOS. - LibrarySymbol expected_symbols[] = { - { "gdnative_init", true }, - { "gdnative_terminate", false }, - { "nativescript_init", false }, - { "nativescript_frame", false }, - { "nativescript_thread_enter", false }, - { "nativescript_thread_exit", false }, - { "gdnative_singleton", false } - }; - String declare_pattern = "extern \"C\" void $name(void)$weak;\n"; - String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n" - "extern void add_ios_init_callback(void (*cb)());\n"; - String linker_flags = ""; - for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) { - String full_name = lib->get_symbol_prefix() + expected_symbols[i].name; - String code = declare_pattern.replace("$name", full_name); - code = code.replace("$weak", expected_symbols[i].is_required ? "" : " __attribute__((weak))"); - additional_code += code; - - if (!expected_symbols[i].is_required) { - if (linker_flags.length() > 0) { - linker_flags += " "; - } - linker_flags += "-Wl,-U,_" + full_name; - } - } - - additional_code += String("void $prefixinit() {\n").replace("$prefix", lib->get_symbol_prefix()); - String register_pattern = " if (&$name) register_dynamic_symbol((char *)\"$name\", (void *)$name);\n"; - for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) { - String full_name = lib->get_symbol_prefix() + expected_symbols[i].name; - additional_code += register_pattern.replace("$name", full_name); - } - additional_code += "}\n"; - additional_code += String("struct $prefixstruct {$prefixstruct() {add_ios_init_callback($prefixinit);}};\n").replace("$prefix", lib->get_symbol_prefix()); - additional_code += String("$prefixstruct $prefixstruct_instance;\n").replace("$prefix", lib->get_symbol_prefix()); - - add_ios_cpp_code(additional_code); - add_ios_linker_flags(linker_flags); - } - } -} - -static void editor_init_callback() { - GDNativeLibrarySingletonEditor *library_editor = memnew(GDNativeLibrarySingletonEditor); - library_editor->set_name(TTR("GDNative")); - ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(library_editor); - - Ref<GDNativeExportPlugin> export_plugin; - export_plugin.instantiate(); - - EditorExport::get_singleton()->add_export_plugin(export_plugin); - - EditorNode::get_singleton()->add_editor_plugin(memnew(GDNativeLibraryEditorPlugin(EditorNode::get_singleton()))); -} - -#endif - -static godot_variant cb_standard_varcall(void *p_procedure_handle, godot_array *p_args) { - godot_gdnative_procedure_fn proc; - proc = (godot_gdnative_procedure_fn)p_procedure_handle; - - return proc(p_args); -} - -GDNativeCallRegistry *GDNativeCallRegistry::singleton; - -Vector<Ref<GDNative>> singleton_gdnatives; - -Ref<GDNativeLibraryResourceLoader> resource_loader_gdnlib; -Ref<GDNativeLibraryResourceSaver> resource_saver_gdnlib; - -void register_gdnative_types() { -#ifdef TOOLS_ENABLED - - EditorNode::add_init_callback(editor_init_callback); -#endif - - GDREGISTER_CLASS(GDNativeLibrary); - GDREGISTER_CLASS(GDNative); - - resource_loader_gdnlib.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_gdnlib); - - resource_saver_gdnlib.instantiate(); - ResourceSaver::add_resource_format_saver(resource_saver_gdnlib); - - GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry); - - GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall); - - register_nativescript_types(); - register_pluginscript_types(); - register_videodecoder_types(); - - // run singletons - - Array singletons = Array(); - if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) { - singletons = ProjectSettings::get_singleton()->get("gdnative/singletons"); - } - Array excluded = Array(); - if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons_disabled")) { - excluded = ProjectSettings::get_singleton()->get("gdnative/singletons_disabled"); - } - - for (int i = 0; i < singletons.size(); i++) { - String path = singletons[i]; - - if (excluded.has(path)) { - continue; - } - - Ref<GDNativeLibrary> lib = ResourceLoader::load(path); - Ref<GDNative> singleton; - singleton.instantiate(); - singleton->set_library(lib); - - if (!singleton->initialize()) { - // Can't initialize. Don't make a native_call then - continue; - } - - void *proc_ptr; - Error err = singleton->get_symbol( - lib->get_symbol_prefix() + "gdnative_singleton", - proc_ptr); - - if (err != OK) { - ERR_PRINT("No " + lib->get_symbol_prefix() + "gdnative_singleton in \"" + singleton->get_library()->get_current_library_path() + "\" found"); - } else { - singleton_gdnatives.push_back(singleton); - ((void (*)())proc_ptr)(); - } - } -} - -void unregister_gdnative_types() { - for (int i = 0; i < singleton_gdnatives.size(); i++) { - if (singleton_gdnatives[i].is_null()) { - continue; - } - - if (!singleton_gdnatives[i]->is_initialized()) { - continue; - } - - singleton_gdnatives.write[i]->terminate(); - } - singleton_gdnatives.clear(); - - unregister_videodecoder_types(); - unregister_pluginscript_types(); - unregister_nativescript_types(); - - memdelete(GDNativeCallRegistry::singleton); - - ResourceLoader::remove_resource_format_loader(resource_loader_gdnlib); - resource_loader_gdnlib.unref(); - - ResourceSaver::remove_resource_format_saver(resource_saver_gdnlib); - resource_saver_gdnlib.unref(); - - // This is for printing out the sizes of the core types - - /* - print_line(String("array:\t") + itos(sizeof(Array))); - print_line(String("basis:\t") + itos(sizeof(Basis))); - print_line(String("color:\t") + itos(sizeof(Color))); - print_line(String("dict:\t" ) + itos(sizeof(Dictionary))); - print_line(String("node_path:\t") + itos(sizeof(NodePath))); - print_line(String("plane:\t") + itos(sizeof(Plane))); - print_line(String("poolarray:\t") + itos(sizeof(PackedByteArray))); - print_line(String("quat:\t") + itos(sizeof(Quat))); - print_line(String("rect2:\t") + itos(sizeof(Rect2))); - 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(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))); - print_line(String("vector3:\t") + itos(sizeof(Vector3))); - */ -} diff --git a/modules/gdnative/register_types.h b/modules/gdnative/register_types.h deleted file mode 100644 index 662c638442..0000000000 --- a/modules/gdnative/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GDNATIVE_REGISTER_TYPES_H -#define GDNATIVE_REGISTER_TYPES_H - -void register_gdnative_types(); -void unregister_gdnative_types(); - -#endif // GDNATIVE_REGISTER_TYPES_H diff --git a/modules/gdnative/tests/test_variant.h b/modules/gdnative/tests/test_variant.h deleted file mode 100644 index c506882283..0000000000 --- a/modules/gdnative/tests/test_variant.h +++ /dev/null @@ -1,205 +0,0 @@ -/*************************************************************************/ -/* test_variant.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 TEST_GDNATIVE_VARIANT_H -#define TEST_GDNATIVE_VARIANT_H - -#include <gdnative/gdnative.h> -#include <gdnative/variant.h> - -#include "tests/test_macros.h" - -namespace TestGDNativeVariant { - -TEST_CASE("[GDNative Variant] New Variant with copy") { - godot_variant src; - godot_variant_new_int(&src, 42); - - godot_variant copy; - godot_variant_new_copy(©, &src); - - CHECK(godot_variant_as_int(©) == 42); - CHECK(godot_variant_get_type(©) == GODOT_VARIANT_TYPE_INT); - - godot_variant_destroy(&src); - godot_variant_destroy(©); -} - -TEST_CASE("[GDNative Variant] New Variant with Nil") { - godot_variant val; - godot_variant_new_nil(&val); - - CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_NIL); - - godot_variant_destroy(&val); -} - -TEST_CASE("[GDNative Variant] New Variant with bool") { - godot_variant val; - godot_variant_new_bool(&val, true); - - CHECK(godot_variant_as_bool(&val)); - CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_BOOL); - - godot_variant_destroy(&val); -} - -TEST_CASE("[GDNative Variant] New Variant with float") { - godot_variant val; - godot_variant_new_float(&val, 4.2); - - CHECK(godot_variant_as_float(&val) == 4.2); - CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_FLOAT); - - godot_variant_destroy(&val); -} - -TEST_CASE("[GDNative Variant] New Variant with String") { - String str = "something"; - - godot_variant val; - godot_variant_new_string(&val, (godot_string *)&str); - godot_string gd_str = godot_variant_as_string(&val); - String *result = (String *)&gd_str; - - CHECK(*result == String("something")); - CHECK(godot_variant_get_type(&val) == GODOT_VARIANT_TYPE_STRING); - - godot_variant_destroy(&val); - godot_string_destroy(&gd_str); -} - -TEST_CASE("[GDNative Variant] Variant call") { - String str("something"); - godot_variant self; - godot_variant_new_string(&self, (godot_string *)&str); - - godot_variant ret; - - godot_string_name method; - godot_string_name_new_with_latin1_chars(&method, "is_valid_identifier"); - - godot_variant_call_error 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)); - - godot_variant_destroy(&ret); - godot_variant_destroy(&self); - godot_string_name_destroy(&method); -} - -TEST_CASE("[GDNative Variant] Variant evaluate") { - godot_variant one; - godot_variant_new_int(&one, 1); - godot_variant two; - godot_variant_new_int(&two, 2); - - godot_variant three; - godot_variant_new_nil(&three); - bool valid = false; - - godot_variant_evaluate(GODOT_VARIANT_OP_ADD, &one, &two, &three, &valid); - - CHECK(godot_variant_get_type(&three) == GODOT_VARIANT_TYPE_INT); - CHECK(godot_variant_as_int(&three) == 3); - CHECK(valid); - - godot_variant_destroy(&one); - godot_variant_destroy(&two); - godot_variant_destroy(&three); -} - -TEST_CASE("[GDNative Variant] Variant set/get named") { - godot_string_name x; - godot_string_name_new_with_latin1_chars(&x, "x"); - - Vector2 vec(0, 0); - godot_variant self; - godot_variant_new_vector2(&self, (godot_vector2 *)&vec); - - godot_variant set; - godot_variant_new_float(&set, 1.0); - - bool set_valid = false; - godot_variant_set_named(&self, &x, &set, &set_valid); - - bool get_valid = false; - godot_variant get = godot_variant_get_named(&self, &x, &get_valid); - - CHECK(get_valid); - CHECK(set_valid); - CHECK(godot_variant_get_type(&get) == GODOT_VARIANT_TYPE_FLOAT); - CHECK(godot_variant_as_float(&get) == 1.0); - - godot_string_name_destroy(&x); - godot_variant_destroy(&self); - godot_variant_destroy(&set); - godot_variant_destroy(&get); -} - -TEST_CASE("[GDNative Variant] Get utility function argument name") { - godot_string_name function; - godot_string_name_new_with_latin1_chars(&function, "pow"); - - godot_string arg_name = godot_variant_get_utility_function_argument_name(&function, 0); - - String *arg_name_str = (String *)&arg_name; - - CHECK(*arg_name_str == "base"); - - godot_string_destroy(&arg_name); - godot_string_name_destroy(&function); -} - -TEST_CASE("[GDNative Variant] Get utility function list") { - int count = godot_variant_get_utility_function_count(); - - godot_string_name *c_list = (godot_string_name *)godot_alloc(count * sizeof(godot_string_name)); - godot_variant_get_utility_function_list(c_list); - - List<StringName> cpp_list; - Variant::get_utility_function_list(&cpp_list); - - godot_string_name *cur = c_list; - - for (const StringName &E : cpp_list) { - const StringName &cpp_name = E; - StringName *c_name = (StringName *)cur++; - - CHECK(*c_name == cpp_name); - } - - godot_free(c_list); -} -} // namespace TestGDNativeVariant - -#endif // TEST_GDNATIVE_VARIANT_H diff --git a/modules/gdnative/videodecoder/SCsub b/modules/gdnative/videodecoder/SCsub deleted file mode 100644 index 5948b9a3dd..0000000000 --- a/modules/gdnative/videodecoder/SCsub +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_vsdecoder_gdnative = env_modules.Clone() - -env_vsdecoder_gdnative.Prepend(CPPPATH=["#modules/gdnative/include/"]) -env_vsdecoder_gdnative.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/gdnative/videodecoder/register_types.cpp b/modules/gdnative/videodecoder/register_types.cpp deleted file mode 100644 index 54a577a2b6..0000000000 --- a/modules/gdnative/videodecoder/register_types.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "core/object/class_db.h" -#include "video_stream_gdnative.h" - -static Ref<ResourceFormatLoaderVideoStreamGDNative> resource_loader_vsgdnative; - -void register_videodecoder_types() { - resource_loader_vsgdnative.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_vsgdnative, true); - - GDREGISTER_CLASS(VideoStreamGDNative); -} - -void unregister_videodecoder_types() { - ResourceLoader::remove_resource_format_loader(resource_loader_vsgdnative); - resource_loader_vsgdnative.unref(); -} diff --git a/modules/gdnative/videodecoder/register_types.h b/modules/gdnative/videodecoder/register_types.h deleted file mode 100644 index 809225c925..0000000000 --- a/modules/gdnative/videodecoder/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef VIDEODECODER_REGISTER_TYPES_H -#define VIDEODECODER_REGISTER_TYPES_H - -void register_videodecoder_types(); -void unregister_videodecoder_types(); - -#endif // VIDEODECODER_REGISTER_TYPES_H diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp deleted file mode 100644 index e249363016..0000000000 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/*************************************************************************/ -/* video_stream_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "video_stream_gdnative.h" - -#include "core/config/project_settings.h" -#include "servers/audio_server.h" - -VideoDecoderServer *VideoDecoderServer::instance = nullptr; - -static VideoDecoderServer decoder_server; - -const int AUX_BUFFER_SIZE = 1024; // Buffer 1024 samples. - -// NOTE: Callbacks for the GDNative libraries. -extern "C" { -godot_int GDAPI godot_videodecoder_file_read(void *ptr, uint8_t *buf, int buf_size) { - // ptr is a FileAccess - FileAccess *file = reinterpret_cast<FileAccess *>(ptr); - - // if file exists - if (file) { - int64_t bytes_read = file->get_buffer(buf, buf_size); - return bytes_read; - } - return -1; -} - -int64_t GDAPI godot_videodecoder_file_seek(void *ptr, int64_t pos, int whence) { - // file - FileAccess *file = reinterpret_cast<FileAccess *>(ptr); - - if (file) { - int64_t len = file->get_length(); - switch (whence) { - case SEEK_SET: { - if (pos > len) { - return -1; - } - file->seek(pos); - return file->get_position(); - } break; - case SEEK_CUR: { - // Just in case it doesn't exist - if (pos < 0 && -pos > (int64_t)file->get_position()) { - return -1; - } - file->seek(file->get_position() + pos); - return file->get_position(); - } break; - case SEEK_END: { - // Just in case something goes wrong - if (-pos > len) { - return -1; - } - file->seek_end(pos); - return file->get_position(); - } break; - default: { - // Only 4 possible options, hence default = AVSEEK_SIZE - // Asks to return the length of file - return len; - } break; - } - } - // In case nothing works out. - return -1; -} - -void GDAPI godot_videodecoder_register_decoder(const godot_videodecoder_interface_gdnative *p_interface) { - decoder_server.register_decoder_interface(p_interface); -} -} - -// VideoStreamPlaybackGDNative starts here. - -bool VideoStreamPlaybackGDNative::open_file(const String &p_file) { - ERR_FAIL_COND_V(interface == nullptr, false); - file = FileAccess::open(p_file, FileAccess::READ); - bool file_opened = interface->open_file(data_struct, file); - - if (file_opened) { - num_channels = interface->get_channels(data_struct); - mix_rate = interface->get_mix_rate(data_struct); - - godot_vector2 vec = interface->get_texture_size(data_struct); - texture_size = *(Vector2 *)&vec; - // Only do memset if num_channels > 0 otherwise it will crash. - if (num_channels > 0) { - pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float)); - memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float)); - } - - pcm_write_idx = -1; - samples_decoded = 0; - - Ref<Image> img; - img.instantiate(); - img->create((int)texture_size.width, false, (int)texture_size.height, Image::FORMAT_RGBA8); - - texture->create_from_image(img); - } - - return file_opened; -} - -void VideoStreamPlaybackGDNative::update(float p_delta) { - if (!playing || paused) { - return; - } - if (!file) { - return; - } - time += p_delta; - ERR_FAIL_COND(interface == nullptr); - interface->update(data_struct, p_delta); - - // Don't mix if there's no audio (num_channels == 0). - if (mix_callback && num_channels > 0) { - if (pcm_write_idx >= 0) { - // Previous remains - int mixed = mix_callback(mix_udata, pcm + pcm_write_idx * num_channels, samples_decoded); - if (mixed == samples_decoded) { - pcm_write_idx = -1; - } else { - samples_decoded -= mixed; - pcm_write_idx += mixed; - } - } - if (pcm_write_idx < 0) { - samples_decoded = interface->get_audioframe(data_struct, pcm, AUX_BUFFER_SIZE); - pcm_write_idx = mix_callback(mix_udata, pcm, samples_decoded); - if (pcm_write_idx == samples_decoded) { - pcm_write_idx = -1; - } else { - samples_decoded -= pcm_write_idx; - } - } - } - - if (seek_backward) { - update_texture(); - seek_backward = false; - } - - while (interface->get_playback_position(data_struct) < time && playing) { - update_texture(); - } -} - -void VideoStreamPlaybackGDNative::update_texture() { - PackedByteArray *pba = (PackedByteArray *)interface->get_videoframe(data_struct); - - if (pba == nullptr) { - playing = false; - return; - } - - Ref<Image> img = memnew(Image(texture_size.width, texture_size.height, 0, Image::FORMAT_RGBA8, *pba)); - - texture->update(img); -} - -// ctor and dtor - -VideoStreamPlaybackGDNative::VideoStreamPlaybackGDNative() : - texture(Ref<ImageTexture>(memnew(ImageTexture))) {} - -VideoStreamPlaybackGDNative::~VideoStreamPlaybackGDNative() { - cleanup(); -} - -void VideoStreamPlaybackGDNative::cleanup() { - if (data_struct) { - interface->destructor(data_struct); - } - if (pcm) { - memfree(pcm); - } - if (file) { - file->close(); - memdelete(file); - file = nullptr; - } - pcm = nullptr; - time = 0; - num_channels = -1; - interface = nullptr; - data_struct = nullptr; -} - -void VideoStreamPlaybackGDNative::set_interface(const godot_videodecoder_interface_gdnative *p_interface) { - ERR_FAIL_COND(p_interface == nullptr); - if (interface != nullptr) { - cleanup(); - } - interface = p_interface; - data_struct = interface->constructor((godot_object *)this); -} - -// controls - -bool VideoStreamPlaybackGDNative::is_playing() const { - return playing; -} - -bool VideoStreamPlaybackGDNative::is_paused() const { - return paused; -} - -void VideoStreamPlaybackGDNative::play() { - stop(); - - playing = true; - - delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms"); - delay_compensation /= 1000.0; -} - -void VideoStreamPlaybackGDNative::stop() { - if (playing) { - seek(0); - } - playing = false; -} - -void VideoStreamPlaybackGDNative::seek(float p_time) { - ERR_FAIL_COND(interface == nullptr); - interface->seek(data_struct, p_time); - if (p_time < time) { - seek_backward = true; - } - time = p_time; - // reset audio buffers - memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float)); - pcm_write_idx = -1; - samples_decoded = 0; -} - -void VideoStreamPlaybackGDNative::set_paused(bool p_paused) { - paused = p_paused; -} - -Ref<Texture2D> VideoStreamPlaybackGDNative::get_texture() const { - return texture; -} - -float VideoStreamPlaybackGDNative::get_length() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_length(data_struct); -} - -float VideoStreamPlaybackGDNative::get_playback_position() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_playback_position(data_struct); -} - -bool VideoStreamPlaybackGDNative::has_loop() const { - // TODO: Implement looping? - return false; -} - -void VideoStreamPlaybackGDNative::set_loop(bool p_enable) { - // Do nothing -} - -void VideoStreamPlaybackGDNative::set_audio_track(int p_idx) { - ERR_FAIL_COND(interface == nullptr); - interface->set_audio_track(data_struct, p_idx); -} - -void VideoStreamPlaybackGDNative::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) { - mix_udata = p_userdata; - mix_callback = p_callback; -} - -int VideoStreamPlaybackGDNative::get_channels() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - - return (num_channels > 0) ? num_channels : 0; -} - -int VideoStreamPlaybackGDNative::get_mix_rate() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - - return mix_rate; -} - -/* --- NOTE VideoStreamGDNative starts here. ----- */ - -Ref<VideoStreamPlayback> VideoStreamGDNative::instance_playback() { - Ref<VideoStreamPlaybackGDNative> pb = memnew(VideoStreamPlaybackGDNative); - VideoDecoderGDNative *decoder = decoder_server.get_decoder(file.get_extension().to_lower()); - if (decoder == nullptr) { - return nullptr; - } - pb->set_interface(decoder->interface); - pb->set_audio_track(audio_track); - if (pb->open_file(file)) { - return pb; - } - return nullptr; -} - -void VideoStreamGDNative::set_file(const String &p_file) { - file = p_file; -} - -String VideoStreamGDNative::get_file() { - return file; -} - -void VideoStreamGDNative::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamGDNative::set_file); - ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamGDNative::get_file); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file"); -} - -void VideoStreamGDNative::set_audio_track(int p_track) { - audio_track = p_track; -} - -/* --- NOTE ResourceFormatLoaderVideoStreamGDNative starts here. ----- */ - -RES ResourceFormatLoaderVideoStreamGDNative::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { - if (r_error) { - *r_error = ERR_CANT_OPEN; - } - return RES(); - } - memdelete(f); - VideoStreamGDNative *stream = memnew(VideoStreamGDNative); - stream->set_file(p_path); - Ref<VideoStreamGDNative> ogv_stream = Ref<VideoStreamGDNative>(stream); - if (r_error) { - *r_error = OK; - } - return ogv_stream; -} - -void ResourceFormatLoaderVideoStreamGDNative::get_recognized_extensions(List<String> *p_extensions) const { - Map<String, int>::Element *el = VideoDecoderServer::get_instance()->get_extensions().front(); - while (el) { - p_extensions->push_back(el->key()); - el = el->next(); - } -} - -bool ResourceFormatLoaderVideoStreamGDNative::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "VideoStream"); -} - -String ResourceFormatLoaderVideoStreamGDNative::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (VideoDecoderServer::get_instance()->get_extensions().has(el)) { - return "VideoStreamGDNative"; - } - return ""; -} diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h deleted file mode 100644 index c605dbb433..0000000000 --- a/modules/gdnative/videodecoder/video_stream_gdnative.h +++ /dev/null @@ -1,205 +0,0 @@ -/*************************************************************************/ -/* video_stream_gdnative.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef VIDEO_STREAM_GDNATIVE_H -#define VIDEO_STREAM_GDNATIVE_H - -#include "../gdnative.h" -#include "core/io/file_access.h" -#include "scene/resources/texture.h" -#include "scene/resources/video_stream.h" - -struct VideoDecoderGDNative { - const godot_videodecoder_interface_gdnative *interface = nullptr; - String plugin_name = "none"; - Vector<String> supported_extensions; - - VideoDecoderGDNative() {} - - VideoDecoderGDNative(const godot_videodecoder_interface_gdnative *p_interface) : - interface(p_interface), - plugin_name(p_interface->get_plugin_name()) { - _get_supported_extensions(); - } - -private: - void _get_supported_extensions() { - supported_extensions.clear(); - int num_ext; - const char **supported_ext = interface->get_supported_extensions(&num_ext); - for (int i = 0; i < num_ext; i++) { - supported_extensions.push_back(supported_ext[i]); - } - } -}; - -class VideoDecoderServer { -private: - Vector<VideoDecoderGDNative *> decoders; - Map<String, int> extensions; - - static VideoDecoderServer *instance; - -public: - static VideoDecoderServer *get_instance() { - return instance; - } - - const Map<String, int> &get_extensions() { - return extensions; - } - - void register_decoder_interface(const godot_videodecoder_interface_gdnative *p_interface) { - VideoDecoderGDNative *decoder = memnew(VideoDecoderGDNative(p_interface)); - int index = decoders.size(); - for (int i = 0; i < decoder->supported_extensions.size(); i++) { - extensions[decoder->supported_extensions[i]] = index; - } - decoders.push_back(decoder); - } - - VideoDecoderGDNative *get_decoder(const String &extension) { - if (extensions.size() == 0 || !extensions.has(extension)) { - return nullptr; - } - return decoders[extensions[extension]]; - } - - VideoDecoderServer() { - instance = this; - } - - ~VideoDecoderServer() { - for (int i = 0; i < decoders.size(); i++) { - memdelete(decoders[i]); - } - decoders.clear(); - instance = nullptr; - } -}; - -class VideoStreamPlaybackGDNative : public VideoStreamPlayback { - GDCLASS(VideoStreamPlaybackGDNative, VideoStreamPlayback); - - Ref<ImageTexture> texture; - bool playing = false; - bool paused = false; - - Vector2 texture_size; - - void *mix_udata = nullptr; - AudioMixCallback mix_callback = nullptr; - - int num_channels = -1; - float time = 0.0; - bool seek_backward = false; - int mix_rate = 0; - double delay_compensation = 0; - - float *pcm = nullptr; - int pcm_write_idx = 0; - int samples_decoded = 0; - - void cleanup(); - void update_texture(); - -protected: - String file_name; - - FileAccess *file = nullptr; - - const godot_videodecoder_interface_gdnative *interface = nullptr; - void *data_struct = nullptr; - -public: - VideoStreamPlaybackGDNative(); - ~VideoStreamPlaybackGDNative(); - - void set_interface(const godot_videodecoder_interface_gdnative *p_interface); - - bool open_file(const String &p_file); - - virtual void stop() override; - virtual void play() override; - - virtual bool is_playing() const override; - - virtual void set_paused(bool p_paused) override; - virtual bool is_paused() const override; - - virtual void set_loop(bool p_enable) override; - virtual bool has_loop() const override; - - virtual float get_length() const override; - - virtual float get_playback_position() const override; - virtual void seek(float p_time) override; - - virtual void set_audio_track(int p_idx) override; - - //virtual int mix(int16_t* p_buffer,int p_frames)=0; - - virtual Ref<Texture2D> get_texture() const override; - virtual void update(float p_delta) override; - - virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) override; - virtual int get_channels() const override; - virtual int get_mix_rate() const override; -}; - -class VideoStreamGDNative : public VideoStream { - GDCLASS(VideoStreamGDNative, VideoStream); - - String file; - int audio_track = 0; - -protected: - static void - _bind_methods(); - -public: - void set_file(const String &p_file); - String get_file(); - - virtual void set_audio_track(int p_track) override; - virtual Ref<VideoStreamPlayback> instance_playback() override; - - VideoStreamGDNative() {} -}; - -class ResourceFormatLoaderVideoStreamGDNative : public ResourceFormatLoader { -public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; -}; - -#endif diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index 5c8cbdf869..2f507db548 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -10,6 +10,8 @@ env_gdscript.add_source_files(env.modules_sources, "*.cpp") if env["tools"]: env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp") + SConscript("editor/script_templates/SCsub") + # Those two modules are required for the language server protocol if env["module_jsonrpc_enabled"] and env["module_websocket_enabled"]: env_gdscript.add_source_files(env.modules_sources, "./language_server/*.cpp") @@ -18,6 +20,7 @@ if env["tools"]: # in regular builds where all modules are enabled. env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"]) + if env["tests"]: env_gdscript.Append(CPPDEFINES=["TESTS_ENABLED"]) env_gdscript.add_source_files(env.modules_sources, "./tests/*.cpp") diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 33f4198ac1..70151c4d21 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="@GDScript" version="4.0"> +<class name="@GDScript" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Built-in GDScript functions. </brief_description> @@ -184,26 +184,24 @@ <method name="range" qualifiers="vararg"> <return type="Array" /> <description> - Returns an array with the given range. Range can be 1 argument [code]N[/code] (0 to [code]N[/code] - 1), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). Returns an empty array if the range isn't valid (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]). - Returns an array with the given range. [code]range()[/code] can have 1 argument N ([code]0[/code] to [code]N - 1[/code]), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). [code]increment[/code] can be negative. If [code]increment[/code] is negative, [code]final - 1[/code] will become [code]final + 1[/code]. Also, the initial value must be greater than the final value for the loop to run. + Returns an array with the given range. [method range] can be called in three ways: + [code]range(n: int)[/code]: Starts from 0, increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The argument [code]n[/code] is [b]exclusive[/b]. + [code]range(b: int, n: int)[/code]: Starts from [code]b[/code], increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively. + [code]range(b: int, n: int, s: int)[/code]: Starts from [code]b[/code], increases/decreases by steps of [code]s[/code], and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively. The argument [code]s[/code] [b]can[/b] be negative, but not [code]0[/code]. If [code]s[/code] is [code]0[/code], an error message is printed. + [method range] converts all arguments to [int] before processing. + [b]Note:[/b] Returns an empty array if no value meets the value constraint (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]). + Examples: [codeblock] - print(range(4)) - print(range(2, 5)) - print(range(0, 6, 2)) - [/codeblock] - Output: - [codeblock] - [0, 1, 2, 3] - [2, 3, 4] - [0, 2, 4] + print(range(4)) # Prints [0, 1, 2, 3] + print(range(2, 5)) # Prints [2, 3, 4] + print(range(0, 6, 2)) # Prints [0, 2, 4] + print(range(4, 1, -1)) # Prints [4, 3, 2] [/codeblock] To iterate over an [Array] backwards, use: [codeblock] var array = [3, 6, 9] - var i := array.size() - 1 - while i >= 0: - print(array[i]) - i -= 1 + for i in range(array.size(), 0, -1): + print(array[i - 1]) [/codeblock] Output: [codeblock] @@ -211,6 +209,17 @@ 6 3 [/codeblock] + To iterate over [float], convert them in the loop. + [codeblock] + for i in range (3, 0, -1): + print(i / 10.0) + [/codeblock] + Output: + [codeblock] + 0.3 + 0.2 + 0.1 + [/codeblock] </description> </method> <method name="str" qualifiers="vararg"> diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 5acb29e748..578e7a34f3 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDScript" inherits="Script" version="4.0"> +<class name="GDScript" inherits="Script" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A script implemented in the GDScript programming language. </brief_description> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 4f711dfd1e..e3f0ddfc35 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,20 +31,9 @@ #include "gdscript_highlighter.h" #include "../gdscript.h" #include "../gdscript_tokenizer.h" +#include "core/config/project_settings.h" #include "editor/editor_settings.h" -static bool _is_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} - -static bool _is_hex_symbol(char32_t c) { - return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); -} - -static bool _is_bin_symbol(char32_t c) { - return (c == '0' || c == '1'); -} - Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) { Dictionary color_map; @@ -60,7 +49,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l bool in_keyword = false; bool in_word = false; bool in_function_name = false; + bool in_lambda = false; bool in_variable_declaration = false; + bool in_signal_declaration = false; bool in_function_args = false; bool in_member_variable = false; bool in_node_path = false; @@ -100,17 +91,20 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l color = font_color; bool is_char = !is_symbol(str[j]); bool is_a_symbol = is_symbol(str[j]); - bool is_number = (str[j] >= '0' && str[j] <= '9'); + bool is_number = is_digit(str[j]); /* color regions */ if (is_a_symbol || in_region != -1) { int from = j; - for (; from < line_length; from++) { - if (str[from] == '\\') { - from++; - continue; + + if (in_region == -1) { + for (; from < line_length; from++) { + if (str[from] == '\\') { + from++; + continue; + } + break; } - break; } if (from != line_length) { @@ -142,6 +136,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l /* check if it's the whole line */ if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) { + if (from + end_key_length > line_length) { + // If it's key length and there is a '\', dont skip to highlight esc chars. + if (str.find("\\", from) >= 0) { + break; + } + } prev_color = color_regions[in_region].color; highlighter_info["color"] = color_regions[c].color; color_map[j] = highlighter_info; @@ -161,13 +161,25 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l /* if we are in one find the end key */ if (in_region != -1) { + Color region_color = color_regions[in_region].color; + if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { + region_color = node_path_color; + } + + prev_color = region_color; + highlighter_info["color"] = region_color; + color_map[j] = highlighter_info; + /* search the line */ int region_end_index = -1; int end_key_length = color_regions[in_region].end_key.length(); const char32_t *end_key = color_regions[in_region].end_key.get_data(); for (; from < line_length; from++) { if (line_length - from < end_key_length) { - break; + // Don't break if '\' to highlight esc chars. + if (str.find("\\", from) < 0) { + break; + } } if (!is_symbol(str[from])) { @@ -175,7 +187,16 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } if (str[from] == '\\') { + Dictionary escape_char_highlighter_info; + escape_char_highlighter_info["color"] = symbol_color; + color_map[from] = escape_char_highlighter_info; + from++; + + Dictionary region_continue_highlighter_info; + prev_color = region_color; + region_continue_highlighter_info["color"] = region_color; + color_map[from + 1] = region_continue_highlighter_info; continue; } @@ -192,10 +213,6 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - prev_color = color_regions[in_region].color; - highlighter_info["color"] = color_regions[in_region].color; - color_map[j] = highlighter_info; - previous_type = REGION; previous_text = ""; previous_column = j; @@ -213,14 +230,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } // allow ABCDEF in hex notation - if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) { + if (is_hex_notation && (is_hex_digit(str[j]) || is_number)) { is_number = true; } else { is_hex_notation = false; } // disallow anything not a 0 or 1 - if (is_bin_notation && (_is_bin_symbol(str[j]))) { + if (is_bin_notation && (is_binary_digit(str[j]))) { is_number = true; } else if (is_bin_notation) { is_bin_notation = false; @@ -242,7 +259,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - if (!in_word && _is_char(str[j]) && !is_number) { + if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !is_number) { in_word = true; } @@ -289,20 +306,36 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } if (!in_function_name && in_word && !in_keyword) { - int k = j; - while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { - k++; - } + if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::SIGNAL)) { + in_signal_declaration = true; + } else { + int k = j; + while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + k++; + } - // check for space between name and bracket - while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { - k++; - } + // check for space between name and bracket + while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { + k++; + } + + if (str[k] == '(') { + in_function_name = true; + } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { + in_variable_declaration = true; + } + + // Check for lambda. + if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { + k = j - 1; + while (k > 0 && (str[k] == '\t' || str[k] == ' ')) { + k--; + } - if (str[k] == '(') { - in_function_name = true; - } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { - in_variable_declaration = true; + if (str[k] == ':') { + in_lambda = true; + } + } } } @@ -348,7 +381,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } in_variable_declaration = false; + in_signal_declaration = false; in_function_name = false; + in_lambda = false; in_member_variable = false; } @@ -376,10 +411,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } else if (in_member_variable) { next_type = MEMBER; color = member_color; + } else if (in_signal_declaration) { + next_type = SIGNAL; + + color = member_color; } else if (in_function_name) { next_type = FUNCTION; - if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { + if (!in_lambda && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { color = function_definition_color; } else { color = function_color; @@ -535,7 +574,7 @@ void GDScriptSyntaxHighlighter::_update_cache() { if (E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP) { continue; } - if (name.find("/") != -1) { + if (name.contains("/")) { continue; } member_keywords[name] = member_variable_color; diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 07f21b34ae..1ae0d72896 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -58,6 +58,7 @@ private: SYMBOL, NUMBER, FUNCTION, + SIGNAL, KEYWORD, MEMBER, IDENTIFIER, diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 9d0d91162c..9b540b16f2 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -44,7 +44,7 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve // Search strings in AssignmentNode -> text = "__", hint_tooltip = "__" etc. Error err; - RES loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err); + Ref<Resource> loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err); if (err) { ERR_PRINT("Failed to load " + p_path); return err; diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index caa80fc24c..e7b40aa367 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd new file mode 100644 index 0000000000..a379d915a9 --- /dev/null +++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd @@ -0,0 +1,30 @@ +# meta-description: Classic movement for gravity games (platformer, ...) + +extends _BASE_ + + +const SPEED = 300.0 +const JUMP_VELOCITY = -400.0 + +# Get the gravity from the project settings to be synced with RigidDynamicBody nodes. +var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") + + +func _physics_process(delta: float) -> void: + # Add the gravity. + if not is_on_floor(): + velocity.y += gravity * delta + + # Handle Jump. + if Input.is_action_just_pressed("ui_accept") and is_on_floor(): + velocity.y = JUMP_VELOCITY + + # Get the input direction and handle the movement/deceleration. + # As good practice, you should replace UI actions with custom gameplay actions. + var direction := Input.get_axis("ui_left", "ui_right") + if direction: + velocity.x = direction * SPEED + else: + velocity.x = move_toward(velocity.x, 0, SPEED) + + move_and_slide() diff --git a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd new file mode 100644 index 0000000000..360b199e56 --- /dev/null +++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd @@ -0,0 +1,33 @@ +# meta-description: Classic movement for gravity games (FPS, TPS, ...) + +extends _BASE_ + + +const SPEED = 5.0 +const JUMP_VELOCITY = 4.5 + +# Get the gravity from the project settings to be synced with RigidDynamicBody nodes. +var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") + + +func _physics_process(delta: float) -> void: + # Add the gravity. + if not is_on_floor(): + velocity.y -= gravity * delta + + # Handle Jump. + if Input.is_action_just_pressed("ui_accept") and is_on_floor(): + velocity.y = JUMP_VELOCITY + + # Get the input direction and handle the movement/deceleration. + # As good practice, you should replace UI actions with custom gameplay actions. + var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") + var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() + if direction: + velocity.x = direction.x * SPEED + velocity.z = direction.z * SPEED + else: + velocity.x = move_toward(velocity.x, 0, SPEED) + velocity.z = move_toward(velocity.z, 0, SPEED) + + move_and_slide() diff --git a/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd new file mode 100644 index 0000000000..b27b3e5655 --- /dev/null +++ b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd @@ -0,0 +1,13 @@ +# meta-description: Basic plugin template +@tool +extends EditorPlugin + + +func _enter_tree() -> void: + # Initialization of the plugin goes here. + pass + + +func _exit_tree() -> void: + # Clean-up of the plugin goes here. + pass diff --git a/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd new file mode 100644 index 0000000000..fdb8550d43 --- /dev/null +++ b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd @@ -0,0 +1,8 @@ +# meta-description: Basic editor script template +@tool +extends EditorScript + + +# Called when the script is executed (using File -> Run in Script Editor). +func _run() -> void: + pass diff --git a/modules/gdscript/editor/script_templates/Node/default.gd b/modules/gdscript/editor/script_templates/Node/default.gd new file mode 100644 index 0000000000..cb96a21537 --- /dev/null +++ b/modules/gdscript/editor/script_templates/Node/default.gd @@ -0,0 +1,13 @@ +# meta-description: Base template for Node with default Godot cycle methods + +extends _BASE_ + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass diff --git a/modules/gdscript/editor/script_templates/Object/empty.gd b/modules/gdscript/editor/script_templates/Object/empty.gd new file mode 100644 index 0000000000..387786b0a4 --- /dev/null +++ b/modules/gdscript/editor/script_templates/Object/empty.gd @@ -0,0 +1,3 @@ +# meta-description: Empty template suitable for all Objects + +extends _BASE_ diff --git a/modules/gdscript/editor/script_templates/SCsub b/modules/gdscript/editor/script_templates/SCsub new file mode 100644 index 0000000000..2266ef2d01 --- /dev/null +++ b/modules/gdscript/editor/script_templates/SCsub @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +Import("env") + +import editor.template_builders as build_template_gd + +env["BUILDERS"]["MakeGDTemplateBuilder"] = Builder( + action=env.Run(build_template_gd.make_templates, "Generating GDScript templates header."), + suffix=".h", + src_suffix=".gd", +) + +# Template files +templates_sources = Glob("*/*.gd") + +env.Alias("editor_template_gd", [env.MakeGDTemplateBuilder("templates.gen.h", templates_sources)]) diff --git a/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd new file mode 100644 index 0000000000..283a95d3b4 --- /dev/null +++ b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd @@ -0,0 +1,50 @@ +# meta-description: Visual shader's node plugin template + +@tool +class_name VisualShaderNode_CLASS_ +extends _BASE_ + + +func _get_name() -> String: + return "_CLASS_" + + +func _get_category() -> String: + return "" + + +func _get_description() -> String: + return "" + + +func _get_return_icon_type() -> int: + return PORT_TYPE_SCALAR + + +func _get_input_port_count() -> int: + return 0 + + +func _get_input_port_name(port: int) -> String: + return "" + + +func _get_input_port_type(port: int) -> int: + return PORT_TYPE_SCALAR + + +func _get_output_port_count() -> int: + return 1 + + +func _get_output_port_name(port: int) -> String: + return "result" + + +func _get_output_port_type(port: int) -> int: + return PORT_TYPE_SCALAR + + +func _get_code(input_vars: Array[String], output_vars: Array[String], + mode: int, type: int) -> String: + return output_vars[0] + " = 0.0;" diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 4822e411ce..1b4711804c 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -43,12 +43,17 @@ #include "gdscript_cache.h" #include "gdscript_compiler.h" #include "gdscript_parser.h" +#include "gdscript_rpc_callable.h" #include "gdscript_warning.h" #ifdef TESTS_ENABLED #include "tests/gdscript_test_runner.h" #endif +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif + /////////////////////////// GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) { @@ -77,7 +82,7 @@ Variant GDScriptNativeClass::_new() { RefCounted *rc = Object::cast_to<RefCounted>(o); if (rc) { - return REF(rc); + return Ref<RefCounted>(rc); } else { return o; } @@ -87,6 +92,21 @@ Object *GDScriptNativeClass::instantiate() { return ClassDB::instantiate(name); } +Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_method == SNAME("new")) { + // Constructor. + return Object::callp(p_method, p_args, p_argcount, r_error); + } + MethodBind *method = ClassDB::get_method(name, p_method); + if (method) { + // Native static method. + return method->call(nullptr, p_args, p_argcount, r_error); + } + + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); +} + GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) { if (p_script->initializer) { return p_script->initializer; @@ -175,7 +195,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr } r_error.error = Callable::CallError::CALL_OK; - REF ref; + Ref<RefCounted> ref; Object *owner = nullptr; GDScript *_baseptr = this; @@ -193,7 +213,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { - ref = REF(r); + ref = Ref<RefCounted>(r); } GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error); @@ -791,7 +811,7 @@ void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) { String GDScript::_get_debug_path() const { if (is_built_in() && !get_name().is_empty()) { - return get_name() + " (" + get_path().get_slice("::", 0) + ")"; + return get_name() + " (" + get_path() + ")"; } else { return get_path(); } @@ -817,10 +837,12 @@ Error GDScript::reload(bool p_keep_state) { basedir = basedir.get_base_dir(); } - if (source.find("%BASE%") != -1) { - //loading a template, don't parse +// Loading a template, don't parse. +#ifdef TOOLS_ENABLED + if (EditorSettings::get_singleton() && basedir.begins_with(EditorSettings::get_singleton()->get_project_script_templates_dir())) { return OK; } +#endif { String source_path = path; @@ -927,7 +949,7 @@ const Vector<Multiplayer::RPCConfig> GDScript::get_rpc_methods() const { return rpc_functions; } -Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *top = this; while (top) { Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method); @@ -941,7 +963,7 @@ Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p //none found, regular - return Script::call(p_method, p_args, p_argcount, r_error); + return Script::callp(p_method, p_args, p_argcount, r_error); } bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { @@ -1008,17 +1030,21 @@ Error GDScript::load_byte_code(const String &p_path) { Error GDScript::load_source_code(const String &p_path) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { - ERR_FAIL_COND_V(err, err); + const char *err_name; + if (err < 0 || err >= ERR_MAX) { + err_name = "(invalid error code)"; + } else { + err_name = error_names[err]; + } + ERR_FAIL_COND_V_MSG(err, err, "Attempt to open script '" + p_path + "' resulted in error '" + err_name + "'."); } uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; @@ -1262,7 +1288,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { if (member->setter) { const Variant *val = &p_value; Callable::CallError err; - call(member->setter, &val, 1, err); + callp(member->setter, &val, 1, err); if (err.error == Callable::CallError::CALL_OK) { return true; //function exists, call was successful } else { @@ -1324,7 +1350,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { if (E) { if (E->get().getter) { Callable::CallError err; - r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, nullptr, 0, err); + r_ret = const_cast<GDScriptInstance *>(this)->callp(E->get().getter, nullptr, 0, err); if (err.error == Callable::CallError::CALL_OK) { return true; } @@ -1365,7 +1391,13 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { while (sl) { const Map<StringName, GDScriptFunction *>::Element *E = sl->member_functions.find(p_name); if (E) { - r_ret = Callable(this->owner, E->key()); + Multiplayer::RPCConfig config; + config.name = p_name; + if (sptr->rpc_functions.find(config) != -1) { + r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key()))); + } else { + r_ret = Callable(this->owner, E->key()); + } return true; //index found } sl = sl->_base; @@ -1503,7 +1535,7 @@ bool GDScriptInstance::has_method(const StringName &p_method) const { return false; } -Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *sptr = script.ptr(); while (sptr) { Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); @@ -1538,7 +1570,7 @@ void GDScriptInstance::notification(int p_notification) { String GDScriptInstance::to_string(bool *r_valid) { if (has_method(CoreStringNames::get_singleton()->_to_string)) { Callable::CallError ce; - Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); + Variant ret = callp(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); if (ce.error == Callable::CallError::CALL_OK) { if (ret.get_type() != Variant::STRING) { if (r_valid) { @@ -2012,8 +2044,6 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "preload", "signal", "super", - "trait", - "yield", // var "const", "enum", @@ -2030,6 +2060,11 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "return", "match", "while", + // These keywords are not implemented currently, but reserved for (potential) future use. + // We highlight them as keywords to make errors easier to understand. + "trait", + "namespace", + "yield", nullptr }; @@ -2068,7 +2103,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { Vector<uint8_t> sourcef; Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { return String(); } @@ -2102,8 +2137,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } else { Vector<StringName> extend_classes = subclass->extends; - FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ); - if (!subfile) { + Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ); + if (subfile.is_null()) { break; } String subsource = subfile->get_as_utf8_string(); @@ -2196,7 +2231,6 @@ GDScriptLanguage::GDScriptLanguage() { GLOBAL_DEF("debug/gdscript/warnings/enable", true); GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true); - GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); bool default_enabled = !warning.begins_with("unsafe_"); @@ -2258,7 +2292,7 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na /*************** RESOURCE ***************/ -RES ResourceFormatLoaderGDScript::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<Resource> ResourceFormatLoaderGDScript::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_FILE_CANT_OPEN; } @@ -2301,8 +2335,8 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con } void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'."); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'."); String source = file->get_as_utf8_string(); if (source.is_empty()) { @@ -2319,24 +2353,23 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S } } -Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { +Error ResourceFormatSaverGDScript::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { Ref<GDScript> sqscr = p_resource; ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); String source = sqscr->get_source_code(); - Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + { + Error err; + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'."); - file->store_string(source); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); - return ERR_CANT_CREATE; + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } } - file->close(); - memdelete(file); if (ScriptServer::is_reload_scripts_on_save_enabled()) { GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false); @@ -2345,12 +2378,12 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou return OK; } -void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { +void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const { if (Object::cast_to<GDScript>(*p_resource)) { p_extensions->push_back("gd"); } } -bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const { +bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const { return Object::cast_to<GDScript>(*p_resource) != nullptr; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index ade4f247c9..a20f3b2fca 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -52,6 +52,7 @@ public: _FORCE_INLINE_ const StringName &get_name() const { return name; } Variant _new(); Object *instantiate(); + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; GDScriptNativeClass(const StringName &p_name); }; @@ -166,7 +167,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); void _get_property_list(List<PropertyInfo> *p_properties) const; - Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; + Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; static void _bind_methods(); @@ -212,7 +213,7 @@ public: virtual void update_exports() override; #ifdef TOOLS_ENABLED - virtual const Vector<DocData::ClassDoc> &get_documentation() const override { + virtual Vector<DocData::ClassDoc> get_documentation() const override { return docs; } #endif // TOOLS_ENABLED @@ -261,11 +262,12 @@ class GDScriptInstance : public ScriptInstance { friend class GDScript; friend class GDScriptFunction; friend class GDScriptLambdaCallable; + friend class GDScriptLambdaSelfCallable; friend class GDScriptCompiler; friend struct GDScriptUtilityFunctionsDefinitions; ObjectID owner_id; - Object *owner; + Object *owner = nullptr; Ref<GDScript> script; #ifdef DEBUG_ENABLED Map<StringName, int> member_indices_cache; //used only for hot script reloading @@ -285,7 +287,7 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; } @@ -311,17 +313,17 @@ class GDScriptLanguage : public ScriptLanguage { static GDScriptLanguage *singleton; - Variant *_global_array; + Variant *_global_array = nullptr; Vector<Variant> global_array; Map<StringName, int> globals; Map<StringName, Variant> named_globals; struct CallLevel { - Variant *stack; - GDScriptFunction *function; - GDScriptInstance *instance; - int *ip; - int *line; + Variant *stack = nullptr; + GDScriptFunction *function = nullptr; + GDScriptInstance *instance = nullptr; + int *ip = nullptr; + int *line = nullptr; }; int _debug_parse_err_line; @@ -329,7 +331,7 @@ class GDScriptLanguage : public ScriptLanguage { String _debug_error; int _debug_call_stack_pos; int _debug_max_call_stack; - CallLevel *_call_stack; + CallLevel *_call_stack = nullptr; void _add_global(const StringName &p_name, const Variant &p_value); @@ -396,7 +398,7 @@ public: _debug_call_stack_pos--; } - virtual Vector<StackInfo> debug_get_current_stack_info() { + virtual Vector<StackInfo> debug_get_current_stack_info() override { if (Thread::get_main_id() != Thread::get_caller_id()) { return Vector<StackInfo>(); } @@ -430,77 +432,76 @@ public: _FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; } - virtual String get_name() const; + virtual String get_name() const override; /* LANGUAGE FUNCTIONS */ - virtual void init(); - virtual String get_type() const; - virtual String get_extension() const; - virtual Error execute_file(const String &p_path); - virtual void finish(); + virtual void init() override; + virtual String get_type() const override; + virtual String get_extension() const override; + virtual Error execute_file(const String &p_path) override; + virtual void finish() override; /* 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, 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; - virtual bool supports_documentation() const; - virtual bool can_inherit_from_file() const { return true; } - virtual int find_function(const String &p_function, const String &p_code) const; - virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; - virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint); + virtual void get_reserved_words(List<String> *p_words) const override; + virtual bool is_control_flow_keyword(String p_keywords) const override; + virtual void get_comment_delimiters(List<String> *p_delimiters) const override; + virtual void get_string_delimiters(List<String> *p_delimiters) const override; + virtual bool is_using_templates() override; + virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; + virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override; + 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 override; + virtual Script *create_script() const override; + virtual bool has_named_classes() const override; + virtual bool supports_builtin_mode() const override; + virtual bool supports_documentation() const override; + virtual bool can_inherit_from_file() const override { return true; } + virtual int find_function(const String &p_function, const String &p_code) const override; + virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override; + virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) override; #ifdef TOOLS_ENABLED - virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result); + virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) override; #endif virtual String _get_indentation() const; - virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; - virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); - virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value); - virtual void remove_named_global_constant(const StringName &p_name); + virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override; + virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) override; + virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override; + virtual void remove_named_global_constant(const StringName &p_name) override; /* DEBUGGER FUNCTIONS */ - virtual String debug_get_error() const; - virtual int debug_get_stack_level_count() const; - virtual int debug_get_stack_level_line(int p_level) const; - virtual String debug_get_stack_level_function(int p_level) const; - virtual String debug_get_stack_level_source(int p_level) const; - virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual ScriptInstance *debug_get_stack_level_instance(int p_level); - virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); + virtual String debug_get_error() const override; + virtual int debug_get_stack_level_count() const override; + virtual int debug_get_stack_level_line(int p_level) const override; + virtual String debug_get_stack_level_function(int p_level) const override; + virtual String debug_get_stack_level_source(int p_level) const override; + virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; + virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; + virtual ScriptInstance *debug_get_stack_level_instance(int p_level) override; + virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; + virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) override; - virtual void reload_all_scripts(); - virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); + virtual void reload_all_scripts() override; + virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override; - virtual void frame(); + virtual void frame() override; - virtual void get_public_functions(List<MethodInfo> *p_functions) const; - virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const; + virtual void get_public_functions(List<MethodInfo> *p_functions) const override; + virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override; - virtual void profiling_start(); - virtual void profiling_stop(); + virtual void profiling_start() override; + virtual void profiling_stop() override; - virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); - virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); + virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override; + virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override; /* LOADER FUNCTIONS */ - virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; /* GLOBAL CLASSES */ - virtual bool handles_global_class_type(const String &p_type) const; - virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const; + virtual bool handles_global_class_type(const String &p_type) const override; + virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const override; void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass); Ref<GDScript> get_orphan_subclass(const String &p_qualified_name); @@ -511,7 +512,7 @@ public: class ResourceFormatLoaderGDScript : 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 Ref<Resource> 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; @@ -520,9 +521,9 @@ public: class ResourceFormatSaverGDScript : public ResourceFormatSaver { public: - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const RES &p_resource) const; + virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const Ref<Resource> &p_resource) const; }; #endif // GDSCRIPT_H diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 7b64c0564e..d346264933 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -108,7 +108,7 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; type.kind = GDScriptParser::DataType::ENUM; - type.builtin_type = Variant::OBJECT; + type.builtin_type = Variant::INT; type.is_constant = true; type.is_meta_type = true; @@ -196,7 +196,7 @@ Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::C } if (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::NATIVE) { - if (current_data_type->native_type != StringName("")) { + if (current_data_type->native_type != StringName()) { return check_native_member_name_conflict( p_member_name, p_member_node, @@ -250,7 +250,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 = "RefCounted"; + result.native_type = SNAME("RefCounted"); } else { result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -277,6 +277,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, base = parser->get_parser()->head->get_datatype(); } else { if (p_class->extends.is_empty()) { + push_error("Could not resolve an empty super class path.", p_class); return ERR_PARSE_ERROR; } const StringName &name = p_class->extends[extends_index++]; @@ -438,7 +439,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type StringName first = p_type->type_chain[0]->name; - if (first == "Variant") { + if (first == SNAME("Variant")) { result.kind = GDScriptParser::DataType::VARIANT; if (p_type->type_chain.size() > 1) { push_error(R"("Variant" type don't contain nested types.)", p_type->type_chain[1]); @@ -447,9 +448,9 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type return result; } - if (first == "Object") { + if (first == SNAME("Object")) { result.kind = GDScriptParser::DataType::NATIVE; - result.native_type = "Object"; + result.native_type = SNAME("Object"); if (p_type->type_chain.size() > 1) { push_error(R"("Object" type don't contain nested types.)", p_type->type_chain[1]); return GDScriptParser::DataType(); @@ -646,41 +647,51 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas } } - if (member.variable->datatype_specifier != nullptr) { - datatype = specified_type; + // Check if initializer is an unset identifier (ie: a variable within scope, but declared below) + if (member.variable->initializer && !member.variable->initializer->get_datatype().is_set()) { + if (member.variable->initializer->type == GDScriptParser::Node::IDENTIFIER) { + GDScriptParser::IdentifierNode *initializer_identifier = static_cast<GDScriptParser::IdentifierNode *>(member.variable->initializer); + push_error(vformat(R"(Identifier "%s" must be declared above current variable.)", initializer_identifier->name), member.variable->initializer); + } else { + ERR_PRINT("Parser bug (please report): tried to assign unset node without an identifier."); + } + } else { + if (member.variable->datatype_specifier != nullptr) { + datatype = specified_type; - if (member.variable->initializer != nullptr) { - if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) { - // Try reverse test since it can be a masked subtype. - if (!is_type_compatible(member.variable->initializer->get_datatype(), datatype, true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); - } else { - // TODO: Add warning. + if (member.variable->initializer != nullptr) { + if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true, member.variable->initializer)) { + // Try reverse test since it can be a masked subtype. + if (!is_type_compatible(member.variable->initializer->get_datatype(), datatype, true, member.variable->initializer)) { + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); + } 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 + parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); +#endif + } + 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 (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { -#ifdef DEBUG_ENABLED - parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); -#endif } - 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) { + if (member.variable->initializer == nullptr) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because there's no default value.)", member.variable->identifier->name), member.variable->identifier); + } else if (!datatype.is_set() || datatype.has_no_type()) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value doesn't have a set type.)", member.variable->identifier->name), member.variable->initializer); + } else if (datatype.is_variant()) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is Variant. Use explicit "Variant" type if this is intended.)", member.variable->identifier->name), member.variable->initializer); + } else if (datatype.builtin_type == Variant::NIL) { + push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer); } + datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; } - } else if (member.variable->infer_datatype) { - if (member.variable->initializer == nullptr) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because there's no default value.)", member.variable->identifier->name), member.variable->identifier); - } else if (!datatype.is_set() || datatype.has_no_type()) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value doesn't have a set type.)", member.variable->identifier->name), member.variable->initializer); - } else if (datatype.is_variant()) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is Variant. Use explicit "Variant" type if this is intended.)", member.variable->identifier->name), member.variable->initializer); - } else if (datatype.builtin_type == Variant::NIL) { - push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer); - } - datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; } datatype.is_constant = false; @@ -881,12 +892,23 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { for (int i = 0; i < p_class->members.size(); i++) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) { - resolve_function_body(member.function); - // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { E->apply(parser, member.function); } + +#ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : member.function->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } +#endif // DEBUG_ENABLED + + resolve_function_body(member.function); + +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED } else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) { if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) { if (member.variable->getter != nullptr) { @@ -925,6 +947,10 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) { #ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : member.function->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) { parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name); } @@ -992,6 +1018,9 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable); } } +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED } } } @@ -1096,6 +1125,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * GDScriptParser::FunctionNode *previous_function = parser->current_function; parser->current_function = p_function; +#ifdef TOOLS_ENABLED + int default_value_count = 0; +#endif // TOOLS_ENABLED + for (int i = 0; i < p_function->parameters.size(); i++) { resolve_parameter(p_function->parameters[i]); #ifdef DEBUG_ENABLED @@ -1105,13 +1138,17 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * is_shadowing(p_function->parameters[i]->identifier, "function parameter"); #endif // DEBUG_ENABLED #ifdef TOOLS_ENABLED - if (p_function->parameters[i]->default_value && p_function->parameters[i]->default_value->is_constant) { - p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value); + if (p_function->parameters[i]->default_value) { + default_value_count++; + + if (p_function->parameters[i]->default_value->is_constant) { + p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value); + } } #endif // TOOLS_ENABLED } - if (p_function->identifier->name == "_init") { + if (p_function->identifier->name == GDScriptLanguage::get_singleton()->strings._init) { // Constructor. GDScriptParser::DataType return_type = parser->current_class->get_datatype(); return_type.is_meta_type = false; @@ -1125,6 +1162,57 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * } else { GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type); p_function->set_datatype(return_type); + +#ifdef TOOLS_ENABLED + // Check if the function signature matches the parent. If not it's an error since it breaks polymorphism. + // Not for the constructor which can vary in signature. + GDScriptParser::DataType base_type = parser->current_class->base_type; + GDScriptParser::DataType parent_return_type; + List<GDScriptParser::DataType> parameters_types; + int default_par_count = 0; + bool is_static = false; + bool is_vararg = false; + if (get_function_signature(p_function, false, base_type, p_function->identifier->name, parent_return_type, parameters_types, default_par_count, is_static, is_vararg)) { + bool valid = p_function->is_static == is_static; + valid = valid && parent_return_type == p_function->get_datatype(); + + int par_count_diff = p_function->parameters.size() - parameters_types.size(); + valid = valid && par_count_diff >= 0; + valid = valid && default_value_count >= default_par_count + par_count_diff; + + int i = 0; + for (const GDScriptParser::DataType &par_type : parameters_types) { + valid = valid && par_type == p_function->parameters[i++]->get_datatype(); + } + + if (!valid) { + // Compute parent signature as a string to show in the error message. + String parent_signature = parent_return_type.is_hard_type() ? parent_return_type.to_string() : "Variant"; + if (parent_signature == "null") { + parent_signature = "void"; + } + parent_signature += " " + p_function->identifier->name.operator String() + "("; + int j = 0; + for (const GDScriptParser::DataType &par_type : parameters_types) { + if (j > 0) { + parent_signature += ", "; + } + String parameter = par_type.to_string(); + if (parameter == "null") { + parameter = "Variant"; + } + parent_signature += parameter; + if (j == parameters_types.size() - default_par_count) { + parent_signature += " = default"; + } + + j++; + } + parent_signature += ")"; + push_error(vformat(R"(The function signature doesn't match the parent. Parent signature is "%s".)", parent_signature), p_function); + } + } +#endif // TOOLS_ENABLED } parser->current_function = previous_function; @@ -1186,7 +1274,23 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) { for (int i = 0; i < p_suite->statements.size(); i++) { GDScriptParser::Node *stmt = p_suite->statements[i]; + for (GDScriptParser::AnnotationNode *&annotation : stmt->annotations) { + annotation->apply(parser, stmt); + } + +#ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : stmt->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } +#endif // DEBUG_ENABLED + resolve_node(stmt); + +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED + decide_suite_type(p_suite, stmt); } } @@ -1207,7 +1311,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { bool list_resolved = false; // Optimize constant range() call to not allocate an array. - // Use int, Vector2, Vector3 instead, which also can be used as range iterators. + // Use int, Vector2i, Vector3i instead, which also can be used as range iterators. if (p_for->list && p_for->list->type == GDScriptParser::Node::CALL) { GDScriptParser::CallNode *call = static_cast<GDScriptParser::CallNode *>(p_for->list); GDScriptParser::Node::Type callee_type = call->get_callee_type(); @@ -1366,9 +1470,9 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable type.is_meta_type = false; if (p_variable->initializer != nullptr) { - if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) { + if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true, p_variable->initializer)) { // Try reverse test since it can be a masked subtype. - if (!is_type_compatible(p_variable->initializer->get_datatype(), type, true)) { + if (!is_type_compatible(p_variable->initializer->get_datatype(), type, true, p_variable->initializer)) { push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); } else { // TODO: Add warning. @@ -1380,7 +1484,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION); #endif } - if (p_variable->initializer->get_datatype().is_variant()) { + if (p_variable->initializer->get_datatype().is_variant() && !type.is_variant()) { // TODO: Warn unsafe assign. mark_node_unsafe(p_variable->initializer); p_variable->use_conversion_assign = true; @@ -1552,7 +1656,7 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc if (p_match_pattern->dictionary[i].key) { reduce_expression(p_match_pattern->dictionary[i].key); if (!p_match_pattern->dictionary[i].key->is_constant) { - push_error(R"(Expression in dictionary pattern key must be a constant.)", p_match_pattern->expression); + push_error(R"(Expression in dictionary pattern key must be a constant.)", p_match_pattern->dictionary[i].key); } } @@ -1834,19 +1938,20 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) { - bool compatible = true; - GDScriptParser::DataType op_type = assigned_value_type; - if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { - op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); - } + bool compatible = true; + GDScriptParser::DataType op_type = assigned_value_type; + if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { + op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); + } + p_assignment->set_datatype(op_type); + if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) { if (compatible) { - compatible = is_type_compatible(assignee_type, op_type, true); + compatible = is_type_compatible(assignee_type, op_type, true, p_assignment->assigned_value); if (!compatible) { if (assignee_type.is_hard_type()) { // Try reverse test since it can be a masked subtype. - if (!is_type_compatible(op_type, assignee_type, true)) { + if (!is_type_compatible(op_type, assignee_type, true, p_assignment->assigned_value)) { 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. @@ -1865,7 +1970,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig if (assignee_type.has_no_type() || assigned_value_type.is_variant()) { mark_node_unsafe(p_assignment); - if (assignee_type.is_hard_type()) { + if (assignee_type.is_hard_type() && !assignee_type.is_variant()) { p_assignment->use_conversion_assign = true; } } @@ -2198,7 +2303,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a break; #ifdef DEBUG_ENABLED } else { - if (par_type.builtin_type == Variant::INT && p_call->arguments[i]->get_datatype().builtin_type == Variant::FLOAT) { + if (par_type.builtin_type == Variant::INT && p_call->arguments[i]->get_datatype().builtin_type == Variant::FLOAT && builtin_type != Variant::INT) { parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, p_call->function_name); } #endif @@ -2321,6 +2426,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a base_type = parser->current_class->base_type; base_type.is_meta_type = false; is_self = true; + + if (p_call->callee == nullptr && !lambda_stack.is_empty()) { + push_error("Cannot use `super()` inside a lambda.", p_call); + } } else if (callee_type == GDScriptParser::Node::IDENTIFIER) { base_type = parser->current_class->get_datatype(); base_type.is_meta_type = false; @@ -2371,7 +2480,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a GDScriptParser::DataType return_type; 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)) { + bool is_constructor = (base_type.is_meta_type || (p_call->callee && p_call->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_call->function_name == SNAME("new"); + + if (get_function_signature(p_call, is_constructor, 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 (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) { int index = E.key; @@ -2381,19 +2492,30 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } validate_call_arg(par_types, default_arg_count, is_vararg, p_call); + if (base_type.kind == GDScriptParser::DataType::ENUM && base_type.is_meta_type) { + // Enum type is treated as a dictionary value for function calls. + base_type.is_meta_type = false; + } + 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); + // Get the parent function above any lambda. + GDScriptParser::FunctionNode *parent_function = parser->current_function; + while (parent_function->source_lambda) { + parent_function = parent_function->source_lambda->parent_function; + } + push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call); } else if (!is_self && base_type.is_meta_type && !is_static) { base_type.is_meta_type = false; // For `to_string()`. - push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), 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); + push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call); + } else if (is_self && !is_static) { + mark_lambda_use_self(); } call_type = return_type; } else { - // Check if the name exists as something else. bool found = false; + + // Check if the name exists as something else. if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) { GDScriptParser::IdentifierNode *callee_id; if (callee_type == GDScriptParser::Node::IDENTIFIER) { @@ -2423,11 +2545,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a if (!found && (is_self || (base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN))) { String base_name = is_self && !p_call->is_super ? "self" : base_type.to_string(); push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee); + } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) { + push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type.operator String()), p_call); } } if (call_type.is_coroutine && !p_is_await && !p_is_root) { - push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call->callee); + push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call); } p_call->set_datatype(call_type); @@ -2439,17 +2563,24 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) { GDScriptParser::DataType cast_type = resolve_datatype(p_cast->cast_type); if (!cast_type.is_set()) { + mark_node_unsafe(p_cast); return; } - cast_type.is_meta_type = false; // The casted value won't be a type name. + cast_type = type_from_metatype(cast_type); // The casted value won't be a type name. p_cast->set_datatype(cast_type); if (!cast_type.is_variant()) { GDScriptParser::DataType op_type = p_cast->operand->get_datatype(); if (!op_type.is_variant()) { bool valid = false; - if (op_type.kind == GDScriptParser::DataType::BUILTIN && cast_type.kind == GDScriptParser::DataType::BUILTIN) { + if (op_type.kind == GDScriptParser::DataType::ENUM && cast_type.kind == GDScriptParser::DataType::ENUM) { + // Enum types are compatible between each other, so it's a safe cast. + valid = true; + } else if (op_type.kind == GDScriptParser::DataType::BUILTIN && op_type.builtin_type == Variant::INT && cast_type.kind == GDScriptParser::DataType::ENUM) { + // Convertint int to enum is always valid. + valid = true; + } else if (op_type.kind == GDScriptParser::DataType::BUILTIN && cast_type.kind == GDScriptParser::DataType::BUILTIN) { valid = Variant::can_convert(op_type.builtin_type, cast_type.builtin_type); } else if (op_type.kind != GDScriptParser::DataType::BUILTIN && cast_type.kind != GDScriptParser::DataType::BUILTIN) { valid = is_type_compatible(cast_type, op_type) || is_type_compatible(op_type, cast_type); @@ -2505,31 +2636,37 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node) GDScriptParser::DataType result; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; result.kind = GDScriptParser::DataType::NATIVE; - result.native_type = "Node"; + result.native_type = SNAME("Node"); result.builtin_type = Variant::OBJECT; if (!ClassDB::is_parent_class(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); } + mark_lambda_use_self(); + p_get_node->set_datatype(result); } GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) { + GDScriptParser::DataType type; + Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(p_class_name)); - Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); + if (ref.is_null()) { + push_error(vformat(R"(Could not find script for class "%s".)", p_class_name), p_source); + type.type_source = GDScriptParser::DataType::UNDETECTED; + type.kind = GDScriptParser::DataType::VARIANT; + return type; + } + Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); if (err) { push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source); - GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::UNDETECTED; type.kind = GDScriptParser::DataType::VARIANT; return type; } - GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; type.kind = GDScriptParser::DataType::CLASS; type.builtin_type = Variant::OBJECT; @@ -2551,6 +2688,34 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod const StringName &name = p_identifier->name; + if (base.kind == GDScriptParser::DataType::ENUM) { + if (base.is_meta_type) { + if (base.enum_values.has(name)) { + p_identifier->is_constant = true; + p_identifier->reduced_value = base.enum_values[name]; + + GDScriptParser::DataType result; + result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + result.kind = GDScriptParser::DataType::ENUM; + result.is_constant = true; + result.builtin_type = Variant::INT; + result.native_type = base.native_type; + result.enum_type = base.enum_type; + p_identifier->set_datatype(result); + return; + } else { + // Consider as a Dictionary, so it can be anything. + // This will be evaluated in the next if block. + base.kind = GDScriptParser::DataType::BUILTIN; + base.builtin_type = Variant::DICTIONARY; + base.is_meta_type = false; + } + } else { + push_error(R"(Cannot get property from enum value.)", p_identifier); + return; + } + } + if (base.kind == GDScriptParser::DataType::BUILTIN) { if (base.is_meta_type) { bool valid = true; @@ -2597,31 +2762,6 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod return; } - if (base.kind == GDScriptParser::DataType::ENUM) { - if (base.is_meta_type) { - if (base.enum_values.has(name)) { - p_identifier->is_constant = true; - p_identifier->reduced_value = base.enum_values[name]; - - 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); - } else { - // Consider as a Dictionary - GDScriptParser::DataType dummy; - dummy.kind = GDScriptParser::DataType::VARIANT; - p_identifier->set_datatype(dummy); - } - } else { - push_error(R"(Cannot get property from enum value.)", p_identifier); - } - return; - } - GDScriptParser::ClassNode *base_class = base.class_type; // TODO: Switch current class/function/suite here to avoid misrepresenting identifiers (in recursive reduce calls). @@ -2719,21 +2859,25 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod MethodBind *getter = ClassDB::get_method(native, getter_name); if (getter != nullptr) { p_identifier->set_datatype(type_from_property(getter->get_return_info())); + p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE; } return; } if (ClassDB::get_method_info(native, name, &method_info)) { // Method is callable. p_identifier->set_datatype(make_callable_type(method_info)); + p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE; return; } if (ClassDB::get_signal(native, name, &method_info)) { // Signal is a type too. p_identifier->set_datatype(make_signal_type(method_info)); + p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE; return; } if (ClassDB::has_enum(native, name)) { p_identifier->set_datatype(make_native_enum_type(native, name)); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; return; } bool valid = false; @@ -2742,6 +2886,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod p_identifier->is_constant = true; p_identifier->reduced_value = int_constant; p_identifier->set_datatype(type_from_variant(int_constant, p_identifier)); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; return; } } @@ -2757,7 +2902,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident if (element.identifier->name == p_identifier->name) { GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - type.kind = element.parent_enum->identifier ? GDScriptParser::DataType::ENUM_VALUE : GDScriptParser::DataType::BUILTIN; + type.kind = element.parent_enum->identifier ? GDScriptParser::DataType::ENUM : GDScriptParser::DataType::BUILTIN; type.builtin_type = Variant::INT; type.is_constant = true; if (element.parent_enum->identifier) { @@ -2792,7 +2937,11 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value; found_source = true; break; + case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: + mark_lambda_use_self(); + break; case GDScriptParser::IdentifierNode::MEMBER_VARIABLE: + mark_lambda_use_self(); p_identifier->variable_source->usages++; [[fallthrough]]; case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: @@ -2823,18 +2972,37 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident } 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; + if ((p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE) && parser->current_function && parser->current_function->is_static) { + // Get the parent function above any lambda. + GDScriptParser::FunctionNode *parent_function = parser->current_function; + while (parent_function->source_lambda) { + parent_function = parent_function->source_lambda->parent_function; + } + push_error(vformat(R"*(Cannot access instance variable "%s" from the static function "%s()".)*", p_identifier->name, parent_function->identifier->name), p_identifier); } - 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; + if (!lambda_stack.is_empty()) { + // If the identifier is a member variable (including the native class properties), we consider the lambda to be using `self`, so we keep a reference to the current instance. + if (p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE) { + mark_lambda_use_self(); + return; // No need to capture. + } + // If the identifier is local, check if it's any kind of capture by comparing their source function. + // Only capture locals and enum values. Constants are still accessible from the lambda using the script reference. If not, this method is done. + if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT) { + return; + } + + GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function; + // Make sure we aren't capturing variable in the same lambda. + // This also add captures for nested lambdas. + 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; } @@ -3014,6 +3182,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) { void GDScriptAnalyzer::reduce_self(GDScriptParser::SelfNode *p_self) { p_self->is_constant = false; p_self->set_datatype(type_from_metatype(parser->current_class->get_datatype())); + mark_lambda_use_self(); } void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscript) { @@ -3024,6 +3193,12 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base), true); } else { reduce_expression(p_subscript->base); + + if (p_subscript->base->type == GDScriptParser::Node::ARRAY) { + const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_subscript->base)); + } else if (p_subscript->base->type == GDScriptParser::Node::DICTIONARY) { + const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_subscript->base)); + } } GDScriptParser::DataType result_type; @@ -3341,6 +3516,13 @@ void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) { for (int i = 0; i < p_array->elements.size(); i++) { GDScriptParser::ExpressionNode *element = p_array->elements[i]; + + if (element->type == GDScriptParser::Node::ARRAY) { + const_fold_array(static_cast<GDScriptParser::ArrayNode *>(element)); + } else if (element->type == GDScriptParser::Node::DICTIONARY) { + const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element)); + } + all_is_constant = all_is_constant && element->is_constant; if (!all_is_constant) { return; @@ -3361,6 +3543,13 @@ void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_d for (int i = 0; i < p_dictionary->elements.size(); i++) { const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i]; + + if (element.value->type == GDScriptParser::Node::ARRAY) { + const_fold_array(static_cast<GDScriptParser::ArrayNode *>(element.value)); + } else if (element.value->type == GDScriptParser::Node::DICTIONARY) { + const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element.value)); + } + all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant; if (!all_is_constant) { return; @@ -3457,6 +3646,9 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_metatype(const GDScriptPars GDScriptParser::DataType result = p_meta_type; result.is_meta_type = false; result.is_constant = false; + if (p_meta_type.kind == GDScriptParser::DataType::ENUM) { + result.builtin_type = Variant::INT; + } return result; } @@ -3471,7 +3663,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo result.builtin_type = p_property.type; if (p_property.type == Variant::OBJECT) { result.kind = GDScriptParser::DataType::NATIVE; - result.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name; + result.native_type = p_property.class_name == StringName() ? SNAME("Object") : p_property.class_name; } else { result.kind = GDScriptParser::DataType::BUILTIN; result.builtin_type = p_property.type; @@ -3507,12 +3699,24 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo return result; } -bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) { +bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) { r_static = false; r_vararg = false; r_default_arg_count = 0; StringName function_name = p_function; + if (p_base_type.kind == GDScriptParser::DataType::ENUM) { + if (p_base_type.is_meta_type) { + // Enum type can be treated as a dictionary value. + p_base_type.kind = GDScriptParser::DataType::BUILTIN; + p_base_type.builtin_type = Variant::DICTIONARY; + p_base_type.is_meta_type = false; + } else { + push_error("Cannot call function on enum value.", p_source); + return false; + } + } + if (p_base_type.kind == GDScriptParser::DataType::BUILTIN) { // Construct a base type to get methods. Callable::CallError err; @@ -3535,8 +3739,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source return false; } - bool is_constructor = (p_base_type.is_meta_type || (p_source->callee && p_source->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_function == StaticCString::create("new"); - if (is_constructor) { + if (p_is_constructor) { function_name = "_init"; r_static = true; } @@ -3557,7 +3760,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source } if (found_function != nullptr) { - r_static = is_constructor || found_function->is_static; + r_static = p_is_constructor || found_function->is_static; for (int i = 0; i < found_function->parameters.size(); i++) { r_par_types.push_back(found_function->parameters[i]->get_datatype()); if (found_function->parameters[i]->default_value != nullptr) { @@ -3583,7 +3786,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source } // If the base is a script, it might be trying to access members of the Script class itself. - if (p_base_type.is_meta_type && !is_constructor && (p_base_type.kind == GDScriptParser::DataType::SCRIPT || p_base_type.kind == GDScriptParser::DataType::CLASS)) { + if (p_base_type.is_meta_type && !p_is_constructor && (p_base_type.kind == GDScriptParser::DataType::SCRIPT || p_base_type.kind == GDScriptParser::DataType::CLASS)) { MethodInfo info; StringName script_class = p_base_type.kind == GDScriptParser::DataType::SCRIPT ? p_base_type.script_type->get_class_name() : StringName(GDScript::get_class_static()); @@ -3603,7 +3806,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source } #endif - if (is_constructor) { + if (p_is_constructor) { // Native types always have a default constructor. r_return_type = p_base_type; r_return_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -3627,6 +3830,7 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD r_return_type = type_from_property(p_info.return_val); r_default_arg_count = p_info.default_arguments.size(); r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0; + r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0; for (const PropertyInfo &E : p_info.arguments) { r_par_types.push_back(type_from_property(E)); @@ -3753,6 +3957,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator // Unary version. GDScriptParser::DataType nil_type; nil_type.builtin_type = Variant::NIL; + nil_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; return get_operation_type(p_operation, p_a, nil_type, r_valid, p_source); } @@ -3763,24 +3968,51 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator Variant::Type a_type = p_a.builtin_type; Variant::Type b_type = p_b.builtin_type; + if (p_a.kind == GDScriptParser::DataType::ENUM) { + if (p_a.is_meta_type) { + a_type = Variant::DICTIONARY; + } else { + a_type = Variant::INT; + } + } + if (p_b.kind == GDScriptParser::DataType::ENUM) { + if (p_b.is_meta_type) { + b_type = Variant::DICTIONARY; + } else { + b_type = Variant::INT; + } + } + Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type); - if (op_eval == nullptr) { + bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type(); + bool validated = op_eval != nullptr; + + if (hard_operation && !validated) { r_valid = false; return result; + } else if (hard_operation && validated) { + 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); + } else if (!hard_operation && !validated) { + r_valid = true; + result.type_source = GDScriptParser::DataType::UNDETECTED; + result.kind = GDScriptParser::DataType::VARIANT; + result.builtin_type = Variant::NIL; + } else if (!hard_operation && validated) { + r_valid = true; + result.type_source = GDScriptParser::DataType::INFERRED; + result.kind = GDScriptParser::DataType::BUILTIN; + result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); } - 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); - return result; } // TODO: Add safe/unsafe return variable (for variant cases) -bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion) const { +bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion, const GDScriptParser::Node *p_source_node) { // These return "true" so it doesn't affect users negatively. ERR_FAIL_COND_V_MSG(!p_target.is_set(), true, "Parser bug (please report): Trying to check compatibility of unset target type"); ERR_FAIL_COND_V_MSG(!p_source.is_set(), true, "Parser bug (please report): Trying to check compatibility of unset value type"); @@ -3800,7 +4032,7 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ if (!valid && p_allow_implicit_conversion) { valid = Variant::can_convert_strict(p_source.builtin_type, p_target.builtin_type); } - if (!valid && p_target.builtin_type == Variant::INT && p_source.kind == GDScriptParser::DataType::ENUM_VALUE) { + if (!valid && p_target.builtin_type == Variant::INT && p_source.kind == GDScriptParser::DataType::ENUM && !p_source.is_meta_type) { // Enum value is also integer. valid = true; } @@ -3821,6 +4053,11 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ if (p_target.kind == GDScriptParser::DataType::ENUM) { if (p_source.kind == GDScriptParser::DataType::BUILTIN && p_source.builtin_type == Variant::INT) { +#ifdef DEBUG_ENABLED + if (p_source_node) { + parser->push_warning(p_source_node, GDScriptWarning::INT_ASSIGNED_TO_ENUM); + } +#endif return true; } if (p_source.kind == GDScriptParser::DataType::ENUM) { @@ -3828,11 +4065,6 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ return true; } } - if (p_source.kind == GDScriptParser::DataType::ENUM_VALUE) { - if (p_source.native_type == p_target.native_type && p_target.enum_values.has(p_source.enum_type)) { - return true; - } - } return false; } @@ -3887,7 +4119,6 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ case GDScriptParser::DataType::VARIANT: case GDScriptParser::DataType::BUILTIN: case GDScriptParser::DataType::ENUM: - case GDScriptParser::DataType::ENUM_VALUE: case GDScriptParser::DataType::UNRESOLVED: break; // Already solved before. } @@ -3924,7 +4155,6 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ case GDScriptParser::DataType::VARIANT: case GDScriptParser::DataType::BUILTIN: case GDScriptParser::DataType::ENUM: - case GDScriptParser::DataType::ENUM_VALUE: case GDScriptParser::DataType::UNRESOLVED: break; // Already solved before. } @@ -3945,6 +4175,12 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) { #endif } +void GDScriptAnalyzer::mark_lambda_use_self() { + for (GDScriptParser::LambdaNode *lambda : lambda_stack) { + lambda->use_self = true; + } +} + bool GDScriptAnalyzer::class_exists(const StringName &p_class) const { return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class); } diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index ce4525190b..519e1975c4 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -42,7 +42,7 @@ class GDScriptAnalyzer { HashMap<String, Ref<GDScriptParserRef>> depended_parsers; const GDScriptParser::EnumNode *current_enum = nullptr; - List<const GDScriptParser::LambdaNode *> lambda_stack; + List<GDScriptParser::LambdaNode *> lambda_stack; // Tests for detecting invalid overloading of script members static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node); @@ -105,16 +105,17 @@ class GDScriptAnalyzer { GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const; GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const; GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source); - bool get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); + bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call); 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; + bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr); void push_error(const String &p_message, const GDScriptParser::Node *p_origin); void mark_node_unsafe(const GDScriptParser::Node *p_node); + void mark_lambda_use_self(); bool class_exists(const StringName &p_class) const; Ref<GDScriptParserRef> get_parser_for(const String &p_path); #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 6a7e4278d2..e72069bcd5 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -468,7 +468,7 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1); break; case Variant::TRANSFORM3D: - append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1); + append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM3D, 1); break; case Variant::COLOR: append(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR, 1); @@ -688,6 +688,7 @@ void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr) void GDScriptByteCodeGenerator::write_end_ternary() { patch_jump(ternary_jump_skip_pos.back()->get()); ternary_jump_skip_pos.pop_back(); + ternary_result.pop_back(); } void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) { @@ -1079,6 +1080,24 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_ append(Variant::get_validated_builtin_method(p_type, p_method)); } +void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) { + bool is_validated = false; + + MethodBind *method = ClassDB::get_method(p_class, p_method); + + if (!is_validated) { + // Perform regular call. + append(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_target); + append(method); + append(p_arguments.size()); + return; + } +} + 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++) { @@ -1192,8 +1211,8 @@ 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()); +void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) { + append(p_use_self ? GDScriptFunction::OPCODE_CREATE_SELF_LAMBDA : GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size()); for (int i = 0; i < p_captures.size(); i++) { append(p_captures[i]); } diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index fbbf5802fd..0503f66161 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -464,12 +464,13 @@ public: 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_native_static(const Address &p_target, const StringName &p_class, 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_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) 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; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index b91677d25c..8c198345c2 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -122,6 +122,10 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP } if (singleton->parser_map.has(p_path)) { ref = Ref<GDScriptParserRef>(singleton->parser_map[p_path]); + if (ref.is_null()) { + r_error = ERR_INVALID_DATA; + return ref; + } } else { if (!FileAccess::exists(p_path)) { r_error = ERR_FILE_NOT_FOUND; @@ -133,7 +137,6 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP ref->path = p_path; singleton->parser_map[p_path] = ref.ptr(); } - r_error = ref->raise_status(p_status); return ref; @@ -142,7 +145,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP String GDScriptCache::get_source_code(const String &p_path) { Vector<uint8_t> source_file; Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { ERR_FAIL_COND_V(err, ""); } @@ -150,7 +153,6 @@ String GDScriptCache::get_source_code(const String &p_path) { uint64_t len = f->get_length(); source_file.resize(len + 1); uint64_t r = f->get_buffer(source_file.ptrw(), len); - f->close(); ERR_FAIL_COND_V(r != len, ""); source_file.write[len] = 0; diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index 9fb661d031..3ce976ee14 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index e6ecc92d55..326b66a295 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -125,12 +125,13 @@ public: 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_native_static(const Address &p_target, const StringName &p_class, 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_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) = 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; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index bba664c328..37a988ee4c 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,6 +35,7 @@ #include "gdscript_cache.h" #include "gdscript_utility_functions.h" +#include "core/config/engine.h" #include "core/config/project_settings.h" bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) { @@ -98,6 +99,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D case GDScriptParser::DataType::NATIVE: { result.kind = GDScriptDataType::NATIVE; result.native_type = p_datatype.native_type; + result.builtin_type = p_datatype.builtin_type; } break; case GDScriptParser::DataType::SCRIPT: { result.kind = GDScriptDataType::SCRIPT; @@ -132,19 +134,24 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D result.kind = GDScriptDataType::GDSCRIPT; result.script_type = script.ptr(); result.native_type = script->get_instance_base_type(); + result.builtin_type = p_datatype.builtin_type; } else { result.kind = GDScriptDataType::GDSCRIPT; result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path); result.script_type = result.script_type_ref.ptr(); result.native_type = p_datatype.native_type; + result.builtin_type = p_datatype.builtin_type; } } } break; case GDScriptParser::DataType::ENUM: - case GDScriptParser::DataType::ENUM_VALUE: result.has_type = true; result.kind = GDScriptDataType::BUILTIN; - result.builtin_type = Variant::INT; + if (p_datatype.is_meta_type) { + result.builtin_type = Variant::DICTIONARY; + } else { + result.builtin_type = Variant::INT; + } break; case GDScriptParser::DataType::UNRESOLVED: { ERR_PRINT("Parser bug: converting unresolved type."); @@ -288,16 +295,21 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Try signals and methods (can be made callables). { - if (codegen.class_node->members_indices.has(identifier)) { - const GDScriptParser::ClassNode::Member &member = codegen.class_node->members[codegen.class_node->members_indices[identifier]]; - if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) { - // Get like it was a property. - GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here. - GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF); - - gen->write_get_named(temp, identifier, self); - return temp; + // Search upwards through parent classes: + const GDScriptParser::ClassNode *base_class = codegen.class_node; + while (base_class != nullptr) { + if (base_class->has_member(identifier)) { + const GDScriptParser::ClassNode::Member &member = base_class->get_member(identifier); + if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) { + // Get like it was a property. + GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here. + GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF); + + gen->write_get_named(temp, identifier, self); + return temp; + } } + base_class = base_class->base_type.class_type; } // Try in native base. @@ -344,7 +356,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code class_node = class_node->outer; } - RES res; + Ref<Resource> res; if (class_node->identifier && class_node->identifier->name == identifier) { res = Ref<GDScript>(main_script); @@ -469,7 +481,14 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } break; case GDScriptParser::Node::CAST: { const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression); - GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type->get_datatype()); + GDScriptParser::DataType og_cast_type = cn->cast_type->get_datatype(); + GDScriptDataType cast_type = _gdtype_from_datatype(og_cast_type); + + if (og_cast_type.kind == GDScriptParser::DataType::ENUM) { + // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer. + cast_type.kind = GDScriptDataType::BUILTIN; + cast_type.builtin_type = Variant::INT; + } // Create temporary for result first since it will be deleted last. GDScriptCodeGenerator::Address result = codegen.add_temporary(cast_type); @@ -557,6 +576,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // 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 if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") && + ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) { + // It's a static native method call. + gen->write_call_native_static(result, 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) { @@ -882,7 +905,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code #endif /* Find chain of sets */ - StringName assign_property; + StringName assign_class_member_property; + + GDScriptCodeGenerator::Address target_member_property; + bool is_member_property = false; + bool member_property_has_setter = false; + bool member_property_is_in_setter = false; + StringName member_property_setter_function; List<const GDScriptParser::SubscriptNode *> chain; @@ -892,11 +921,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code while (true) { chain.push_back(n); if (n->base->type != GDScriptParser::Node::SUBSCRIPT) { - // Check for a built-in property. + // Check for a property. if (n->base->type == GDScriptParser::Node::IDENTIFIER) { GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base); - if (_is_class_member_property(codegen, identifier->name)) { - assign_property = identifier->name; + StringName var_name = identifier->name; + if (_is_class_member_property(codegen, var_name)) { + assign_class_member_property = var_name; + } else if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { + is_member_property = true; + member_property_setter_function = codegen.script->member_indices[var_name].setter; + member_property_has_setter = member_property_setter_function != StringName(); + member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name; + target_member_property.mode = GDScriptCodeGenerator::Address::MEMBER; + target_member_property.address = codegen.script->member_indices[var_name].index; + target_member_property.type = codegen.script->member_indices[var_name].data_type; } } break; @@ -969,17 +1007,19 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Perform operator if any. if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype())); if (subscript->is_attribute) { gen->write_get_named(value, name, prev_base); } else { gen->write_get(value, key, prev_base); } - gen->write_binary_operator(value, assignment->variant_op, value, assigned); + gen->write_binary_operator(op_result, assignment->variant_op, value, assigned); + gen->pop_temporary(); if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); } - assigned = value; + assigned = op_result; } // Perform assignment. @@ -1013,10 +1053,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code assigned = info.base; } - // If this is a local member, also assign to it. + // If this is a class member property, also assign to it. // This allow things like: position.x += 2.0 - if (assign_property != StringName()) { - gen->write_set_member(assigned, assign_property); + if (assign_class_member_property != StringName()) { + gen->write_set_member(assigned, assign_class_member_property); + } + // Same as above but for members + if (is_member_property) { + if (member_property_has_setter && !member_property_is_in_setter) { + Vector<GDScriptCodeGenerator::Address> args; + args.push_back(assigned); + gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), member_property_setter_function, args); + } else { + gen->write_assign(target_member_property, assigned); + } } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -1035,8 +1085,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name; if (has_operation) { - GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); - GDScriptCodeGenerator::Address member = codegen.add_temporary(); + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); + GDScriptCodeGenerator::Address member = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype())); gen->write_get_member(member, name); gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value); gen->pop_temporary(); // Pop member temp. @@ -1053,29 +1103,26 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } } else { // Regular assignment. - GDScriptCodeGenerator::Address target; - + ERR_FAIL_COND_V_MSG(assignment->assignee->type != GDScriptParser::Node::IDENTIFIER, GDScriptCodeGenerator::Address(), "Expected the assignee to be an identifier here."); + GDScriptCodeGenerator::Address member; + bool is_member = false; bool has_setter = false; bool is_in_setter = false; StringName setter_function; - if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) { - StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; - if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { - setter_function = codegen.script->member_indices[var_name].setter; - if (setter_function != StringName()) { - has_setter = true; - is_in_setter = setter_function == codegen.function_name; - target.mode = GDScriptCodeGenerator::Address::MEMBER; - target.address = codegen.script->member_indices[var_name].index; - } - } + StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; + if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { + is_member = true; + setter_function = codegen.script->member_indices[var_name].setter; + has_setter = setter_function != StringName(); + is_in_setter = has_setter && setter_function == codegen.function_name; + member.mode = GDScriptCodeGenerator::Address::MEMBER; + member.address = codegen.script->member_indices[var_name].index; + member.type = codegen.script->member_indices[var_name].data_type; } - if (has_setter) { - if (!is_in_setter) { - // Store stack slot for the temp value. - target = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype())); - } + GDScriptCodeGenerator::Address target; + if (is_member) { + target = member; // _parse_expression could call its getter, but we want to know the actual address } else { target = _parse_expression(codegen, r_error, assignment->assignee); if (r_error) { @@ -1092,7 +1139,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE; if (has_operation) { // Perform operation. - GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee); gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value); to_assign = op_result; @@ -1150,7 +1197,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code return GDScriptCodeGenerator::Address(); } - gen->write_lambda(result, function, captures); + gen->write_lambda(result, function, captures, lambda->use_self); for (int i = 0; i < captures.size(); i++) { if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -1995,7 +2042,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ 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, r_error, parameter->default_value, true); + GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value); if (r_error) { memdelete(codegen.generator); return nullptr; @@ -2069,7 +2116,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ if (p_func) { // if no return statement -> return type is void not unresolved Variant if (p_func->body->has_return) { - gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype()); + gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); } else { gd_function->return_type = GDScriptDataType(); gd_function->return_type.has_type = true; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 7d5bee93ac..8d71437344 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index 9287df2ea0..dc114f2eff 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -564,6 +564,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 5 + argc; } break; + case OPCODE_CALL_NATIVE_STATIC: { + MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]]; + int argc = _code_ptr[ip + 2 + instr_var_args]; + + text += "call native method static "; + text += DADDR(1 + argc); + text += " = "; + text += method->get_instance_class(); + text += "."; + text += method->get_name(); + text += "("; + + for (int i = 0; i < argc; i++) { + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + text += ")"; + + incr += 4 + argc; + } break; case OPCODE_CALL_PTRCALL_NO_RETURN: { text += "call-ptrcall (no return) "; @@ -770,6 +792,25 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr = 3 + captures_count; } break; + case OPCODE_CREATE_SELF_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 self 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]); @@ -968,7 +1009,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { DISASSEMBLE_TYPE_ADJUST(QUATERNION); DISASSEMBLE_TYPE_ADJUST(AABB); DISASSEMBLE_TYPE_ADJUST(BASIS); - DISASSEMBLE_TYPE_ADJUST(TRANSFORM); + DISASSEMBLE_TYPE_ADJUST(TRANSFORM3D); DISASSEMBLE_TYPE_ADJUST(COLOR); DISASSEMBLE_TYPE_ADJUST(STRING_NAME); DISASSEMBLE_TYPE_ADJUST(NODE_PATH); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index ec01c19295..0197bf9ea3 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -43,6 +43,7 @@ #include "core/config/project_settings.h" #include "editor/editor_file_system.h" #include "editor/editor_settings.h" +#include "editor/script_templates/templates.gen.h" #endif void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { @@ -55,68 +56,46 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("\"\"\" \"\"\""); } -String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const { - String processed_template = p_template; - -#ifdef TOOLS_ENABLED - if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) { - processed_template = processed_template.replace("%INT_TYPE%", ": int"); - processed_template = processed_template.replace("%STRING_TYPE%", ": String"); - processed_template = processed_template.replace("%FLOAT_TYPE%", ": float"); - processed_template = processed_template.replace("%VOID_RETURN%", " -> void"); - } else { - processed_template = processed_template.replace("%INT_TYPE%", ""); - processed_template = processed_template.replace("%STRING_TYPE%", ""); - processed_template = processed_template.replace("%FLOAT_TYPE%", ""); - processed_template = processed_template.replace("%VOID_RETURN%", ""); - } -#else - processed_template = processed_template.replace("%INT_TYPE%", ""); - processed_template = processed_template.replace("%STRING_TYPE%", ""); - processed_template = processed_template.replace("%FLOAT_TYPE%", ""); - processed_template = processed_template.replace("%VOID_RETURN%", ""); -#endif - - processed_template = processed_template.replace("%BASE%", p_base_class_name); - processed_template = processed_template.replace("%TS%", _get_indentation()); - - return processed_template; +bool GDScriptLanguage::is_using_templates() { + return true; } -Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - String _template = "extends %BASE%\n" - "\n" - "\n" - "# Declare member variables here. Examples:\n" - "# var a%INT_TYPE% = 2\n" - "# var b%STRING_TYPE% = \"text\"\n" - "\n" - "\n" - "# Called when the node enters the scene tree for the first time.\n" - "func _ready()%VOID_RETURN%:\n" - "%TS%pass # Replace with function body.\n" - "\n" - "\n" - "# Called every frame. 'delta' is the elapsed time since the previous frame.\n" - "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n" - "#%TS%pass\n"; - - _template = _get_processed_template(_template, p_base_class_name); - +Ref<Script> GDScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { Ref<GDScript> script; script.instantiate(); - script->set_source_code(_template); - + String processed_template = p_template; + bool type_hints = false; +#ifdef TOOLS_ENABLED + type_hints = EDITOR_GET("text_editor/completion/add_type_hints"); +#endif + if (!type_hints) { + processed_template = processed_template.replace(": int", "") + .replace(": String", "") + .replace(": Array[String]", "") + .replace(": float", "") + .replace(":=", "=") + .replace(" -> String", "") + .replace(" -> int", "") + .replace(" -> void", ""); + } + + processed_template = processed_template.replace("_BASE_", p_base_class_name) + .replace("_CLASS_", p_class_name) + .replace("_TS_", _get_indentation()); + script->set_source_code(processed_template); return script; } -bool GDScriptLanguage::is_using_templates() { - return true; -} - -void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { - String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name); - p_script->set_source_code(_template); +Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) { + Vector<ScriptLanguage::ScriptTemplate> templates; +#ifdef TOOLS_ENABLED + for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) { + if (TEMPLATES[i].inherit == p_object) { + templates.append(TEMPLATES[i]); + } + } +#endif + return templates; } static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, Map<int, String> &r_funcs) { @@ -236,7 +215,7 @@ Script *GDScriptLanguage::create_script() const { /* DEBUGGER FUNCTIONS */ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) { - //break because of parse error + // break because of parse error if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) { _debug_parse_err_line = p_line; @@ -506,10 +485,93 @@ struct GDScriptCompletionIdentifier { const GDScriptParser::ExpressionNode *assigned_expression = nullptr; }; +// LOCATION METHODS +// These methods are used to populate the `CodeCompletionOption::location` integer. +// For these methods, the location is based on the depth in the inheritance chain that the property +// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D +// will have a "better" (lower) location "score" than a property that is found on CanvasItem. + +static int _get_property_location(StringName p_class, StringName p_property) { + if (!ClassDB::has_property(p_class, p_property)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_property(class_test, p_property, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_constant_location(StringName p_class, StringName p_constant) { + if (!ClassDB::has_integer_constant(p_class, p_constant)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_integer_constant(class_test, p_constant, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_signal_location(StringName p_class, StringName p_signal) { + if (!ClassDB::has_signal(p_class, p_signal)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_signal(class_test, p_signal, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_method_location(StringName p_class, StringName p_method) { + if (!ClassDB::has_method(p_class, p_method)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_method(class_test, p_method, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) { + if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::get_integer_constant_enum(class_test, p_enum_constant, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +// END LOCATION METHODS + 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; - if (enum_name.find(".") == -1) { + if (!enum_name.contains(".")) { return enum_name; } return enum_name.get_slice(".", 1); @@ -603,12 +665,50 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio if (par->default_value) { String def_val = "<unknown>"; - if (par->default_value->type == GDScriptParser::Node::LITERAL) { - const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value); - def_val = literal->value.get_construct_string(); - } else if (par->default_value->type == GDScriptParser::Node::IDENTIFIER) { - const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value); - def_val = id->name.operator String(); + switch (par->default_value->type) { + case GDScriptParser::Node::LITERAL: { + const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value); + def_val = literal->value.get_construct_string(); + } break; + case GDScriptParser::Node::IDENTIFIER: { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value); + def_val = id->name.operator String(); + } break; + case GDScriptParser::Node::CALL: { + const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(par->default_value); + if (call->is_constant && call->reduced) { + def_val = call->function_name.operator String() + call->reduced_value.operator String(); + } + } break; + case GDScriptParser::Node::ARRAY: { + const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->default_value); + if (arr->is_constant && arr->reduced) { + def_val = arr->reduced_value.operator String(); + } + } break; + case GDScriptParser::Node::DICTIONARY: { + const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->default_value); + if (dict->is_constant && dict->reduced) { + def_val = dict->reduced_value.operator String(); + } + } break; + case GDScriptParser::Node::SUBSCRIPT: { + const GDScriptParser::SubscriptNode *sub = static_cast<const GDScriptParser::SubscriptNode *>(par->default_value); + if (sub->is_constant) { + if (sub->datatype.kind == GDScriptParser::DataType::ENUM) { + def_val = sub->get_datatype().to_string(); + } else if (sub->reduced) { + const Variant::Type vt = sub->reduced_value.get_type(); + if (vt == Variant::Type::NIL || vt == Variant::Type::FLOAT || vt == Variant::Type::INT || vt == Variant::Type::STRING || vt == Variant::Type::STRING_NAME || vt == Variant::Type::BOOL || vt == Variant::Type::NODE_PATH) { + def_val = sub->reduced_value.operator String(); + } else { + def_val = sub->get_datatype().to_string() + sub->reduced_value.operator String(); + } + } + } + } break; + default: + break; } arghint += " = " + def_val; } @@ -622,11 +722,11 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio return arghint; } -static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) { +static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptLanguage::CodeCompletionOption> &r_list) { const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; for (int i = 0; i < p_dir->get_file_count(); i++) { - ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH); + ScriptLanguage::CodeCompletionOption option(p_dir->get_file_path(i), ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH); option.insert_text = option.display.quote(quote_style); r_list.insert(option.display, option); } @@ -636,29 +736,29 @@ static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String } } -static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptCodeCompletionOption> &r_result) { - if (p_annotation->name == "@export_range") { +static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { + if (p_annotation->name == SNAME("@export_range")) { if (p_argument == 3 || p_argument == 4) { // Slider hint. - ScriptCodeCompletionOption slider1("or_greater", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption slider1("or_greater", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); slider1.insert_text = slider1.display.quote(p_quote_style); r_result.insert(slider1.display, slider1); - ScriptCodeCompletionOption slider2("or_lesser", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption slider2("or_lesser", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); slider2.insert_text = slider2.display.quote(p_quote_style); r_result.insert(slider2.display, slider2); } - } else if (p_annotation->name == "@export_exp_easing") { + } else if (p_annotation->name == SNAME("@export_exp_easing")) { if (p_argument == 0 || p_argument == 1) { // Easing hint. - ScriptCodeCompletionOption hint1("attenuation", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption hint1("attenuation", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); hint1.insert_text = hint1.display.quote(p_quote_style); r_result.insert(hint1.display, hint1); - ScriptCodeCompletionOption hint2("inout", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption hint2("inout", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); hint2.insert_text = hint2.display.quote(p_quote_style); r_result.insert(hint2.display, hint2); } - } else if (p_annotation->name == "@export_node_path") { - ScriptCodeCompletionOption node("Node", ScriptCodeCompletionOption::KIND_CLASS); + } else if (p_annotation->name == SNAME("@export_node_path")) { + ScriptLanguage::CodeCompletionOption node("Node", ScriptLanguage::CODE_COMPLETION_KIND_CLASS); r_result.insert(node.display, node); List<StringName> node_types; ClassDB::get_inheriters_from_class("Node", &node_types); @@ -666,18 +766,38 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a if (!ClassDB::is_class_exposed(E)) { continue; } - ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + r_result.insert(option.display, option); + } + } else if (p_annotation->name == SNAME("@warning_ignore")) { + for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { + ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); + r_result.insert(warning.display, warning); + } + } +} + +static void _find_built_in_variants(Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) { + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) { + ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + r_result.insert(option.display, option); + } else { + ScriptLanguage::CodeCompletionOption option(Variant::get_type_name(Variant::Type(i)), ScriptLanguage::CODE_COMPLETION_KIND_CLASS); r_result.insert(option.display, option); } } } -static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) { +static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { + // Built-in Variant Types + _find_built_in_variants(r_result, true); + List<StringName> native_types; ClassDB::get_class_list(&native_types); for (const StringName &E : native_types) { if (ClassDB::is_class_exposed(E) && !Engine::get_singleton()->has_singleton(E)) { - ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); r_result.insert(option.display, option); } } @@ -688,7 +808,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio List<StringName> enums; ClassDB::get_enum_list(p_context.current_class->base_type.native_type, &enums); for (const StringName &E : enums) { - ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_ENUM); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_ENUM); r_result.insert(option.display, option); } } @@ -699,18 +819,18 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio const GDScriptParser::ClassNode::Member &member = current->members[i]; switch (member.type) { case GDScriptParser::ClassNode::Member::CLASS: { - ScriptCodeCompletionOption option(member.m_class->identifier->name, ScriptCodeCompletionOption::KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL); r_result.insert(option.display, option); } break; case GDScriptParser::ClassNode::Member::ENUM: { if (!p_inherit_only) { - ScriptCodeCompletionOption option(member.m_enum->identifier->name, ScriptCodeCompletionOption::KIND_ENUM); + ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, ScriptLanguage::LOCATION_LOCAL); r_result.insert(option.display, option); } } break; case GDScriptParser::ClassNode::Member::CONSTANT: { if (member.constant->get_datatype().is_meta_type && p_context.current_class->outer != nullptr) { - ScriptCodeCompletionOption option(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL); r_result.insert(option.display, option); } } break; @@ -726,7 +846,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); for (const StringName &E : global_classes) { - ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE); r_result.insert(option.display, option); } @@ -737,19 +857,19 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") { continue; } - ScriptCodeCompletionOption option(info.name, ScriptCodeCompletionOption::KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE); r_result.insert(option.display, option); } } -static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptCodeCompletionOption> &r_result) { +static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { for (int i = 0; i < p_suite->locals.size(); i++) { - ScriptCodeCompletionOption option; + ScriptLanguage::CodeCompletionOption option; if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) { - option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, ScriptLanguage::LOCATION_LOCAL); option.default_value = p_suite->locals[i].constant->initializer->reduced_value; } else { - option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE); + option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE, ScriptLanguage::LOCATION_LOCAL); } r_result.insert(option.display, option); } @@ -758,24 +878,26 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, } } -static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth); +static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth); -static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) { +static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT); if (!p_parent_only) { bool outer = false; const GDScriptParser::ClassNode *clss = p_class; + int classes_processed = 0; while (clss) { for (int i = 0; i < clss->members.size(); i++) { + const int location = (classes_processed + p_recursion_depth) | ScriptLanguage::LOCATION_PARENT_MASK; const GDScriptParser::ClassNode::Member &member = clss->members[i]; - ScriptCodeCompletionOption option; + ScriptLanguage::CodeCompletionOption option; switch (member.type) { case GDScriptParser::ClassNode::Member::VARIABLE: if (p_only_functions || outer || (p_static)) { continue; } - option = ScriptCodeCompletionOption(member.variable->identifier->name, ScriptCodeCompletionOption::KIND_MEMBER); + option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); break; case GDScriptParser::ClassNode::Member::CONSTANT: if (p_only_functions) { @@ -784,7 +906,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (r_result.has(member.constant->identifier->name)) { continue; } - option = ScriptCodeCompletionOption(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); if (member.constant->initializer) { option.default_value = member.constant->initializer->reduced_value; } @@ -793,25 +915,25 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (p_only_functions) { continue; } - option = ScriptCodeCompletionOption(member.m_class->identifier->name, ScriptCodeCompletionOption::KIND_CLASS); + option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, location); break; case GDScriptParser::ClassNode::Member::ENUM_VALUE: if (p_only_functions) { continue; } - option = ScriptCodeCompletionOption(member.enum_value.identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); break; case GDScriptParser::ClassNode::Member::ENUM: if (p_only_functions) { continue; } - option = ScriptCodeCompletionOption(member.m_enum->identifier->name, ScriptCodeCompletionOption::KIND_ENUM); + option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location); break; case GDScriptParser::ClassNode::Member::FUNCTION: if (outer || (p_static && !member.function->is_static) || member.function->identifier->name.operator String().begins_with("@")) { continue; } - option = ScriptCodeCompletionOption(member.function->identifier->name, ScriptCodeCompletionOption::KIND_FUNCTION); + option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); if (member.function->parameters.size() > 0) { option.insert_text += "("; } else { @@ -822,7 +944,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (p_only_functions || outer) { continue; } - option = ScriptCodeCompletionOption(member.signal->identifier->name, ScriptCodeCompletionOption::KIND_SIGNAL); + option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); break; case GDScriptParser::ClassNode::Member::UNDEFINED: break; @@ -831,6 +953,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, } outer = true; clss = clss->outer; + classes_processed++; } } @@ -842,14 +965,14 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, _find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1); } -static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) { +static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT); GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { - ScriptCodeCompletionOption option("new", ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL); option.insert_text += "("; r_result.insert(option.display, option); } @@ -869,21 +992,24 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<PropertyInfo> members; scr->get_script_property_list(&members); for (const PropertyInfo &E : members) { - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); + int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.class_name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); } } Map<StringName, Variant> constants; scr->get_constants(&constants); for (const KeyValue<StringName, Variant> &E : constants) { - ScriptCodeCompletionOption option(E.key.operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key); + ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); r_result.insert(option.display, option); } List<MethodInfo> signals; scr->get_script_signal_list(&signals); for (const MethodInfo &E : signals) { - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_SIGNAL); + int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); r_result.insert(option.display, option); } } @@ -894,7 +1020,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (E.name.begins_with("@")) { continue; } - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); if (E.arguments.size()) { option.insert_text += "("; } else { @@ -924,7 +1051,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<String> constants; ClassDB::get_integer_constant_list(type, &constants); for (const String &E : constants) { - ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT); + int location = p_recursion_depth + _get_constant_location(type, StringName(E)); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); r_result.insert(option.display, option); } @@ -935,33 +1063,36 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { continue; } - if (E.name.find("/") != -1) { + if (E.name.contains("/")) { continue; } - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); + int location = p_recursion_depth + _get_property_location(type, E.class_name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); } } } - if (!_static || Engine::get_singleton()->has_singleton(type)) { - List<MethodInfo> methods; - bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize(); - ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters); - for (const MethodInfo &E : methods) { - if (E.name.begins_with("_")) { - continue; - } - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E.arguments.size()) { - option.insert_text += "("; - } else { - option.insert_text += "()"; - } - r_result.insert(option.display, option); + bool only_static = _static && !Engine::get_singleton()->has_singleton(type); + + List<MethodInfo> methods; + ClassDB::get_method_list(type, &methods, false, true); + for (const MethodInfo &E : methods) { + if (only_static && (E.flags & METHOD_FLAG_STATIC) == 0) { + continue; + } + if (E.name.begins_with("_")) { + continue; + } + int location = p_recursion_depth + _get_method_location(type, E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); + if (E.arguments.size()) { + option.insert_text += "("; + } else { + option.insert_text += "()"; } + r_result.insert(option.display, option); } - return; } break; case GDScriptParser::DataType::BUILTIN: { @@ -981,8 +1112,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } for (const PropertyInfo &E : members) { - if (String(E.name).find("/") == -1) { - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); + if (!String(E.name).contains("/")) { + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); r_result.insert(option.display, option); } } @@ -991,7 +1122,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<MethodInfo> methods; tmp.get_method_list(&methods); for (const MethodInfo &E : methods) { - ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); if (E.arguments.size()) { option.insert_text += "("; } else { @@ -1009,7 +1140,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } } -static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) { +static void _find_identifiers(const GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { if (!p_only_functions && p_context.current_suite) { // This includes function parameters, since they are also locals. _find_identifiers_in_suite(p_context.current_suite, r_result); @@ -1024,7 +1155,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool for (const StringName &E : functions) { MethodInfo function = GDScriptUtilityFunctions::get_function_info(E); - ScriptCodeCompletionOption option(String(E), ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(String(E), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) { option.insert_text += "("; } else { @@ -1037,17 +1168,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool return; } - static const char *_type_names[Variant::VARIANT_MAX] = { - "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" - }; - static_assert((sizeof(_type_names) / sizeof(*_type_names)) == Variant::VARIANT_MAX, "Completion for builtin types is incomplete"); - - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - ScriptCodeCompletionOption option(_type_names[i], ScriptCodeCompletionOption::KIND_CLASS); - r_result.insert(option.display, option); - } + _find_built_in_variants(r_result); static const char *_keywords[] = { "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super", @@ -1057,7 +1178,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool const char **kw = _keywords; while (*kw) { - ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption option(*kw, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); r_result.insert(option.display, option); kw++; } @@ -1070,7 +1191,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool const char **kws = _keywords_with_space; while (*kws) { - ScriptCodeCompletionOption option(*kws, ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption option(*kws, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); option.insert_text += " "; r_result.insert(option.display, option); kws++; @@ -1083,7 +1204,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool const char **kwa = _keywords_with_args; while (*kwa) { - ScriptCodeCompletionOption option(*kwa, ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(*kwa, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); option.insert_text += "("; r_result.insert(option.display, option); kwa++; @@ -1093,7 +1214,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool Variant::get_utility_function_list(&utility_func_names); for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(E->get(), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); option.insert_text += "("; r_result.insert(option.display, option); } @@ -1103,17 +1224,17 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool if (!E.value().is_singleton) { continue; } - ScriptCodeCompletionOption option(E.key(), ScriptCodeCompletionOption::KIND_CONSTANT); + ScriptLanguage::CodeCompletionOption option(E.key(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); r_result.insert(option.display, option); } // Native classes and global constants. for (const KeyValue<StringName, int> &E : GDScriptLanguage::get_singleton()->get_global_map()) { - ScriptCodeCompletionOption option; + ScriptLanguage::CodeCompletionOption option; if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) { - option = ScriptCodeCompletionOption(E.key.operator String(), ScriptCodeCompletionOption::KIND_CLASS); + option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CLASS); } else { - option = ScriptCodeCompletionOption(E.key.operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); } r_result.insert(option.display, option); } @@ -1179,9 +1300,34 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); +static bool _is_expression_named_identifier(const GDScriptParser::ExpressionNode *p_expression, const StringName &p_name) { + if (p_expression) { + switch (p_expression->type) { + case GDScriptParser::Node::IDENTIFIER: { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression); + if (id->name == p_name) { + return true; + } + } break; + case GDScriptParser::Node::CAST: { + const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression); + return _is_expression_named_identifier(cn->operand, p_name); + } break; + default: + break; + } + } + + return false; +} + static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) { bool found = false; + if (p_expression == nullptr) { + return false; + } + if (p_expression->is_constant) { // Already has a value, so just use that. r_type = _type_from_variant(p_expression->reduced_value); @@ -1361,7 +1507,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, Object *baseptr = base.value; - if (all_is_const && String(call->function_name) == "get_node" && ClassDB::is_parent_class(native_type.native_type, "Node") && args.size()) { + if (all_is_const && call->function_name == SNAME("get_node") && ClassDB::is_parent_class(native_type.native_type, SNAME("Node")) && args.size()) { String arg1 = args[0]; if (arg1.begins_with("/root/")) { String which = arg1.get_slice("/", 2); @@ -1383,8 +1529,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } if (!script.ends_with(".gd")) { - //not a script, try find the script anyway, - //may have some success + // not a script, try find the script anyway, + // may have some success script = script.get_basename() + ".gd"; } @@ -1881,6 +2027,14 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & return true; } else if (init->start_line == p_context.current_line) { return false; + // Detects if variable is assigned to itself + } else if (_is_expression_named_identifier(init, member.variable->identifier->name)) { + if (member.variable->initializer->get_datatype().is_set()) { + r_type.type = member.variable->initializer->get_datatype(); + } else if (member.variable->get_datatype().is_set() && !member.variable->get_datatype().is_variant()) { + r_type.type = member.variable->get_datatype(); + } + return true; } else if (_guess_expression_type(p_context, init, r_type)) { return true; } else if (init->get_datatype().is_set() && !init->get_datatype().is_variant()) { @@ -2062,7 +2216,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex GDScriptParser::DataType base_type = p_base.type; bool is_static = base_type.is_meta_type; - if (is_static && p_method == "new") { + if (is_static && p_method == SNAME("new")) { r_type.type = base_type; r_type.type.is_meta_type = false; r_type.type.is_constant = false; @@ -2158,20 +2312,20 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex return false; } -static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, Map<String, ScriptCodeCompletionOption> &r_result) { - if (p_enum_hint.find(".") == -1) { +static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { + if (!p_enum_hint.contains(".")) { // Global constant or in the current class. StringName current_enum = p_enum_hint; if (p_context.current_class && p_context.current_class->has_member(current_enum) && p_context.current_class->get_member(current_enum).type == GDScriptParser::ClassNode::Member::ENUM) { const GDScriptParser::EnumNode *_enum = p_context.current_class->get_member(current_enum).m_enum; for (int i = 0; i < _enum->values.size(); i++) { - ScriptCodeCompletionOption option(_enum->values[i].identifier->name, ScriptCodeCompletionOption::KIND_ENUM); + ScriptLanguage::CodeCompletionOption option(_enum->values[i].identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM); r_result.insert(option.display, option); } } else { for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { if (CoreConstants::get_global_constant_enum(i) == current_enum) { - ScriptCodeCompletionOption option(CoreConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM); + ScriptLanguage::CodeCompletionOption option(CoreConstants::get_global_constant_name(i), ScriptLanguage::CODE_COMPLETION_KIND_ENUM); r_result.insert(option.display, option); } } @@ -2188,13 +2342,14 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); for (const StringName &E : enum_constants) { String candidate = class_name + "." + E; - ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM); + int location = _get_enum_constant_location(class_name, E); + ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location); r_result.insert(option.display, option); } } } -static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptCodeCompletionOption> &r_result, String &r_arghint) { +static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) { Variant base = p_base.value; GDScriptParser::DataType base_type = p_base.type; @@ -2235,7 +2390,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (opt.is_quoted()) { opt = opt.unquote().quote(quote_style); // Handle user preference. } - ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); r_result.insert(option.display, option); } } @@ -2251,7 +2406,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_arghint = _make_arguments_hint(info, p_argidx); } - if (p_argidx == 0 && ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node")) { + if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (p_method == SNAME("get_node") || p_method == SNAME("has_node"))) { // Get autoloads List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); @@ -2262,13 +2417,13 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c continue; } String name = s.get_slice("/", 1); - ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH); + ScriptLanguage::CodeCompletionOption option("/root/" + name, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH); option.insert_text = option.display.quote(quote_style); r_result.insert(option.display, option); } } - if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, "InputEvent") && p_method.operator String().find("action") != -1) { + if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && p_method.operator String().contains("action")) { // Get input actions List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); @@ -2278,7 +2433,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c continue; } String name = s.get_slice("/", 1); - ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT); + ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); option.insert_text = option.display.quote(quote_style); r_result.insert(option.display, option); } @@ -2313,7 +2468,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } } -static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { +static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { if (p_call->type == GDScriptParser::Node::PRELOAD) { if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result); @@ -2343,7 +2498,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_arghint = _make_arguments_hint(info, p_argidx); return; } else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) { - // Complete constructor + // Complete constructor. List<MethodInfo> constructors; Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors); @@ -2369,6 +2524,32 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) { const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee); + if (subscript->base != nullptr && subscript->base->type == GDScriptParser::Node::IDENTIFIER) { + const GDScriptParser::IdentifierNode *base_identifier = static_cast<const GDScriptParser::IdentifierNode *>(subscript->base); + + Variant::Type method_type = GDScriptParser::get_builtin_type(base_identifier->name); + if (method_type < Variant::VARIANT_MAX) { + Variant v; + Callable::CallError err; + Variant::construct(method_type, v, nullptr, 0, err); + if (err.error != Callable::CallError::CALL_OK) { + return; + } + List<MethodInfo> methods; + v.get_method_list(&methods); + + for (MethodInfo &E : methods) { + if (p_argidx >= E.arguments.size()) { + continue; + } + if (E.name == call->function_name) { + r_arghint += _make_arguments_hint(E, p_argidx); + return; + } + } + } + } + if (subscript->is_attribute) { GDScriptCompletionIdentifier ci; if (_guess_expression_type(p_context, subscript->base, ci)) { @@ -2392,7 +2573,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<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; GDScriptParser parser; @@ -2402,7 +2583,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c analyzer.analyze(); r_forced = false; - Map<String, ScriptCodeCompletionOption> options; + Map<String, ScriptLanguage::CodeCompletionOption> options; GDScriptParser::CompletionContext completion_context = parser.get_completion_context(); completion_context.base = p_owner; @@ -2415,7 +2596,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<MethodInfo> annotations; parser.get_annotation_list(&annotations); for (const MethodInfo &E : annotations) { - ScriptCodeCompletionOption option(E.name.substr(1), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption option(E.name.substr(1), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); if (E.arguments.size() > 0) { option.insert_text += "("; } @@ -2431,17 +2612,36 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c _find_annotation_arguments(annotation, completion_context.current_argument, quote_style, options); r_forced = true; } break; - case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { - List<StringName> constants; - Variant::get_constants_for_type(completion_context.builtin_type, &constants); - for (const StringName &E : constants) { - ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT); - bool valid = false; - Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid); - if (valid) { - option.default_value = default_value; + case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: { + // Constants. + { + List<StringName> constants; + Variant::get_constants_for_type(completion_context.builtin_type, &constants); + for (const StringName &E : constants) { + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + bool valid = false; + Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid); + if (valid) { + option.default_value = default_value; + } + options.insert(option.display, option); + } + } + // Methods. + { + List<StringName> methods; + Variant::get_builtin_method_list(completion_context.builtin_type, &methods); + for (const StringName &E : methods) { + if (Variant::is_builtin_method_static(completion_context.builtin_type, E)) { + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + if (Variant::get_builtin_method_argument_count(completion_context.builtin_type, E) > 0 || Variant::is_builtin_method_vararg(completion_context.builtin_type, E)) { + option.insert_text += "("; + } else { + option.insert_text += "()"; + } + options.insert(option.display, option); + } } - options.insert(option.display, option); } } break; case GDScriptParser::COMPLETION_INHERIT_TYPE: { @@ -2449,7 +2649,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_forced = true; } break; case GDScriptParser::COMPLETION_TYPE_NAME_OR_VOID: { - ScriptCodeCompletionOption option("void", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption option("void", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); options.insert(option.display, option); } [[fallthrough]]; @@ -2459,16 +2659,16 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } break; case GDScriptParser::COMPLETION_PROPERTY_DECLARATION_OR_TYPE: { _list_available_types(false, completion_context, options); - ScriptCodeCompletionOption get("get", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption get("get", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); options.insert(get.display, get); - ScriptCodeCompletionOption set("set", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption set("set", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); options.insert(set.display, set); r_forced = true; } break; case GDScriptParser::COMPLETION_PROPERTY_DECLARATION: { - ScriptCodeCompletionOption get("get", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption get("get", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); options.insert(get.display, get); - ScriptCodeCompletionOption set("set", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption set("set", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); options.insert(set.display, set); r_forced = true; } break; @@ -2484,7 +2684,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (member.function->is_static) { continue; } - ScriptCodeCompletionOption option(member.function->identifier->name, ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); options.insert(option.display, option); } r_forced = true; @@ -2616,7 +2816,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c ClassDB::get_virtual_methods(class_name, &virtual_methods); for (const MethodInfo &mi : virtual_methods) { String method_hint = mi.name; - if (method_hint.find(":") != -1) { + if (method_hint.contains(":")) { method_hint = method_hint.get_slice(":", 0); } method_hint += "("; @@ -2627,7 +2827,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c method_hint += ", "; } String arg = mi.arguments[i].name; - if (arg.find(":") != -1) { + if (arg.contains(":")) { arg = arg.substr(0, arg.find(":")); } method_hint += arg; @@ -2654,7 +2854,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } method_hint += ":"; - ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(method_hint, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); options.insert(option.display, option); } } break; @@ -2677,7 +2877,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (!opt.replace("/", "_").is_valid_identifier()) { opt = opt.quote(quote_style); // Handle user preference. } - ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); + ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH); options.insert(option.display, option); } @@ -2686,7 +2886,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { String path = "/root/" + E.key(); - ScriptCodeCompletionOption option(path.quote(quote_style), ScriptCodeCompletionOption::KIND_NODE_PATH); + ScriptLanguage::CodeCompletionOption option(path.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH); options.insert(option.display, option); } } @@ -2699,7 +2899,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } break; } - for (const KeyValue<String, ScriptCodeCompletionOption> &E : options) { + for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &E : options) { r_options->push_back(E.value); } @@ -2708,7 +2908,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c #else -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<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { return OK; } @@ -2719,10 +2919,10 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path String GDScriptLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", false); + bool use_space_indentation = EDITOR_GET("text_editor/behavior/indent/type"); if (use_space_indentation) { - int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4); + int indent_size = EDITOR_GET("text_editor/behavior/indent/size"); String space_indent = ""; for (int i = 0; i < indent_size; i++) { @@ -2770,7 +2970,7 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t } if (indent_stack.size() && indent_stack.back()->get() != tc) { - indent_stack.push_back(tc); //this is not right but gets the job done + indent_stack.push_back(tc); // this is not right but gets the job done } } @@ -2807,7 +3007,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co case GDScriptParser::DataType::CLASS: { if (base_type.class_type) { if (base_type.class_type->has_member(p_symbol)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION; r_result.location = base_type.class_type->get_member(p_symbol).get_line(); r_result.class_path = base_type.script_path; r_result.script = GDScriptCache::get_shallow_script(r_result.class_path); @@ -2821,7 +3021,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co if (scr.is_valid()) { int line = scr->get_member_line(p_symbol); if (line >= 0) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION; r_result.location = line; r_result.script = scr; return OK; @@ -2845,7 +3045,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } if (ClassDB::has_method(class_name, p_symbol, true)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; return OK; @@ -2855,7 +3055,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co ClassDB::get_virtual_methods(class_name, &virtual_methods, true); for (const MethodInfo &E : virtual_methods) { if (E.name == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; return OK; @@ -2864,7 +3064,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true); if (enum_name != StringName()) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM; r_result.class_name = base_type.native_type; r_result.class_member = enum_name; return OK; @@ -2874,7 +3074,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co ClassDB::get_integer_constant_list(class_name, &constants, true); for (const String &E : constants) { if (E == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; return OK; @@ -2882,7 +3082,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } if (ClassDB::has_property(class_name, p_symbol, true)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; return OK; @@ -2899,14 +3099,14 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co base_type.kind = GDScriptParser::DataType::UNRESOLVED; if (Variant::has_constant(base_type.builtin_type, p_symbol)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; r_result.class_name = Variant::get_type_name(base_type.builtin_type); r_result.class_member = p_symbol; return OK; } Variant v; - REF v_ref; + Ref<RefCounted> v_ref; if (base_type.builtin_type == Variant::OBJECT) { v_ref.instantiate(); v = v_ref; @@ -2919,7 +3119,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } if (v.has_method(p_symbol)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; r_result.class_name = Variant::get_type_name(base_type.builtin_type); r_result.class_member = p_symbol; return OK; @@ -2928,7 +3128,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co bool valid = false; v.get(p_symbol, &valid); if (valid) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY; r_result.class_name = Variant::get_type_name(base_type.builtin_type); r_result.class_member = p_symbol; return OK; @@ -2946,7 +3146,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co ::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; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = p_symbol; return OK; } @@ -2954,21 +3154,21 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co for (int i = 0; i < Variant::VARIANT_MAX; i++) { Variant::Type t = Variant::Type(i); if (Variant::get_type_name(t) == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = Variant::get_type_name(t); return OK; } } if (GDScriptUtilityFunctions::function_exists(p_symbol)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; r_result.class_name = "@GDScript"; r_result.class_member = p_symbol; return OK; } if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; r_result.class_name = "@GDScript"; r_result.class_member = p_symbol; return OK; @@ -2985,7 +3185,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co bool success = false; ClassDB::get_integer_constant(context.current_class->extends[0], p_symbol, &success); if (success) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; r_result.class_name = context.current_class->extends[0]; r_result.class_member = p_symbol; return OK; @@ -2995,11 +3195,21 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co bool is_function = false; switch (context.type) { - case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; - r_result.class_name = Variant::get_type_name(context.builtin_type); - r_result.class_member = p_symbol; - return OK; + case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: { + if (!Variant::has_builtin_method(context.builtin_type, StringName(p_symbol))) { + // A constant. + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; + r_result.class_name = Variant::get_type_name(context.builtin_type); + r_result.class_member = p_symbol; + return OK; + } + // A method. + GDScriptParser::DataType base_type; + base_type.kind = GDScriptParser::DataType::BUILTIN; + base_type.builtin_type = context.builtin_type; + if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) { + return OK; + } } break; case GDScriptParser::COMPLETION_SUPER_METHOD: case GDScriptParser::COMPLETION_METHOD: { @@ -3024,7 +3234,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co const GDScriptParser::SuiteNode *suite = context.current_suite; while (suite) { if (suite->has_local(p_symbol)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION; r_result.location = suite->get_local(p_symbol).start_line; return OK; } @@ -3049,7 +3259,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } if (FileAccess::exists(script)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION; r_result.location = 0; r_result.script = ResourceLoader::load(script); return OK; @@ -3065,10 +3275,10 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co Object *obj = value; if (obj) { if (Object::cast_to<GDScriptNativeClass>(obj)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = Object::cast_to<GDScriptNativeClass>(obj)->get_name(); } else { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = obj->get_class(); } @@ -3085,18 +3295,18 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co // Otherwise these codes would work StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true); if (enumName != nullptr) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM; r_result.class_name = "@GlobalScope"; r_result.class_member = enumName; return OK; } else { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT; r_result.class_name = "@GlobalScope"; r_result.class_member = p_symbol; return OK; }*/ - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE; r_result.class_name = "@GlobalScope"; r_result.class_member = p_symbol; return OK; @@ -3105,7 +3315,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co List<StringName> utility_functions; Variant::get_utility_function_list(&utility_functions); if (utility_functions.find(p_symbol) != nullptr) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE; + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE; r_result.class_name = "@GlobalScope"; r_result.class_member = p_symbol; return OK; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index a3f0c7dfef..3d708955ed 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -95,7 +95,7 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String int oc = 0; Map<StringName, _GDFKC> sdmap; for (const StackDebug &sd : stack_debug) { - if (sd.line > p_line) { + if (sd.line >= p_line) { break; } @@ -248,7 +248,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { // If the return value is a GDScriptFunctionState reference, // then the function did await again after resuming. - if (ret.is_ref()) { + if (ret.is_ref_counted()) { GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret); if (gdfs && gdfs->function == function) { completed = false; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index e1ed71a268..ba0d51c5cc 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -259,6 +259,7 @@ public: OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND_RET, OPCODE_CALL_BUILTIN_STATIC, + OPCODE_CALL_NATIVE_STATIC, // ptrcall have one instruction per return type. OPCODE_CALL_PTRCALL_NO_RETURN, OPCODE_CALL_PTRCALL_BOOL, @@ -298,6 +299,7 @@ public: OPCODE_AWAIT, OPCODE_AWAIT_RESUME, OPCODE_CREATE_LAMBDA, + OPCODE_CREATE_SELF_LAMBDA, OPCODE_JUMP, OPCODE_JUMP_IF, OPCODE_JUMP_IF_NOT, @@ -364,7 +366,7 @@ public: OPCODE_TYPE_ADJUST_QUATERNION, OPCODE_TYPE_ADJUST_AABB, OPCODE_TYPE_ADJUST_BASIS, - OPCODE_TYPE_ADJUST_TRANSFORM, + OPCODE_TYPE_ADJUST_TRANSFORM3D, OPCODE_TYPE_ADJUST_COLOR, OPCODE_TYPE_ADJUST_STRING_NAME, OPCODE_TYPE_ADJUST_NODE_PATH, @@ -502,6 +504,8 @@ private: List<StackDebug> stack_debug; + Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type); + _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; diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp index 0bc109b6e1..c43fa12c8c 100644 --- a/modules/gdscript/gdscript_lambda_callable.cpp +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -93,3 +93,81 @@ GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptF h = (uint32_t)hash_djb2_one_64((uint64_t)this); } + +bool GDScriptLambdaSelfCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + // Lambda callables are only compared by reference. + return p_a == p_b; +} + +bool GDScriptLambdaSelfCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { + // Lambda callables are only compared by reference. + return p_a < p_b; +} + +uint32_t GDScriptLambdaSelfCallable::hash() const { + return h; +} + +String GDScriptLambdaSelfCallable::get_as_text() const { + if (function->get_name() != StringName()) { + return function->get_name().operator String() + "(lambda)"; + } + return "(anonymous lambda)"; +} + +CallableCustom::CompareEqualFunc GDScriptLambdaSelfCallable::get_compare_equal_func() const { + return compare_equal; +} + +CallableCustom::CompareLessFunc GDScriptLambdaSelfCallable::get_compare_less_func() const { + return compare_less; +} + +ObjectID GDScriptLambdaSelfCallable::get_object() const { + return object->get_instance_id(); +} + +void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { +#ifdef DEBUG_ENABLED + if (object->get_script_instance() == nullptr || object->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) { + ERR_PRINT("Trying to call a lambda with an invalid instance."); + r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return; + } +#endif + + 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(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error); + r_call_error.argument -= captures_amount; + } else { + r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), p_arguments, p_argcount, r_call_error); + } +} + +GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) { + reference = p_self; + object = p_self.ptr(); + function = p_function; + captures = p_captures; + + h = (uint32_t)hash_djb2_one_64((uint64_t)this); +} + +GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) { + object = p_self; + function = p_function; + captures = p_captures; + + h = (uint32_t)hash_djb2_one_64((uint64_t)this); +} diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index 336778d549..248176e32c 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -62,4 +62,29 @@ public: virtual ~GDScriptLambdaCallable() = default; }; +// Lambda callable that references a particular object, so it can use `self` in the body. +class GDScriptLambdaSelfCallable : public CallableCustom { + GDScriptFunction *function = nullptr; + Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference. + Object *object = nullptr; // For non RefCounted objects, use a direct pointer. + 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); + +public: + 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; + + GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures); + GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures); + virtual ~GDScriptLambdaSelfCallable() = default; +}; + #endif // GDSCRIPT_LAMBDA_CALLABLE diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 48f58e51fe..62330d23ed 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -39,6 +39,7 @@ #ifdef DEBUG_ENABLED #include "core/os/os.h" #include "core/string/string_builder.h" +#include "gdscript_warning.h" #endif // DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); + register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true); // Networking. register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); - // TODO: Warning annotations. } GDScriptParser::~GDScriptParser() { @@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ return; } + if (ignored_warning_codes.has(p_code)) { + return; + } + String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower(); if (ignored_warnings.has(warn_name)) { return; @@ -514,7 +519,7 @@ void GDScriptParser::parse_program() { // Check for @tool annotation. AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::CLASS_LEVEL); if (annotation != nullptr) { - if (annotation->name == "@tool") { + if (annotation->name == SNAME("@tool")) { // TODO: don't allow @tool anywhere else. (Should all script annotations be the first thing?). _is_tool = true; if (previous.type != GDScriptTokenizer::Token::NEWLINE) { @@ -568,7 +573,7 @@ void GDScriptParser::parse_program() { // Check for @icon annotation. AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::CLASS_LEVEL); if (annotation != nullptr) { - if (annotation->name == "@icon") { + if (annotation->name == SNAME("@icon")) { if (previous.type != GDScriptTokenizer::Token::NEWLINE) { push_error(R"(Expected newline after "@icon" annotation.)"); } @@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() { template <class T> void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) { advance(); - T *member = (this->*p_parse_function)(); - if (member == nullptr) { - return; - } + #ifdef TOOLS_ENABLED - int doc_comment_line = member->start_line - 1; + int doc_comment_line = previous.start_line - 1; #endif // TOOLS_ENABLED // Consume annotations. + List<AnnotationNode *> annotations; while (!annotation_stack.is_empty()) { AnnotationNode *last_annotation = annotation_stack.back()->get(); if (last_annotation->applies_to(p_target)) { - member->annotations.push_front(last_annotation); + annotations.push_front(last_annotation); annotation_stack.pop_back(); } else { push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind)); clear_unused_annotations(); - return; } #ifdef TOOLS_ENABLED if (last_annotation->start_line == doc_comment_line) { @@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() #endif // TOOLS_ENABLED } + T *member = (this->*p_parse_function)(); + if (member == nullptr) { + return; + } + + // Apply annotations. + for (AnnotationNode *&annotation : annotations) { + member->annotations.push_back(annotation); + } + #ifdef TOOLS_ENABLED // Consume doc comments. class_doc_line = MIN(class_doc_line, doc_comment_line - 1); @@ -805,6 +817,8 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) { class_end = true; break; default: + // Display a completion with identifiers. + make_completion_context(COMPLETION_IDENTIFIER, nullptr); push_error(vformat(R"(Unexpected "%s" in class body.)", current.get_name())); advance(); break; @@ -1366,6 +1380,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali push_completion_call(annotation); make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, 0, true); if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) { + push_multiline(true); int argument_index = 0; do { make_completion_context(COMPLETION_ANNOTATION_ARGUMENTS, annotation, argument_index, true); @@ -1377,6 +1392,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali } annotation->arguments.push_back(argument); } while (match(GDScriptTokenizer::Token::COMMA)); + pop_multiline(); consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after annotation arguments.)*"); } @@ -1507,6 +1523,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code; #endif + bool is_annotation = false; + switch (current.type) { case GDScriptTokenizer::Token::PASS: advance(); @@ -1576,6 +1594,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { break; case GDScriptTokenizer::Token::ANNOTATION: { advance(); + is_annotation = true; AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT); if (annotation != nullptr) { annotation_stack.push_back(annotation); @@ -1616,6 +1635,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { } } + // Apply annotations to statement. + while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) { + AnnotationNode *last_annotation = annotation_stack.back()->get(); + if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) { + result->annotations.push_front(last_annotation); + annotation_stack.pop_back(); + } else { + push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name)); + clear_unused_annotations(); + } + } + #ifdef DEBUG_ENABLED if (unreachable && result != nullptr) { current_suite->has_unreachable_code = true; @@ -1832,7 +1863,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { if (pattern == nullptr) { continue; } - if (pattern->pattern_type == PatternNode::PT_BIND) { + if (pattern->binds.size() > 0) { has_bind = true; } if (branch->patterns.size() > 0 && has_bind) { @@ -1868,6 +1899,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { for (const StringName &E : binds) { SuiteNode::Local local(branch->patterns[0]->binds[E], current_function); + local.type = SuiteNode::Local::PATTERN_BIND; suite->add_local(local); } } @@ -2076,7 +2108,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign); while (p_precedence <= get_rule(current.type)->precedence) { - if (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) { + if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL)) { return previous_operand; } // Also switch multiline mode on here for infix operators. @@ -2169,9 +2201,6 @@ 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; @@ -2386,6 +2415,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode push_error("Assignment is not allowed inside an expression."); return parse_expression(false); // Return the following expression. } + if (p_previous_operand == nullptr) { + return parse_expression(false); // Return the following expression. + } #ifdef DEBUG_ENABLED VariableNode *source_variable = nullptr; @@ -2651,7 +2683,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode * 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) { - make_completion_context(COMPLETION_BUILT_IN_TYPE_CONSTANT, builtin_type, true); + make_completion_context(COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, builtin_type, true); is_builtin = true; } } @@ -2660,12 +2692,13 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode * } } - attribute->is_attribute = true; attribute->base = p_previous_operand; if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier after "." for attribute access.)")) { return attribute; } + + attribute->is_attribute = true; attribute->attribute = parse_identifier(); return attribute; @@ -2717,7 +2750,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre pop_multiline(); return nullptr; } - call->function_name = current_function->identifier->name; + if (current_function->identifier) { + call->function_name = current_function->identifier->name; + } else { + call->function_name = SNAME("<anonymous>"); + } } else { consume(GDScriptTokenizer::Token::PERIOD, R"(Expected "." or "(" after "super".)"); make_completion_context(COMPLETION_SUPER_METHOD, call, true); @@ -3447,6 +3484,15 @@ template <PropertyHint t_hint, Variant::Type t_type> bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_node) { ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); + { + const int max_flags = 32; + + if (t_hint == PropertyHint::PROPERTY_HINT_FLAGS && p_annotation->resolved_arguments.size() > max_flags) { + push_error(vformat(R"(The argument count limit for "@export_flags" is exceeded (%d/%d).)", p_annotation->resolved_arguments.size(), max_flags), p_annotation); + return false; + } + } + VariableNode *variable = static_cast<VariableNode *>(p_node); if (variable->exported) { push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); @@ -3468,10 +3514,10 @@ 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. + // This is called after the analyzer is done finding the type, so this should be set here. DataType export_type = variable->get_datatype(); - if (p_annotation->name == "@export") { + if (p_annotation->name == SNAME("@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; @@ -3496,7 +3542,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type); break; case GDScriptParser::DataType::NATIVE: - if (ClassDB::is_parent_class(export_type.native_type, "Resource")) { + if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { variable->export_info.type = Variant::OBJECT; variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; variable->export_info.hint_string = export_type.native_type; @@ -3510,12 +3556,12 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node 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().capitalize().xml_escape(); + for (OrderedHashMap<StringName, int>::Element E = export_type.enum_values.front(); E; E = E.next()) { + enum_hint_string += E.key().operator String().capitalize().xml_escape(); enum_hint_string += ":"; - enum_hint_string += String::num_int64(E->get()).xml_escape(); + enum_hint_string += String::num_int64(E.value()).xml_escape(); - if (E->next()) { + if (E.next()) { enum_hint_string += ","; } } @@ -3552,7 +3598,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) { - ERR_FAIL_V_MSG(false, "Not implemented."); +#ifdef DEBUG_ENABLED + bool has_error = false; + for (const Variant &warning_name : p_annotation->resolved_arguments) { + GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper()); + if (warning == GDScriptWarning::WARNING_MAX) { + push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation); + has_error = true; + } else { + p_node->ignored_warnings.push_back(warning); + } + } + + return !has_error; + +#else // ! DEBUG_ENABLED + // Only available in debug builds. + return true; +#endif // DEBUG_ENABLED } template <Multiplayer::RPCMode t_mode> @@ -3691,8 +3754,6 @@ String GDScriptParser::DataType::to_string() const { } case ENUM: return enum_type.operator String() + " (enum)"; - case ENUM_VALUE: - return enum_type.operator String() + " (enum value)"; case UNRESOLVED: return "<unresolved type>"; } @@ -4190,7 +4251,11 @@ void GDScriptParser::TreePrinter::print_get_node(GetNodeNode *p_get_node) { } void GDScriptParser::TreePrinter::print_identifier(IdentifierNode *p_identifier) { - push_text(p_identifier->name); + if (p_identifier != nullptr) { + push_text(p_identifier->name); + } else { + push_text("<invalid identifier>"); + } } void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 2f05b4b948..10474db02f 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -106,8 +106,7 @@ public: NATIVE, SCRIPT, CLASS, // GDScript. - ENUM, // Full enumeration. - ENUM_VALUE, // Value from enumeration. + ENUM, // Enumeration. VARIANT, // Can be any type. UNRESOLVED, }; @@ -133,7 +132,7 @@ public: ClassNode *class_type = nullptr; MethodInfo method_info; // For callable/signals. - Map<StringName, int> enum_values; // For enums. + OrderedHashMap<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; } @@ -185,8 +184,6 @@ public: return builtin_type == p_other.builtin_type; case NATIVE: case ENUM: - return native_type == p_other.native_type; - case ENUM_VALUE: return native_type == p_other.native_type && enum_type == p_other.enum_type; case SCRIPT: return script_type == p_other.script_type; @@ -297,6 +294,7 @@ public: int leftmost_column = 0, rightmost_column = 0; Node *next = nullptr; List<AnnotationNode *> annotations; + Vector<uint32_t> ignored_warnings; DataType datatype; @@ -314,7 +312,7 @@ public: bool is_constant = false; Variant reduced_value; - virtual bool is_expression() const { return true; } + virtual bool is_expression() const override { return true; } virtual ~ExpressionNode() {} protected: @@ -769,6 +767,7 @@ public: LOCAL_BIND, // Pattern bind. MEMBER_VARIABLE, MEMBER_CONSTANT, + INHERITED_VARIABLE, }; Source source = UNDEFINED_SOURCE; @@ -802,6 +801,7 @@ public: FunctionNode *parent_function = nullptr; Vector<IdentifierNode *> captures; Map<StringName, int> captures_indices; + bool use_self = false; bool has_name() const { return function && function->identifier; @@ -1148,7 +1148,7 @@ public: COMPLETION_ASSIGN, // Assignment based on type (e.g. enum values). COMPLETION_ATTRIBUTE, // After id.| to look for members. COMPLETION_ATTRIBUTE_METHOD, // After id.| to look for methods. - COMPLETION_BUILT_IN_TYPE_CONSTANT, // Constants inside a built-in type (e.g. Color.blue). + COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, // Constants inside a built-in type (e.g. Color.BLUE) or static methods (e.g. Color.html). COMPLETION_CALL_ARGUMENTS, // Complete with nodes, input actions, enum values (or usual expressions). // TODO: COMPLETION_DECLARATION, // Potential declaration (var, const, func). COMPLETION_GET_NODE, // Get node with $ notation. @@ -1204,6 +1204,7 @@ private: #ifdef DEBUG_ENABLED List<GDScriptWarning> warnings; Set<String> ignored_warnings; + Set<uint32_t> ignored_warning_codes; Set<int> unsafe_lines; #endif diff --git a/modules/gdscript/gdscript_rpc_callable.cpp b/modules/gdscript/gdscript_rpc_callable.cpp new file mode 100644 index 0000000000..07ef5aefcb --- /dev/null +++ b/modules/gdscript/gdscript_rpc_callable.cpp @@ -0,0 +1,86 @@ +/*************************************************************************/ +/* gdscript_rpc_callable.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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_rpc_callable.h" + +#include "core/templates/hashfuncs.h" +#include "scene/main/node.h" + +bool GDScriptRPCCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a->hash() == p_b->hash(); +} + +bool GDScriptRPCCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a->hash() < p_b->hash(); +} + +uint32_t GDScriptRPCCallable::hash() const { + return h; +} + +String GDScriptRPCCallable::get_as_text() const { + String class_name = object->get_class(); + Ref<Script> script = object->get_script(); + return class_name + "(" + script->get_path().get_file() + ")::" + String(method) + " (rpc)"; +} + +CallableCustom::CompareEqualFunc GDScriptRPCCallable::get_compare_equal_func() const { + return compare_equal; +} + +CallableCustom::CompareLessFunc GDScriptRPCCallable::get_compare_less_func() const { + return compare_less; +} + +ObjectID GDScriptRPCCallable::get_object() const { + return object->get_instance_id(); +} + +void GDScriptRPCCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + r_return_value = object->callp(method, p_arguments, p_argcount, r_call_error); +} + +GDScriptRPCCallable::GDScriptRPCCallable(Object *p_object, const StringName &p_method) { + object = p_object; + method = p_method; + h = method.hash(); + h = hash_djb2_one_64(object->get_instance_id(), h); + node = Object::cast_to<Node>(object); + ERR_FAIL_COND_MSG(!node, "RPC can only be defined on class that extends Node."); +} + +void GDScriptRPCCallable::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const { + if (unlikely(!node)) { + r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return; + } + r_call_error.error = Callable::CallError::CALL_OK; + node->rpcp(p_peer_id, method, p_arguments, p_argcount); +} diff --git a/modules/gdnative/gdnative/callable.cpp b/modules/gdscript/gdscript_rpc_callable.h index 85274e5e22..2c8734a74b 100644 --- a/modules/gdnative/gdnative/callable.cpp +++ b/modules/gdscript/gdscript_rpc_callable.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* callable.cpp */ +/* gdscript_rpc_callable.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,30 +28,34 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gdnative/callable.h" +#ifndef GDSCRIPT_RPC_CALLABLE +#define GDSCRIPT_RPC_CALLABLE #include "core/variant/callable.h" #include "core/variant/variant.h" -static_assert(sizeof(godot_callable) == sizeof(Callable), "Callable size mismatch"); +class Node; -#ifdef __cplusplus -extern "C" { -#endif +class GDScriptRPCCallable : public CallableCustom { + Object *object = nullptr; + Node *node = nullptr; + StringName method; + uint32_t h = 0; -void GDAPI godot_callable_new(godot_callable *p_self) { - memnew_placement(p_self, Callable); -} + static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); + static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b); -void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src) { - memnew_placement(r_dest, Callable(*(Callable *)p_src)); -} +public: + 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; + void rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override; -void GDAPI godot_callable_destroy(godot_callable *p_self) { - Callable *self = (Callable *)p_self; - self->~Callable(); -} + GDScriptRPCCallable(Object *p_object, const StringName &p_method); + virtual ~GDScriptRPCCallable() = default; +}; -#ifdef __cplusplus -} -#endif +#endif // GDSCRIPT_RPC_CALLABLE diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 3725fb58f5..63fad0d9bb 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -312,22 +312,6 @@ GDScriptTokenizer::Token GDScriptTokenizer::pop_error() { return error; } -static bool _is_alphanumeric(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; -} - -static bool _is_digit(char32_t c) { - return (c >= '0' && c <= '9'); -} - -static bool _is_hex_digit(char32_t c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); -} - -static bool _is_binary_digit(char32_t c) { - return (c == '0' || c == '1'); -} - GDScriptTokenizer::Token GDScriptTokenizer::make_token(Token::Type p_type) { Token token(p_type); token.start_line = start_line; @@ -448,10 +432,10 @@ GDScriptTokenizer::Token GDScriptTokenizer::check_vcs_marker(char32_t p_test, To } GDScriptTokenizer::Token GDScriptTokenizer::annotation() { - if (!_is_alphanumeric(_peek())) { + if (!is_ascii_identifier_char(_peek())) { push_error("Expected annotation identifier after \"@\"."); } - while (_is_alphanumeric(_peek())) { + while (is_ascii_identifier_char(_peek())) { // Consume all identifier characters. _advance(); } @@ -526,7 +510,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() { #define MAX_KEYWORD_LENGTH 10 // Consume all alphanumeric characters. - while (_is_alphanumeric(_peek())) { + while (is_ascii_identifier_char(_peek())) { _advance(); } @@ -612,7 +596,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { bool has_decimal = false; bool has_exponent = false; bool has_error = false; - bool (*digit_check_func)(char32_t) = _is_digit; + bool (*digit_check_func)(char32_t) = is_digit; if (_peek(-1) == '.') { has_decimal = true; @@ -620,20 +604,20 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { if (_peek() == 'x') { // Hexadecimal. base = 16; - digit_check_func = _is_hex_digit; + digit_check_func = is_hex_digit; _advance(); } else if (_peek() == 'b') { // Binary. base = 2; - digit_check_func = _is_binary_digit; + digit_check_func = is_binary_digit; _advance(); } } // Allow '_' to be used in a number, for readability. bool previous_was_underscore = false; - while (digit_check_func(_peek()) || _peek() == '_') { - if (_peek() == '_') { + while (digit_check_func(_peek()) || is_underscore(_peek())) { + if (is_underscore(_peek())) { if (previous_was_underscore) { Token error = make_error(R"(Only one underscore can be used as a numeric separator.)"); error.start_column = column; @@ -682,7 +666,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { _advance(); // Consume decimal digits. - while (_is_digit(_peek()) || _peek() == '_') { + while (is_digit(_peek()) || is_underscore(_peek())) { _advance(); } } @@ -696,7 +680,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { _advance(); } // Consume exponent digits. - if (!_is_digit(_peek())) { + if (!is_digit(_peek())) { Token error = make_error(R"(Expected exponent value after "e".)"); error.start_column = column; error.leftmost_column = column; @@ -705,8 +689,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { push_error(error); } previous_was_underscore = false; - while (_is_digit(_peek()) || _peek() == '_') { - if (_peek() == '_') { + while (is_digit(_peek()) || is_underscore(_peek())) { + if (is_underscore(_peek())) { if (previous_was_underscore) { Token error = make_error(R"(Only one underscore can be used as a numeric separator.)"); error.start_column = column; @@ -733,7 +717,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { error.rightmost_column = column + 1; push_error(error); has_error = true; - } else if (_is_alphanumeric(_peek())) { + } else if (is_ascii_identifier_char(_peek())) { // Letter at the end of the number. push_error("Invalid numeric notation."); } @@ -786,6 +770,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { } String result; + char32_t prev = 0; + int prev_pos = 0; for (;;) { // Consume actual string. @@ -852,16 +838,18 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { case '\\': escaped = '\\'; break; - case 'u': + case 'U': + case 'u': { // Hexadecimal sequence. - for (int i = 0; i < 4; i++) { + int hex_len = (code == 'U') ? 6 : 4; + for (int j = 0; j < hex_len; j++) { if (_is_at_end()) { return make_error("Unterminated string."); } char32_t digit = _peek(); char32_t value = 0; - if (digit >= '0' && digit <= '9') { + if (is_digit(digit)) { value = digit - '0'; } else if (digit >= 'a' && digit <= 'f') { value = digit - 'a'; @@ -886,7 +874,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { _advance(); } - break; + } break; case '\r': if (_peek() != '\n') { // Carriage return without newline in string. (???) @@ -909,11 +897,53 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { valid_escape = false; break; } + // Parse UTF-16 pair. + if (valid_escape) { + if ((escaped & 0xfffffc00) == 0xd800) { + if (prev == 0) { + prev = escaped; + prev_pos = column - 2; + continue; + } else { + Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + error.start_column = column - 2; + error.leftmost_column = error.start_column; + push_error(error); + valid_escape = false; + prev = 0; + } + } else if ((escaped & 0xfffffc00) == 0xdc00) { + if (prev == 0) { + Token error = make_error("Invalid UTF-16 sequence in string, unpaired trail surrogate"); + error.start_column = column - 2; + error.leftmost_column = error.start_column; + push_error(error); + valid_escape = false; + } else { + escaped = (prev << 10UL) + escaped - ((0xd800 << 10UL) + 0xdc00 - 0x10000); + prev = 0; + } + } + if (prev != 0) { + Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + error.start_column = prev_pos; + error.leftmost_column = error.start_column; + push_error(error); + prev = 0; + } + } if (valid_escape) { result += escaped; } } else if (ch == quote_char) { + if (prev != 0) { + Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + error.start_column = prev_pos; + error.leftmost_column = error.start_column; + push_error(error); + prev = 0; + } _advance(); if (is_multiline) { if (_peek() == quote_char && _peek(1) == quote_char) { @@ -930,6 +960,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { break; } } else { + if (prev != 0) { + Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + error.start_column = prev_pos; + error.leftmost_column = error.start_column; + push_error(error); + prev = 0; + } result += ch; _advance(); if (ch == '\n') { @@ -937,6 +974,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { } } } + if (prev != 0) { + Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + error.start_column = prev_pos; + error.leftmost_column = error.start_column; + push_error(error); + prev = 0; + } // Make the literal. Variant string; @@ -1262,9 +1306,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { line_continuation = false; - if (_is_digit(c)) { + if (is_digit(c)) { return number(); - } else if (_is_alphanumeric(c)) { + } else if (is_ascii_identifier_char(c)) { return potential_identifier(); } @@ -1332,7 +1376,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { if (_peek() == '.') { _advance(); return make_token(Token::PERIOD_PERIOD); - } else if (_is_digit(_peek())) { + } else if (is_digit(_peek())) { // Number starting with '.'. return number(); } else { @@ -1449,7 +1493,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { } default: - return make_error(vformat(R"(Unknown character "%s".")", String(&c, 1))); + return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1))); } } diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index b4ee11fd9a..abd090e381 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index e997d3a51e..a914374985 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -432,21 +432,21 @@ struct GDScriptUtilityFunctionsDefinitions { } static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - String str; + String s; for (int i = 0; i < p_arg_count; i++) { - str += p_args[i]->operator String(); + s += p_args[i]->operator String(); } if (Thread::get_caller_id() == Thread::get_main_id()) { ScriptLanguage *script = GDScriptLanguage::get_singleton(); if (script->debug_get_stack_level_count() > 0) { - str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()"; + s += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()"; } } else { - str += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id()); + s += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id()); } - print_line(str); + print_line(s); *r_ret = Variant(); } @@ -545,7 +545,7 @@ struct GDScriptUtilityFunctionsDefinitions { }; struct GDScriptUtilityFunctionInfo { - GDScriptUtilityFunctions::FunctionPtr function; + GDScriptUtilityFunctions::FunctionPtr function = nullptr; MethodInfo info; bool is_constant = false; }; diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h index c6d3718844..9ca7cf33d8 100644 --- a/modules/gdscript/gdscript_utility_functions.h +++ b/modules/gdscript/gdscript_utility_functions.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index be9e5df2b0..e28dd26c28 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -93,9 +93,13 @@ static String _get_var_type(const Variant *p_var) { basestr = "null instance"; } } else { - basestr = bobj->get_class(); - if (bobj->get_script_instance()) { - basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; + if (bobj->is_class_ptr(GDScriptNativeClass::get_class_ptr_static())) { + basestr = Object::cast_to<GDScriptNativeClass>(bobj)->get_name(); + } else { + basestr = bobj->get_class(); + if (bobj->get_script_instance()) { + basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; + } } } @@ -123,6 +127,34 @@ static String _get_var_type(const Variant *p_var) { } #endif // DEBUG_ENABLED +Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataType &p_data_type) { + if (p_data_type.kind == GDScriptDataType::BUILTIN) { + if (p_data_type.builtin_type == Variant::ARRAY) { + Array array; + // Typed array. + if (p_data_type.has_container_element_type()) { + const GDScriptDataType &element_type = p_data_type.get_container_element_type(); + array.set_typed( + element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT, + element_type.native_type, + element_type.script_type); + } + + return array; + } else { + Callable::CallError ce; + Variant variant; + Variant::construct(p_data_type.builtin_type, variant, nullptr, 0, ce); + + ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, Variant()); + + return variant; + } + } + + return Variant(); +} + String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const { String err_text; @@ -235,6 +267,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND_RET, \ &&OPCODE_CALL_BUILTIN_STATIC, \ + &&OPCODE_CALL_NATIVE_STATIC, \ &&OPCODE_CALL_PTRCALL_NO_RETURN, \ &&OPCODE_CALL_PTRCALL_BOOL, \ &&OPCODE_CALL_PTRCALL_INT, \ @@ -273,6 +306,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_AWAIT, \ &&OPCODE_AWAIT_RESUME, \ &&OPCODE_CREATE_LAMBDA, \ + &&OPCODE_CREATE_SELF_LAMBDA, \ &&OPCODE_JUMP, \ &&OPCODE_JUMP_IF, \ &&OPCODE_JUMP_IF_NOT, \ @@ -339,7 +373,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_TYPE_ADJUST_QUATERNION, \ &&OPCODE_TYPE_ADJUST_AABB, \ &&OPCODE_TYPE_ADJUST_BASIS, \ - &&OPCODE_TYPE_ADJUST_TRANSFORM, \ + &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \ &&OPCODE_TYPE_ADJUST_COLOR, \ &&OPCODE_TYPE_ADJUST_STRING_NAME, \ &&OPCODE_TYPE_ADJUST_NODE_PATH, \ @@ -428,7 +462,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODES_TABLE; if (!_code_ptr) { - return Variant(); + return _get_default_variant_for_data_type(return_type); } r_err.error = Callable::CallError::CALL_OK; @@ -467,11 +501,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_err.argument = _argument_count; - return Variant(); + return _get_default_variant_for_data_type(return_type); } else if (p_argcount < _argument_count - _default_arg_count) { r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_err.argument = _argument_count - _default_arg_count; - return Variant(); + return _get_default_variant_for_data_type(return_type); } else { defarg = _argument_count - p_argcount; } @@ -488,12 +522,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&stack[i + 3], Variant(*p_args[i])); continue; } - + // If types already match, don't call Variant::construct(). Constructors of some types + // (e.g. packed arrays) do copies, whereas they pass by reference when inside a Variant. + if (argument_types[i].is_type(*p_args[i], false)) { + memnew_placement(&stack[i + 3], 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(); + return _get_default_variant_for_data_type(return_type); } if (argument_types[i].kind == GDScriptDataType::BUILTIN) { Variant arg; @@ -1414,7 +1453,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a const StringName native_type = _global_names_ptr[native_type_idx]; Array array; - array.set_typed(builtin_type, native_type, script_type); + array.set_typed(builtin_type, native_type, *script_type); array.resize(argc); for (int i = 0; i < argc; i++) { @@ -1484,7 +1523,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Callable::CallError err; if (call_ret) { GET_INSTRUCTION_ARG(ret, argc + 1); - base->call(*methodname, (const Variant **)argptrs, argc, *ret, err); + base->callp(*methodname, (const Variant **)argptrs, argc, *ret, err); #ifdef DEBUG_ENABLED if (!call_async && ret->get_type() == Variant::OBJECT) { // Check if getting a function state without await. @@ -1503,7 +1542,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif } else { Variant ret; - base->call(*methodname, (const Variant **)argptrs, argc, ret, err); + base->callp(*methodname, (const Variant **)argptrs, argc, ret, err); } #ifdef DEBUG_ENABLED if (GDScriptLanguage::get_singleton()->profiling) { @@ -1527,7 +1566,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } else if (methodstr == "free") { if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { - if (base->is_ref()) { + if (base->is_ref_counted()) { err_text = "Attempted to free a reference."; OPCODE_BREAK; } else if (base->get_type() == Variant::OBJECT) { @@ -1615,7 +1654,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } else if (methodstr == "free") { if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { - if (base->is_ref()) { + if (base->is_ref_counted()) { err_text = "Attempted to free a reference."; OPCODE_BREAK; } else if (base->get_type() == Variant::OBJECT) { @@ -1677,6 +1716,47 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_NATIVE_STATIC) { + CHECK_SPACE(3 + instr_arg_count); + + ip += instr_arg_count; + + GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= _methods_count); + MethodBind *method = _methods_ptr[_code_ptr[ip + 1]]; + + int argc = _code_ptr[ip + 2]; + 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; + *ret = method->call(nullptr, argptrs, argc, 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 '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs); + OPCODE_BREAK; + } +#endif + + ip += 3; + } + DISPATCH_OPCODE; + #ifdef DEBUG_ENABLED #define OPCODE_CALL_PTR(m_type) \ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \ @@ -2198,6 +2278,41 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CREATE_SELF_LAMBDA) { + CHECK_SPACE(2 + instr_arg_count); + + GD_ERR_BREAK(p_instance == nullptr); + + 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; + } + + GDScriptLambdaSelfCallable *callable; + if (Object::cast_to<RefCounted>(p_instance->owner)) { + callable = memnew(GDScriptLambdaSelfCallable(Ref<RefCounted>(Object::cast_to<RefCounted>(p_instance->owner)), lambda, captures)); + } else { + callable = memnew(GDScriptLambdaSelfCallable(p_instance->owner, 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]; @@ -2307,7 +2422,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } Array array; - array.set_typed(builtin_type, native_type, script_type); + array.set_typed(builtin_type, native_type, *script_type); #ifdef DEBUG_ENABLED bool valid = array.typed_assign(*VariantInternal::get_array(r)); @@ -2777,7 +2892,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a args[0] = &vref; Callable::CallError ce; - Variant has_next = obj->call(CoreStringNames::get_singleton()->_iter_init, (const Variant **)args, 1, ce); + Variant has_next = obj->callp(CoreStringNames::get_singleton()->_iter_init, (const Variant **)args, 1, ce); #ifdef DEBUG_ENABLED if (ce.error != Callable::CallError::CALL_OK) { @@ -2791,7 +2906,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a ip = jumpto; } else { GET_INSTRUCTION_ARG(iterator, 2); - *iterator = obj->call(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce); + *iterator = obj->callp(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce); #ifdef DEBUG_ENABLED if (ce.error != Callable::CallError::CALL_OK) { err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container); @@ -3108,7 +3223,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a args[0] = &vref; Callable::CallError ce; - Variant has_next = obj->call(CoreStringNames::get_singleton()->_iter_next, (const Variant **)args, 1, ce); + Variant has_next = obj->callp(CoreStringNames::get_singleton()->_iter_next, (const Variant **)args, 1, ce); #ifdef DEBUG_ENABLED if (ce.error != Callable::CallError::CALL_OK) { @@ -3122,7 +3237,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a ip = jumpto; } else { GET_INSTRUCTION_ARG(iterator, 2); - *iterator = obj->call(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce); + *iterator = obj->callp(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce); #ifdef DEBUG_ENABLED if (ce.error != Callable::CallError::CALL_OK) { err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container); @@ -3184,7 +3299,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_TYPE_ADJUST(QUATERNION, Quaternion); OPCODE_TYPE_ADJUST(AABB, AABB); OPCODE_TYPE_ADJUST(BASIS, Basis); - OPCODE_TYPE_ADJUST(TRANSFORM, Transform3D); + OPCODE_TYPE_ADJUST(TRANSFORM3D, Transform3D); OPCODE_TYPE_ADJUST(COLOR, Color); OPCODE_TYPE_ADJUST(STRING_NAME, StringName); OPCODE_TYPE_ADJUST(NODE_PATH, NodePath); @@ -3319,6 +3434,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } #endif + // Get a default return type in case of failure + retvalue = _get_default_variant_for_data_type(return_type); + OPCODE_OUT; } diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index a351bd6dad..ad96e36640 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -152,6 +152,9 @@ String GDScriptWarning::get_message() const { CHECK_SYMBOLS(3); return vformat(R"(The %s '%s' has the same name as a %s.)", symbols[0], symbols[1], symbols[2]); } + case INT_ASSIGNED_TO_ENUM: { + return "Integer used when an enum value is expected. If this is intended cast the integer to the enum type."; + } case WARNING_MAX: break; // Can't happen, but silences warning } @@ -199,6 +202,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "REDUNDANT_AWAIT", "EMPTY_FILE", "SHADOWED_GLOBAL_IDENTIFIER", + "INT_ASSIGNED_TO_ENUM", }; static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names."); @@ -213,7 +217,7 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) } } - ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name); + return WARNING_MAX; } #endif // DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index d05f47efe7..82efe3568f 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -70,6 +70,7 @@ public: REDUNDANT_AWAIT, // await is used but expression is synchronous (not a signal nor a coroutine). EMPTY_FILE, // A script file is empty. SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable. + INT_ASSIGNED_TO_ENUM, // An integer value was assigned to an enum-typed variable without casting. WARNING_MAX, }; diff --git a/modules/gdscript/icons/GDScriptInternal.svg b/modules/gdscript/icons/GDScriptInternal.svg new file mode 100644 index 0000000000..fcabaafbd0 --- /dev/null +++ b/modules/gdscript/icons/GDScriptInternal.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578c-.2364329.0758517-.4668872.16921-.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941c-.1119126.2211335-.2072287.4502818-.28516.68555l-2.2539.5625v2l2.2578.56445c.075942.2357685.1692993.465568.2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953c.2211335.111913.4502818.207229.68555.28516l.5625 2.2539h2l.56445-2.2578c.2357685-.07594.465568-.169299.6875-.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941c.111913-.221133.207229-.4502818.28516-.68555l2.2539-.5625v-2l-2.2578-.56445c-.075942-.2357685-.169299-.4655679-.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953c-.221133-.1119126-.4502818-.2072287-.68555-.28516l-.5625-2.2539zm1 5c1.1045695 0 2 .8954305 2 2s-.8954305 2-2 2-2-.8954305-2-2 .8954305-2 2-2z" fill="none" stroke="#e0e0e0"/></svg> diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 80f4721e2d..5516f59fe9 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -108,7 +108,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) { document_links.clear(); GDScriptTokenizer tokenizer; - FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); + Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); tokenizer.set_source_code(p_code); while (true) { GDScriptTokenizer::Token token = tokenizer.scan(); @@ -212,7 +212,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p const Variant &default_value = m.constant->initializer->reduced_value; String value_text; if (default_value.get_type() == Variant::OBJECT) { - RES res = default_value; + Ref<Resource> res = default_value; if (res.is_valid() && !res->get_path().is_empty()) { value_text = "preload(\"" + res->get_path() + "\")"; if (symbol.documentation.is_empty()) { @@ -541,7 +541,7 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position & for (int c = p_position.character; c >= 0; c--) { start_pos = c; char32_t ch = line[c]; - bool valid_char = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'; + bool valid_char = is_ascii_identifier_char(ch); if (!valid_char) { break; } @@ -550,7 +550,7 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position & int end_pos = p_position.character; for (int c = p_position.character; c < line.length(); c++) { char32_t ch = line[c]; - bool valid_char = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'; + bool valid_char = is_ascii_identifier_char(ch); if (!valid_char) { break; } diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h index 5d7b16765b..99b0bf45d0 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.h +++ b/modules/gdscript/language_server/gdscript_extend_parser.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 578943696e..cdddab319d 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index a4a63a23a8..0fed8597f9 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 41a2f9e4ad..14337e87da 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -45,17 +45,20 @@ GDScriptLanguageServer::GDScriptLanguageServer() { void GDScriptLanguageServer::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { start(); - break; - case NOTIFICATION_EXIT_TREE: + } break; + + case NOTIFICATION_EXIT_TREE: { stop(); - break; + } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (started && !use_thread) { protocol.poll(); } } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { String host = String(_EDITOR_GET("network/language_server/remote_host")); int port = (int)_EDITOR_GET("network/language_server/remote_port"); diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h index feee23dd13..8de72fc9c9 100644 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ b/modules/gdscript/language_server/gdscript_language_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index d2e033d7de..c42bd58aeb 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -166,49 +166,51 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { params.load(p_params); Dictionary request_data = params.to_json(); - List<ScriptCodeCompletionOption> options; + List<ScriptLanguage::CodeCompletionOption> options; GDScriptLanguageProtocol::get_singleton()->get_workspace()->completion(params, &options); if (!options.is_empty()) { int i = 0; arr.resize(options.size()); - for (const ScriptCodeCompletionOption &option : options) { + for (const ScriptLanguage::CodeCompletionOption &option : options) { lsp::CompletionItem item; item.label = option.display; item.data = request_data; switch (option.kind) { - case ScriptCodeCompletionOption::KIND_ENUM: + case ScriptLanguage::CODE_COMPLETION_KIND_ENUM: item.kind = lsp::CompletionItemKind::Enum; break; - case ScriptCodeCompletionOption::KIND_CLASS: + case ScriptLanguage::CODE_COMPLETION_KIND_CLASS: item.kind = lsp::CompletionItemKind::Class; break; - case ScriptCodeCompletionOption::KIND_MEMBER: + case ScriptLanguage::CODE_COMPLETION_KIND_MEMBER: item.kind = lsp::CompletionItemKind::Property; break; - case ScriptCodeCompletionOption::KIND_FUNCTION: + case ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION: item.kind = lsp::CompletionItemKind::Method; break; - case ScriptCodeCompletionOption::KIND_SIGNAL: + case ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL: item.kind = lsp::CompletionItemKind::Event; break; - case ScriptCodeCompletionOption::KIND_CONSTANT: + case ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT: item.kind = lsp::CompletionItemKind::Constant; break; - case ScriptCodeCompletionOption::KIND_VARIABLE: + case ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE: item.kind = lsp::CompletionItemKind::Variable; break; - case ScriptCodeCompletionOption::KIND_FILE_PATH: + case ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH: item.kind = lsp::CompletionItemKind::File; break; - case ScriptCodeCompletionOption::KIND_NODE_PATH: + case ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH: item.kind = lsp::CompletionItemKind::Snippet; break; - case ScriptCodeCompletionOption::KIND_PLAIN_TEXT: + case ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT: item.kind = lsp::CompletionItemKind::Text; break; + default: { + } } arr[i] = item.to_json(); @@ -422,10 +424,6 @@ GDScriptTextDocument::GDScriptTextDocument() { file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES); } -GDScriptTextDocument::~GDScriptTextDocument() { - memdelete(file_checker); -} - 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); diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 9021c84a3f..9732765f34 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -40,7 +40,7 @@ class GDScriptTextDocument : public RefCounted { protected: static void _bind_methods(); - FileAccess *file_checker; + Ref<FileAccess> file_checker; void didOpen(const Variant &p_param); void didClose(const Variant &p_param); @@ -75,7 +75,6 @@ public: void initialize(); GDScriptTextDocument(); - virtual ~GDScriptTextDocument(); }; #endif diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 9be9cbc749..89ee6b35e5 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -63,7 +63,7 @@ void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStr String function_signature = "func " + function; String source = script->get_source_code(); - if (source.find(function_signature) != -1) { + if (source.contains(function_signature)) { return; } @@ -221,7 +221,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) { Error err; - DirAccessRef dir = DirAccess::open(p_root_dir, &err); + Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err); if (OK == err) { dir->list_dir_begin(); String file_name = dir->get_next(); @@ -269,7 +269,7 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) { Vector<lsp::DocumentedSymbolInformation> script_symbols; E.value->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)) { + if (query.is_subsequence_ofn(script_symbols[i].name)) { lsp::DocumentedSymbolInformation symbol = script_symbols[i]; symbol.location.uri = get_file_uri(symbol.location.uri); arr.push_back(symbol.to_json()); @@ -380,7 +380,7 @@ Error GDScriptWorkspace::initialize() { symbol.children.push_back(symbol_arg); } - if (data.qualifiers.find("vararg") != -1) { + if (data.qualifiers.contains("vararg")) { params += params.is_empty() ? "..." : ", ..."; } @@ -560,7 +560,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { for (int i = 0; i < owners.size(); i++) { NodePath owner_path = owners[i]; - RES owner_res = ResourceLoader::load(owner_path); + Ref<Resource> 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->instantiate(); @@ -571,7 +571,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { return owner_scene_node; } -void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options) { +void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<ScriptLanguage::CodeCompletionOption> *r_options) { String path = get_file_path(p_params.textDocument.uri); String call_hint; bool forced = false; @@ -585,7 +585,7 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S stack.push_back(owner_scene_node); while (!stack.is_empty()) { - current = stack.pop_back(); + current = Object::cast_to<Node>(stack.pop_back()); Ref<GDScript> script = current->get_script(); if (script.is_valid() && script->get_path() == path) { break; @@ -638,7 +638,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu symbol_identifier = "_init"; } if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) { - if (ret.type == ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION) { + if (ret.type == ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION) { String target_script_path = path; if (!ret.script.is_null()) { target_script_path = ret.script->get_path(); diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 6f5600b5cf..92e78f8992 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -85,7 +85,7 @@ public: String get_file_uri(const String &p_path) const; void publish_diagnostics(const String &p_path); - void completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options); + void completion(const lsp::CompletionParams &p_params, List<ScriptLanguage::CodeCompletionOption> *r_options); const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_required = false); void resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index b12d1f5f3b..a63f9df918 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -1940,7 +1940,7 @@ static String marked_documentation(const String &p_bbcode) { line = "\t" + line.substr(code_block_indent, line.length()); } - if (in_code_block && line.find("[/codeblock]") != -1) { + if (in_code_block && line.contains("[/codeblock]")) { line = "\n"; in_code_block = false; } diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index c2b1981f31..59acb1c064 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -111,54 +111,62 @@ static void _editor_init() { #endif // TOOLS_ENABLED -void register_gdscript_types() { - GDREGISTER_CLASS(GDScript); +void initialize_gdscript_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + GDREGISTER_CLASS(GDScript); - script_language_gd = memnew(GDScriptLanguage); - ScriptServer::register_language(script_language_gd); + script_language_gd = memnew(GDScriptLanguage); + ScriptServer::register_language(script_language_gd); - resource_loader_gd.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_gd); + resource_loader_gd.instantiate(); + ResourceLoader::add_resource_format_loader(resource_loader_gd); - resource_saver_gd.instantiate(); - ResourceSaver::add_resource_format_saver(resource_saver_gd); + resource_saver_gd.instantiate(); + ResourceSaver::add_resource_format_saver(resource_saver_gd); - gdscript_cache = memnew(GDScriptCache); + gdscript_cache = memnew(GDScriptCache); + + GDScriptUtilityFunctions::register_functions(); + } #ifdef TOOLS_ENABLED - EditorNode::add_init_callback(_editor_init); + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + EditorNode::add_init_callback(_editor_init); - gdscript_translation_parser_plugin.instantiate(); - EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); + gdscript_translation_parser_plugin.instantiate(); + EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); + } #endif // TOOLS_ENABLED - - GDScriptUtilityFunctions::register_functions(); } -void unregister_gdscript_types() { - ScriptServer::unregister_language(script_language_gd); +void uninitialize_gdscript_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + ScriptServer::unregister_language(script_language_gd); - if (gdscript_cache) { - memdelete(gdscript_cache); - } + if (gdscript_cache) { + memdelete(gdscript_cache); + } - if (script_language_gd) { - memdelete(script_language_gd); - } + if (script_language_gd) { + memdelete(script_language_gd); + } + + ResourceLoader::remove_resource_format_loader(resource_loader_gd); + resource_loader_gd.unref(); - ResourceLoader::remove_resource_format_loader(resource_loader_gd); - resource_loader_gd.unref(); + ResourceSaver::remove_resource_format_saver(resource_saver_gd); + resource_saver_gd.unref(); - ResourceSaver::remove_resource_format_saver(resource_saver_gd); - resource_saver_gd.unref(); + GDScriptParser::cleanup(); + GDScriptUtilityFunctions::unregister_functions(); + } #ifdef TOOLS_ENABLED - EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); - gdscript_translation_parser_plugin.unref(); + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); + gdscript_translation_parser_plugin.unref(); + } #endif // TOOLS_ENABLED - - GDScriptParser::cleanup(); - GDScriptUtilityFunctions::unregister_functions(); } #ifdef TESTS_ENABLED diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index ce1c03d1d0..a7e6b02dcf 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef GDSCRIPT_REGISTER_TYPES_H #define GDSCRIPT_REGISTER_TYPES_H -void register_gdscript_types(); -void unregister_gdscript_types(); +#include "modules/register_module_types.h" + +void initialize_gdscript_module(ModuleInitializationLevel p_level); +void uninitialize_gdscript_module(ModuleInitializationLevel p_level); #endif // GDSCRIPT_REGISTER_TYPES_H diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 21883b3c6e..ea51990237 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -70,26 +70,24 @@ void init_autoloads() { continue; } - RES res = ResourceLoader::load(info.path); + Ref<Resource> 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(); + Ref<PackedScene> scn = res; + Ref<Script> script = res; + if (scn.is_valid()) { + n = scn->instantiate(); + } else if (script.is_valid()) { + StringName ibt = script->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); + ERR_CONTINUE_MSG(!valid_type, "Script does not inherit from Node: " + info.path); Object *obj = ClassDB::instantiate(ibt); - ERR_CONTINUE_MSG(obj == nullptr, - "Cannot instance script for autoload, expected 'Node' inheritance, got: " + - String(ibt)); + ERR_CONTINUE_MSG(!obj, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + "."); n = Object::cast_to<Node>(obj); - n->set_script(script_res); + n->set_script(script); } ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path); @@ -134,12 +132,14 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l if (do_init_languages) { init_language(p_source_dir); } +#ifdef DEBUG_ENABLED // 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); } +#endif // Enable printing to show results _print_line_enabled = true; @@ -153,6 +153,21 @@ GDScriptTestRunner::~GDScriptTestRunner() { } } +#ifndef DEBUG_ENABLED +static String strip_warnings(const String &p_expected) { + // On release builds we don't have warnings. Here we remove them from the output before comparison + // so it doesn't fail just because of difference in warnings. + String expected_no_warnings; + for (String line : p_expected.split("\n")) { + if (line.begins_with(">> ")) { + continue; + } + expected_no_warnings += line + "\n"; + } + return expected_no_warnings.strip_edges() + "\n"; +} +#endif + int GDScriptTestRunner::run_tests() { if (!make_tests()) { FAIL("An error occurred while making the tests."); @@ -170,6 +185,9 @@ int GDScriptTestRunner::run_tests() { GDScriptTest::TestResult result = test.run_test(); String expected = FileAccess::get_file_as_string(test.get_output_file()); +#ifndef DEBUG_ENABLED + expected = strip_warnings(expected); +#endif INFO(test.get_source_file()); if (!result.passed) { INFO(expected); @@ -211,7 +229,7 @@ bool GDScriptTestRunner::generate_outputs() { bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { Error err = OK; - DirAccessRef dir(DirAccess::open(p_dir, &err)); + Ref<DirAccess> dir(DirAccess::open(p_dir, &err)); if (err != OK) { return false; @@ -233,6 +251,22 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { } } else { if (next.get_extension().to_lower() == "gd") { +#ifndef DEBUG_ENABLED + // On release builds, skip tests marked as debug only. + Error open_err = OK; + Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err)); + if (open_err != OK) { + ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next)); + next = dir->get_next(); + continue; + } else { + if (script_file->get_line() == "#debug-only") { + next = dir->get_next(); + continue; + } + } +#endif + 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); @@ -252,7 +286,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { bool GDScriptTestRunner::make_tests() { Error err = OK; - DirAccessRef dir(DirAccess::open(source_dir, &err)); + Ref<DirAccess> dir(DirAccess::open(source_dir, &err)); ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory."); @@ -362,16 +396,16 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha } builder.append("\n>> on function: "); - builder.append(p_function); + builder.append(String::utf8(p_function)); builder.append("()\n>> "); - builder.append(String(p_file).trim_prefix(self->base_dir)); + builder.append(String::utf8(p_file).trim_prefix(self->base_dir)); builder.append("\n>> "); builder.append(itos(p_line)); builder.append("\n>> "); - builder.append(p_error); + builder.append(String::utf8(p_error)); if (strlen(p_explanation) > 0) { builder.append("\n>> "); - builder.append(p_explanation); + builder.append(String::utf8(p_explanation)); } builder.append("\n"); @@ -387,6 +421,10 @@ bool GDScriptTest::check_output(const String &p_output) const { String got = p_output.strip_edges(); // TODO: may be hacky. got += "\n"; // Make sure to insert newline for CI static checks. +#ifndef DEBUG_ENABLED + expected = strip_warnings(expected); +#endif + return got == expected; } @@ -469,6 +507,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { return result; } +#ifdef DEBUG_ENABLED StringBuilder warning_string; for (const GDScriptWarning &E : parser.get_warnings()) { const GDScriptWarning warning = E; @@ -482,6 +521,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { warning_string.append("\n"); } result.output += warning_string.as_string(); +#endif // Test compiling. GDScriptCompiler compiler; @@ -533,7 +573,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { // Call test function. Callable::CallError call_err; - instance->call(GDScriptTestRunner::test_function_name, nullptr, 0, call_err); + instance->callp(GDScriptTestRunner::test_function_name, nullptr, 0, call_err); // Tear down output handlers. remove_print_handler(&_print_handler); @@ -571,7 +611,7 @@ bool GDScriptTest::generate_output() { } Error err = OK; - FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); + Ref<FileAccess> out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); if (err != OK) { return false; } @@ -580,7 +620,6 @@ bool GDScriptTest::generate_output() { output += "\n"; // Make sure to insert newline for CI static checks. out_file->store_string(output); - out_file->close(); return true; } diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h index 98c57dc97c..d6c6419e21 100644 --- a/modules/gdscript/tests/gdscript_test_runner.h +++ b/modules/gdscript/tests/gdscript_test_runner.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -63,8 +63,8 @@ public: private: struct ErrorHandlerData { - TestResult *result; - GDScriptTest *self; + TestResult *result = nullptr; + GDScriptTest *self = nullptr; ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) { result = p_result; self = p_this; diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h index cf4e61f07d..0722fb800e 100644 --- a/modules/gdscript/tests/gdscript_test_runner_suite.h +++ b/modules/gdscript/tests/gdscript_test_runner_suite.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_assign_with_wrong_enum_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_assign_with_wrong_enum_type.gd new file mode 100644 index 0000000000..928c886650 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_assign_with_wrong_enum_type.gd @@ -0,0 +1,10 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } +enum MyOtherEnum { OTHER_ENUM_VALUE_1, OTHER_ENUM_VALUE_2 } + +# Different enum types can't be assigned without casting. +var class_var: MyEnum = MyEnum.ENUM_VALUE_1 + +func test(): + print(class_var) + class_var = MyOtherEnum.OTHER_ENUM_VALUE_2 + print(class_var) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_assign_with_wrong_enum_type.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_assign_with_wrong_enum_type.out new file mode 100644 index 0000000000..fde7e92f8c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_assign_with_wrong_enum_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a value of type "MyOtherEnum (enum)" to a target of type "MyEnum (enum)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_init_with_wrong_enum_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_init_with_wrong_enum_type.gd new file mode 100644 index 0000000000..03a1711d7b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_init_with_wrong_enum_type.gd @@ -0,0 +1,8 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } +enum MyOtherEnum { OTHER_ENUM_VALUE_1, OTHER_ENUM_VALUE_2 } + +# Different enum types can't be assigned without casting. +var class_var: MyEnum = MyOtherEnum.OTHER_ENUM_VALUE_1 + +func test(): + print(class_var) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_init_with_wrong_enum_type.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_init_with_wrong_enum_type.out new file mode 100644 index 0000000000..b1710c798d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_class_var_init_with_wrong_enum_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Value of type "MyOtherEnum (enum)" cannot be assigned to a variable of type "MyEnum (enum)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_assign_with_wrong_enum_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_assign_with_wrong_enum_type.gd new file mode 100644 index 0000000000..d08d3dd7b2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_assign_with_wrong_enum_type.gd @@ -0,0 +1,8 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } +enum MyOtherEnum { OTHER_ENUM_VALUE_1, OTHER_ENUM_VALUE_2 } + +func test(): + var local_var: MyEnum = MyEnum.ENUM_VALUE_1 + print(local_var) + local_var = MyOtherEnum.OTHER_ENUM_VALUE_2 + print(local_var) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_assign_with_wrong_enum_type.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_assign_with_wrong_enum_type.out new file mode 100644 index 0000000000..fde7e92f8c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_assign_with_wrong_enum_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a value of type "MyOtherEnum (enum)" to a target of type "MyEnum (enum)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_init_with_wrong_enum_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_init_with_wrong_enum_type.gd new file mode 100644 index 0000000000..ca6d892218 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_init_with_wrong_enum_type.gd @@ -0,0 +1,6 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } +enum MyOtherEnum { OTHER_ENUM_VALUE_1, OTHER_ENUM_VALUE_2 } + +func test(): + var local_var: MyEnum = MyOtherEnum.OTHER_ENUM_VALUE_1 + print(local_var) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_init_with_wrong_enum_type.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_init_with_wrong_enum_type.out new file mode 100644 index 0000000000..b1710c798d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_local_var_init_with_wrong_enum_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Value of type "MyOtherEnum (enum)" cannot be assigned to a variable of type "MyEnum (enum)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_less.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_less.gd new file mode 100644 index 0000000000..435711fcaf --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_less.gd @@ -0,0 +1,10 @@ +func test(): + print("Shouldn't reach this") + +class Parent: + func my_function(_par1: int) -> int: + return 0 + +class Child extends Parent: + func my_function() -> int: + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_less.out b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_less.out new file mode 100644 index 0000000000..3baeb17066 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_less.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +The function signature doesn't match the parent. Parent signature is "int my_function(int)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_more.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_more.gd new file mode 100644 index 0000000000..2bd392e8f8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_more.gd @@ -0,0 +1,10 @@ +func test(): + print("Shouldn't reach this") + +class Parent: + func my_function(_par1: int) -> int: + return 0 + +class Child extends Parent: + func my_function(_pary1: int, _par2: int) -> int: + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_more.out b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_more.out new file mode 100644 index 0000000000..3baeb17066 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_count_more.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +The function signature doesn't match the parent. Parent signature is "int my_function(int)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_default_values.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_default_values.gd new file mode 100644 index 0000000000..49ec82ce2d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_default_values.gd @@ -0,0 +1,10 @@ +func test(): + print("Shouldn't reach this") + +class Parent: + func my_function(_par1: int = 0) -> int: + return 0 + +class Child extends Parent: + func my_function(_par1: int) -> int: + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_default_values.out b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_default_values.out new file mode 100644 index 0000000000..665c229339 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_default_values.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +The function signature doesn't match the parent. Parent signature is "int my_function(int = default)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_type.gd new file mode 100644 index 0000000000..4a17a7831f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_type.gd @@ -0,0 +1,10 @@ +func test(): + print("Shouldn't reach this") + +class Parent: + func my_function(_par1: int) -> int: + return 0 + +class Child extends Parent: + func my_function(_par1: Vector2) -> int: + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_type.out b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_type.out new file mode 100644 index 0000000000..3baeb17066 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_parameter_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +The function signature doesn't match the parent. Parent signature is "int my_function(int)". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_return_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_return_type.gd new file mode 100644 index 0000000000..b205ec96ef --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_return_type.gd @@ -0,0 +1,10 @@ +func test(): + print("Shouldn't reach this") + +class Parent: + func my_function() -> int: + return 0 + +class Child extends Parent: + func my_function() -> Vector2: + return Vector2() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_return_type.out b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_return_type.out new file mode 100644 index 0000000000..5b22739a93 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_dont_match_parent_signature_return_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +The function signature doesn't match the parent. Parent signature is "int my_function()". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out index 015ad756f8..6f7f0783f0 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out @@ -1,2 +1,2 @@ GDTEST_ANALYZER_ERROR -Invalid index type "bool" for a base of type "Array". +Cannot get index "true" from "[0, 1]". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd new file mode 100644 index 0000000000..05d9bd6a3d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/56702 + +func test(): + # somewhat obscure feature: referencing parameters in defaults, but only earlier ones! + ref_default("non-optional") + + +func ref_default(nondefault1, defa=nondefault1, defb=defc, defc=1): + prints(nondefault1, nondefault2, defa, defb, defc) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out new file mode 100644 index 0000000000..1d5b5bf393 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Identifier "defc" not declared in the current scope. diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_enum_to_int_typed_var.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_enum_to_int_typed_var.gd new file mode 100644 index 0000000000..edb785c8b6 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_enum_to_int_typed_var.gd @@ -0,0 +1,13 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } + +var class_var: int = MyEnum.ENUM_VALUE_1 + +func test(): + print(class_var) + class_var = MyEnum.ENUM_VALUE_2 + print(class_var) + + var local_var: int = MyEnum.ENUM_VALUE_1 + print(local_var) + local_var = MyEnum.ENUM_VALUE_2 + print(local_var) diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_enum_to_int_typed_var.out b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_enum_to_int_typed_var.out new file mode 100644 index 0000000000..5f53802c33 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_enum_to_int_typed_var.out @@ -0,0 +1,5 @@ +GDTEST_OK +0 +1 +0 +1 diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_int_cast_to_same_enum.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_int_cast_to_same_enum.gd new file mode 100644 index 0000000000..726e4fd413 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_int_cast_to_same_enum.gd @@ -0,0 +1,13 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } + +var class_var: MyEnum = 0 as MyEnum + +func test(): + print(class_var) + class_var = 1 as MyEnum + print(class_var) + + var local_var: MyEnum = 0 as MyEnum + print(local_var) + local_var = 1 as MyEnum + print(local_var) diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_int_cast_to_same_enum.out b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_int_cast_to_same_enum.out new file mode 100644 index 0000000000..5f53802c33 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_int_cast_to_same_enum.out @@ -0,0 +1,5 @@ +GDTEST_OK +0 +1 +0 +1 diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_other_enum_cast_to_same_enum.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_other_enum_cast_to_same_enum.gd new file mode 100644 index 0000000000..798912c987 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_other_enum_cast_to_same_enum.gd @@ -0,0 +1,14 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } +enum MyOtherEnum { OTHER_ENUM_VALUE_1, OTHER_ENUM_VALUE_2 } + +var class_var: MyEnum = MyOtherEnum.OTHER_ENUM_VALUE_1 as MyEnum + +func test(): + print(class_var) + class_var = MyOtherEnum.OTHER_ENUM_VALUE_2 as MyEnum + print(class_var) + + var local_var: MyEnum = MyOtherEnum.OTHER_ENUM_VALUE_1 as MyEnum + print(local_var) + local_var = MyOtherEnum.OTHER_ENUM_VALUE_2 as MyEnum + print(local_var) diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_other_enum_cast_to_same_enum.out b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_other_enum_cast_to_same_enum.out new file mode 100644 index 0000000000..5f53802c33 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_other_enum_cast_to_same_enum.out @@ -0,0 +1,5 @@ +GDTEST_OK +0 +1 +0 +1 diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_same_enum.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_same_enum.gd new file mode 100644 index 0000000000..2bfb318c3c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_same_enum.gd @@ -0,0 +1,13 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } + +var class_var: MyEnum = MyEnum.ENUM_VALUE_1 + +func test(): + print(class_var) + class_var = MyEnum.ENUM_VALUE_2 + print(class_var) + + var local_var: MyEnum = MyEnum.ENUM_VALUE_1 + print(local_var) + local_var = MyEnum.ENUM_VALUE_2 + print(local_var) diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_assign_same_enum.out b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_same_enum.out new file mode 100644 index 0000000000..5f53802c33 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_assign_same_enum.out @@ -0,0 +1,5 @@ +GDTEST_OK +0 +1 +0 +1 diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_is_treated_as_int.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_is_treated_as_int.gd new file mode 100644 index 0000000000..7022d14566 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_is_treated_as_int.gd @@ -0,0 +1,21 @@ +# Enum is equivalent to int for comparisons and operations. +enum MyEnum { + ZERO, + ONE, + TWO, +} + +enum OtherEnum { + ZERO, + ONE, + TWO, +} + +func test(): + print(MyEnum.ZERO == OtherEnum.ZERO) + print(MyEnum.ZERO == 1) + print(MyEnum.ZERO != OtherEnum.ONE) + print(MyEnum.ZERO != 0) + + print(MyEnum.ONE + OtherEnum.TWO) + print(2 - MyEnum.ONE) diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_is_treated_as_int.out b/modules/gdscript/tests/scripts/analyzer/features/enum_is_treated_as_int.out new file mode 100644 index 0000000000..c8f34c11db --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_is_treated_as_int.out @@ -0,0 +1,7 @@ +GDTEST_OK +true +false +true +false +3 +1 diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_type_is_treated_as_dictionary.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_type_is_treated_as_dictionary.gd new file mode 100644 index 0000000000..885d70408a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_type_is_treated_as_dictionary.gd @@ -0,0 +1,13 @@ +enum MyEnum { + ZERO, + ONE, + TWO, +} + +func test(): + for key in MyEnum.keys(): + prints(key, MyEnum[key]) + + # https://github.com/godotengine/godot/issues/55491 + for key in MyEnum: + prints(key, MyEnum[key]) diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_type_is_treated_as_dictionary.out b/modules/gdscript/tests/scripts/analyzer/features/enum_type_is_treated_as_dictionary.out new file mode 100644 index 0000000000..d29f53109c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_type_is_treated_as_dictionary.out @@ -0,0 +1,7 @@ +GDTEST_OK +ZERO 0 +ONE 1 +TWO 2 +ZERO 0 +ONE 1 +TWO 2 diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd new file mode 100644 index 0000000000..631e7be5ce --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd @@ -0,0 +1,14 @@ +func test(): + var instance := Parent.new() + instance.my_function({"a": 1}) + instance = Child.new() + instance.my_function({"a": 1}) + print("No failure") + +class Parent: + func my_function(_par1: Dictionary = {}) -> void: + pass + +class Child extends Parent: + func my_function(_par1: Dictionary = {}) -> void: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out new file mode 100644 index 0000000000..67f0045867 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out @@ -0,0 +1,2 @@ +GDTEST_OK +No failure diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.gd b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.gd new file mode 100644 index 0000000000..d678f3acfc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.gd @@ -0,0 +1,17 @@ +func test(): + var instance := Parent.new() + var result := instance.my_function(1) + print(result) + assert(result == 1) + instance = Child.new() + result = instance.my_function(2) + print(result) + assert(result == 0) + +class Parent: + func my_function(par1: int) -> int: + return par1 + +class Child extends Parent: + func my_function(_par1: int, par2: int = 0) -> int: + return par2 diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.out b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.out new file mode 100644 index 0000000000..fc5315a501 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.out @@ -0,0 +1,3 @@ +GDTEST_OK +1 +0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd new file mode 100644 index 0000000000..877a4ea221 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd @@ -0,0 +1,15 @@ +@warning_ignore(unused_private_class_variable) +var _unused = 2 + +@warning_ignore(unused_variable) +func test(): + print("test") + var unused = 3 + + @warning_ignore(redundant_await) + print(await regular_func()) + + print("done") + +func regular_func(): + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out new file mode 100644 index 0000000000..42292774a0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out @@ -0,0 +1,4 @@ +GDTEST_OK +test +0 +done diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd new file mode 100644 index 0000000000..e9690ee93d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd @@ -0,0 +1,2 @@ +func test(): + $=$ diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out new file mode 100644 index 0000000000..b3dc181a22 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.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/match_multiple_variable_binds_in_branch.gd b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd new file mode 100644 index 0000000000..4608c778aa --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd @@ -0,0 +1,4 @@ +func test(): + match 1: + [[[var a]]], 2: + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out new file mode 100644 index 0000000000..1cdc24683b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Cannot use a variable bind with multiple patterns. diff --git a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out index 67c7e28046..3cdafb04a9 100644 --- a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out +++ b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out @@ -10,5 +10,5 @@ wildcard [1,2,[1,{1:2,2:var z,..}]] 3 [1,2,[1,{1:2,2:var z,..}]] -[1, 3, 5, 123] +[1, 3, 5, "123"] wildcard diff --git a/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd new file mode 100644 index 0000000000..cc78309ae4 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd @@ -0,0 +1,58 @@ +# https://github.com/godotengine/godot/issues/50285 + +@warning_ignore(unused_local_constant) +func test(): + const CONST_INNER_DICTIONARY = { "key": true } + const CONST_NESTED_DICTIONARY_OLD_WORKAROUND = { + "key1": "value1", + "key2": CONST_INNER_DICTIONARY + } + # All of these should be valid + const CONST_NESTED_DICTIONARY = { + "key1": "value1", + "key2": { "key": true } + } + + + const CONST_DICTIONARY_WITH_ARRAY = { + "key1": [1,2,3,4] + } + + const CONST_NESTED_ARRAY = [[],[2],[1,2,3]] + const CONST_ARRAY_WITH_DICT = [{"key1": 3}, {"key2": 5}] + + const THREE_DIMENSIONAL_ARRAY = [[[],[],[]],[[],[],[]],[[],[],[]]] + const MANY_NESTED_DICT = { + "key1": { + "key11": { + "key111": {}, + "key112": {}, + }, + "key12": { + "key121": {}, + "key122": {}, + }, + }, + "key2": { + "key21": { + "key211": {}, + "key212": {}, + }, + "key22": { + "key221": {}, + "key222": {}, + }, + } + } + + + const CONST_ARRAY_ACCESS = [1,2,3][0] + const CONST_DICT_ACCESS = {"key1": 5}["key1"] + + const CONST_ARRAY_NESTED_ACCESS = [[1,2,3],[4,5,6],[8,9,10]][0][1] + const CONST_DICT_NESTED_ACCESS = {"key1": {"key2": 1}}["key1"]["key2"] + + print(CONST_ARRAY_ACCESS) + print(CONST_DICT_ACCESS) + print(CONST_ARRAY_NESTED_ACCESS) + print(CONST_DICT_NESTED_ACCESS) diff --git a/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out new file mode 100644 index 0000000000..5883fc5c18 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out @@ -0,0 +1,5 @@ +GDTEST_OK +1 +5 +2 +1 diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd b/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd new file mode 100644 index 0000000000..eb392672eb --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd @@ -0,0 +1,40 @@ +# Test access visibility of parent elements in nested class architectures. +class Parent: + const parent_const := 1 + + var parent_variable := 2 + + signal parent_signal + + var parent_attribute: int: + get: + return 3 + + func parent_func(): + return 4 + + class Nested: + const nested_const := 5 + + +class Child extends Parent: + func child_test(): + print(parent_const) + print(self.parent_const) + print(parent_variable) + print(self.parent_variable) + print(parent_signal.get_name()) + print(self.parent_signal.get_name()) + print(parent_attribute) + print(self.parent_attribute) + print(parent_func.get_method()) + print(self.parent_func.get_method()) + print(parent_func()) + print(self.parent_func()) + print(Nested.nested_const) + print(self.Nested.nested_const) + print(Parent.Nested.nested_const) + + +func test(): + Child.new().child_test() diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.out b/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.out new file mode 100644 index 0000000000..09e87bccfa --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.out @@ -0,0 +1,16 @@ +GDTEST_OK +1 +1 +2 +2 +parent_signal +parent_signal +3 +3 +parent_func +parent_func +4 +4 +5 +5 +5 diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.out b/modules/gdscript/tests/scripts/parser/features/dictionary.out index 54083c1afc..5f999f573a 100644 --- a/modules/gdscript/tests/scripts/parser/features/dictionary.out +++ b/modules/gdscript/tests/scripts/parser/features/dictionary.out @@ -7,8 +7,8 @@ null false empty array zero Vector2i -{22:{4:[nesting, arrays]}} -{4:[nesting, arrays]} -[nesting, arrays] +{22:{4:["nesting", "arrays"]}} +{4:["nesting", "arrays"]} +["nesting", "arrays"] nesting arrays diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out index 447d7e223c..5143d040a9 100644 --- a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out @@ -1,2 +1,2 @@ GDTEST_OK -{2:4, a:1, b:2, with spaces:3} +{"a":1, "b":2, "with spaces":3, "2":4} diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out index 62be807a1f..dd28609850 100644 --- a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out @@ -1,2 +1,2 @@ GDTEST_OK -{hello:{world:{is:beautiful}}} +{"hello":{"world":{"is":"beautiful"}}} diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd new file mode 100644 index 0000000000..a0ae7fb17c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd @@ -0,0 +1,6 @@ +func test(): + match [1, 2, 3]: + [var a, var b, var c]: + print(a == 1) + print(b == 2) + print(c == 3) diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out new file mode 100644 index 0000000000..316db6d748 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out @@ -0,0 +1,4 @@ +GDTEST_OK +true +true +true diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out index 4009160439..8b8c33202f 100644 --- a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out +++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out @@ -1,5 +1,5 @@ GDTEST_OK -{8:{key:value}} -{key:value} +{8:{"key":"value"}} +{"key":"value"} value value diff --git a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd index 9ad98b78a8..e4d6a72f90 100644 --- a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd +++ b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd @@ -6,7 +6,7 @@ signal a # No parameters. signal b() -# With paramters. +# With parameters. signal c(a, b, c) # With parameters multiline. diff --git a/modules/gdscript/tests/scripts/parser/warnings/enum_assign_int_without_casting.gd b/modules/gdscript/tests/scripts/parser/warnings/enum_assign_int_without_casting.gd new file mode 100644 index 0000000000..2be1024214 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/enum_assign_int_without_casting.gd @@ -0,0 +1,15 @@ +enum MyEnum { ENUM_VALUE_1, ENUM_VALUE_2 } + +# Assigning int value to enum-typed variable without explicit cast causes a warning. +# While it is valid it may be a mistake in the assignment. +var class_var: MyEnum = 0 + +func test(): + print(class_var) + class_var = 1 + print(class_var) + + var local_var: MyEnum = 0 + print(local_var) + local_var = 1 + print(local_var) diff --git a/modules/gdscript/tests/scripts/parser/warnings/enum_assign_int_without_casting.out b/modules/gdscript/tests/scripts/parser/warnings/enum_assign_int_without_casting.out new file mode 100644 index 0000000000..eef13bbff8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/enum_assign_int_without_casting.out @@ -0,0 +1,21 @@ +GDTEST_OK +>> WARNING +>> Line: 5 +>> INT_ASSIGNED_TO_ENUM +>> Integer used when an enum value is expected. If this is intended cast the integer to the enum type. +>> WARNING +>> Line: 9 +>> INT_ASSIGNED_TO_ENUM +>> Integer used when an enum value is expected. If this is intended cast the integer to the enum type. +>> WARNING +>> Line: 12 +>> INT_ASSIGNED_TO_ENUM +>> Integer used when an enum value is expected. If this is intended cast the integer to the enum type. +>> WARNING +>> Line: 14 +>> INT_ASSIGNED_TO_ENUM +>> Integer used when an enum value is expected. If this is intended cast the integer to the enum type. +0 +1 +0 +1 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 index 10780b5379..7b3c112fe9 100644 --- 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 @@ -1,3 +1,4 @@ +#debug-only func test(): var node := Node.new() var inside_tree = node.is_inside_tree 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 index e585c374e2..fe48ade26b 100644 --- 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 @@ -2,5 +2,5 @@ GDTEST_RUNTIME_ERROR >> SCRIPT ERROR >> on function: test() >> runtime/errors/callable_call_after_free_object.gd ->> 5 +>> 6 >> Attempt to call function 'null::is_inside_tree (Callable)' on a null instance. diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd new file mode 100644 index 0000000000..3d063869ab --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd @@ -0,0 +1,23 @@ +var member = "foo" + +func bar(): + print("bar") + +func test(): + var lambda1 = func(): + print(member) + lambda1.call() + + var lambda2 = func(): + var nested = func(): + print(member) + nested.call() + lambda2.call() + + var lambda3 = func(): + bar() + lambda3.call() + + var lambda4 = func(): + return self + print(lambda4.call() == self) diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out new file mode 100644 index 0000000000..53d602b234 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out @@ -0,0 +1,5 @@ +GDTEST_OK +foo +foo +bar +true diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd new file mode 100644 index 0000000000..8156b4ec68 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd @@ -0,0 +1,35 @@ +# https://github.com/godotengine/godot/issues/56702 + +func test(): + const_default() + func_result_default() + # calling again will run the initializer again, + # as the default is not evaluated at time of defining the function (as in python) + # but every time the function is called (as in C++) + func_result_default() + lots_of_defaults("non-optional") + # somewhat obscure feature: referencing earlier parameters + ref_default("non-optional", 42) + + +func const_default(param=42): + print(param) + + +var default_val := 0 + +func get_default(): + default_val += 1 + return default_val + + +func func_result_default(param=get_default()): + print(param) + + +func lots_of_defaults(nondefault, one=1, two=2, three=get_default()): + prints(nondefault, one, two, three) + + +func ref_default(nondefault1, nondefault2, defa=nondefault1, defb=nondefault2 - 1): + prints(nondefault1, nondefault2, defa, defb) diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.out b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out new file mode 100644 index 0000000000..50e0885ae5 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out @@ -0,0 +1,6 @@ +GDTEST_OK +42 +1 +2 +non-optional 1 2 3 +non-optional 42 non-optional 41 diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out index 7670fc0128..d4468737a5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.out +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out @@ -21,14 +21,14 @@ hello/world RID(0) Node::get_name Node::[signal]property_list_changed -{hello:123} -[hello, 123] +{"hello":123} +["hello", 123] [255, 0, 1] [-1, 0, 1] [-1, 0, 1] [-1, 0, 1] [-1, 0, 1] -[hello, world] +["hello", "world"] [(1, 1), (0, 0)] [(1, 1, 1), (0, 0, 0)] [(1, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1)] diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 80eabc1596..d8f60d5e9b 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -204,8 +204,8 @@ void test(TestType p_type) { return; } - FileAccessRef fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test); + Ref<FileAccess> fa = FileAccess::open(test, FileAccess::READ); + ERR_FAIL_COND_MSG(fa.is_null(), "Could not open file: " + test); // Initialize the language for the test routine. init_language(fa->get_path_absolute().get_base_dir()); diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h index c7ee5a2208..b6b1f26203 100644 --- a/modules/gdscript/tests/test_gdscript.h +++ b/modules/gdscript/tests/test_gdscript.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub index 1954a32697..22ef1b5ea9 100644 --- a/modules/glslang/SCsub +++ b/modules/glslang/SCsub @@ -12,7 +12,6 @@ thirdparty_obj = [] if env["builtin_glslang"]: thirdparty_dir = "#thirdparty/glslang/" thirdparty_sources = [ - "glslang/CInterface/glslang_c_interface.cpp", "glslang/MachineIndependent/attribute.cpp", "glslang/MachineIndependent/Constant.cpp", "glslang/MachineIndependent/glslang_tab.cpp", @@ -44,7 +43,6 @@ if env["builtin_glslang"]: "glslang/GenericCodeGen/CodeGen.cpp", "glslang/GenericCodeGen/Link.cpp", "OGLCompilersDLL/InitializeDll.cpp", - "SPIRV/CInterface/spirv_c_interface.cpp", "SPIRV/disassemble.cpp", "SPIRV/doc.cpp", "SPIRV/GlslangToSpv.cpp", @@ -54,7 +52,6 @@ if env["builtin_glslang"]: "SPIRV/SpvPostProcess.cpp", "SPIRV/SPVRemapper.cpp", "SPIRV/SpvTools.cpp", - "StandAlone/ResourceLimits.cpp", ] if env["platform"] == "windows": @@ -65,10 +62,12 @@ if env["builtin_glslang"]: thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] # Treat glslang headers as system headers to avoid raising warnings. Not supported on MSVC. + # Include `#thirdparty` to workaround mismatch between location of `SPIRV` in library source + # and in installed public headers. if not env.msvc: - env_glslang.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path]) + env_glslang.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path, "-isystem", Dir("#thirdparty").path]) else: - env_glslang.Prepend(CPPPATH=[thirdparty_dir]) + env_glslang.Prepend(CPPPATH=[thirdparty_dir, "#thirdparty"]) env_glslang.Append(CPPDEFINES=["ENABLE_OPT=0"]) diff --git a/modules/glslang/glslang_resource_limits.h b/modules/glslang/glslang_resource_limits.h new file mode 100644 index 0000000000..02d3daff07 --- /dev/null +++ b/modules/glslang/glslang_resource_limits.h @@ -0,0 +1,147 @@ +/*************************************************************************/ +/* glslang_resource_limits.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 GLSLANG_RESOURCE_LIMITS_H +#define GLSLANG_RESOURCE_LIMITS_H + +#include <glslang/Include/ResourceLimits.h> + +// Synchronized with upstream glslang/StandAlone/ResourceLimits.cpp which is not +// part of the public API. + +const TBuiltInResource DefaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, + + /* .limits = */ { + /* .nonInductiveForLoops = */ true, + /* .whileLoops = */ true, + /* .doWhileLoops = */ true, + /* .generalUniformIndexing = */ true, + /* .generalAttributeMatrixVectorIndexing = */ true, + /* .generalVaryingIndexing = */ true, + /* .generalSamplerIndexing = */ true, + /* .generalVariableIndexing = */ true, + /* .generalConstantMatrixVectorIndexing = */ true, + } +}; + +#endif // GLSLANG_RESOURCE_LIMITS_H diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index 69bf59f848..64891d9ee8 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,10 +32,11 @@ #include "servers/rendering/rendering_device.h" -#include <SPIRV/GlslangToSpv.h> -#include <StandAlone/ResourceLimits.h> +#include "glslang_resource_limits.h" + #include <glslang/Include/Types.h> #include <glslang/Public/ShaderLang.h> +#include <glslang/SPIRV/GlslangToSpv.h> 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; @@ -129,7 +130,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage std::string pre_processed_code; //preprocess - if (!shader.preprocess(&glslang::DefaultTBuiltInResource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) { + if (!shader.preprocess(&DefaultTBuiltInResource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) { if (r_error) { (*r_error) = "Failed pre-process:\n"; (*r_error) += shader.getInfoLog(); @@ -144,7 +145,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage shader.setStrings(&cs_strings, 1); //parse - if (!shader.parse(&glslang::DefaultTBuiltInResource, DefaultVersion, false, messages)) { + if (!shader.parse(&DefaultTBuiltInResource, DefaultVersion, false, messages)) { if (r_error) { (*r_error) = "Failed parse:\n"; (*r_error) += shader.getInfoLog(); @@ -189,17 +190,22 @@ static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities * 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 +void initialize_glslang_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) { + return; + } + + // 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_to_spirv_function(_compile_shader_glsl); RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl); } -void register_glslang_types() { -} +void uninitialize_glslang_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) { + return; + } -void unregister_glslang_types() { glslang::FinalizeProcess(); } diff --git a/modules/glslang/register_types.h b/modules/glslang/register_types.h index a1264b77c9..d9611cc02f 100644 --- a/modules/glslang/register_types.h +++ b/modules/glslang/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,8 +33,9 @@ #define MODULE_GLSLANG_HAS_PREREGISTER -void preregister_glslang_types(); -void register_glslang_types(); -void unregister_glslang_types(); +#include "modules/register_module_types.h" + +void initialize_glslang_module(ModuleInitializationLevel p_level); +void uninitialize_glslang_module(ModuleInitializationLevel p_level); #endif // GLSLANG_REGISTER_TYPES_H diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub index 5d03ee8361..3379404a00 100644 --- a/modules/gltf/SCsub +++ b/modules/gltf/SCsub @@ -4,7 +4,8 @@ Import("env") Import("env_modules") env_gltf = env_modules.Clone() -env_gltf.Prepend(CPPPATH=["."]) # Godot's own source files env_gltf.add_source_files(env.modules_sources, "*.cpp") +if env["tools"]: + env_gltf.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/gltf/config.py b/modules/gltf/config.py index a4736321fa..189b5a831a 100644 --- a/modules/gltf/config.py +++ b/modules/gltf/config.py @@ -8,12 +8,16 @@ def configure(env): def get_doc_classes(): return [ - "EditorSceneImporterGLTF", + "EditorSceneFormatImporterBlend", + "EditorSceneFormatImporterFBX", + "EditorSceneFormatImporterGLTF", "GLTFAccessor", "GLTFAnimation", "GLTFBufferView", "GLTFCamera", "GLTFDocument", + "GLTFDocumentExtension", + "GLTFDocumentExtensionConvertImporterMesh", "GLTFLight", "GLTFMesh", "GLTFNode", @@ -22,8 +26,6 @@ def get_doc_classes(): "GLTFSpecGloss", "GLTFState", "GLTFTexture", - "GLTFDocumentExtension", - "GLTFDocumentExtensionConvertImporterMesh", ] diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml new file mode 100644 index 0000000000..ca8eb9854f --- /dev/null +++ b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorSceneFormatImporterBlend" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Importer for Blender's [code].blend[/code] scene file format. + </brief_description> + <description> + Imports Blender scenes in the [code].blend[/code] file format through the glTF 2.0 3D import pipeline. This importer requires Blender to be installed by the user, so that it can be used to export the scene as glTF 2.0. + The location of the Blender binary is set via the [code]filesystem/import/blender/blender3_path[/code] editor setting. + This importer is only used if [member ProjectSettings.filesystem/import/blender/enabled] is enabled, otherwise [code].blend[/code] files present in the project folder are not imported. + Blend import requires Blender 3.0. + Internally, the EditorSceneFormatImporterBlend uses the Blender glTF "Use Original" mode to reference external textures. + </description> + <tutorials> + </tutorials> +</class> diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml new file mode 100644 index 0000000000..6754d963ff --- /dev/null +++ b/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorSceneFormatImporterFBX" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Importer for the [code].fbx[/code] scene file format. + </brief_description> + <description> + Imports Autodesk FBX 3D scenes by way of converting them to glTF 2.0 using the FBX2glTF command line tool. + The location of the FBX2glTF binary is set via the [code]filesystem/import/fbx/fbx2gltf_path[/code] editor setting. + This importer is only used if [member ProjectSettings.filesystem/import/fbx/enabled] is enabled, otherwise [code].fbx[/code] files present in the project folder are not imported. + </description> + <tutorials> + </tutorials> +</class> diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml new file mode 100644 index 0000000000..5a6a2f52d9 --- /dev/null +++ b/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorSceneFormatImporterGLTF" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> +</class> diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index ae81cae81a..b73a4f8c5f 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFAccessor" inherits="Resource" version="4.0"> +<class name="GLTFAccessor" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml index 70480c2b38..e2991170a4 100644 --- a/modules/gltf/doc_classes/GLTFAnimation.xml +++ b/modules/gltf/doc_classes/GLTFAnimation.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFAnimation" inherits="Resource" version="4.0"> +<class name="GLTFAnimation" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml index f58aa46508..00b6ccbe7d 100644 --- a/modules/gltf/doc_classes/GLTFBufferView.xml +++ b/modules/gltf/doc_classes/GLTFBufferView.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFBufferView" inherits="Resource" version="4.0"> +<class name="GLTFBufferView" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml index 3682df5951..9b9eff6141 100644 --- a/modules/gltf/doc_classes/GLTFCamera.xml +++ b/modules/gltf/doc_classes/GLTFCamera.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFCamera" inherits="Resource" version="4.0"> +<class name="GLTFCamera" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 8d8e25e8b3..cb0e3b6754 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -1,32 +1,60 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFDocument" inherits="Resource" version="4.0"> +<class name="GLTFDocument" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> + Append a glTF2 3d format from a file, buffer or scene and then write to the filesystem, buffer or scene. </description> <tutorials> </tutorials> <methods> - <method name="import_scene"> - <return type="Node" /> + <method name="append_from_buffer"> + <return type="int" enum="Error" /> + <argument index="0" name="bytes" type="PackedByteArray" /> + <argument index="1" name="base_path" type="String" /> + <argument index="2" name="state" type="GLTFState" /> + <argument index="3" name="flags" type="int" default="0" /> + <argument index="4" name="bake_fps" type="int" default="30" /> + <description> + </description> + </method> + <method name="append_from_file"> + <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> - <argument index="1" name="flags" type="int" default="0" /> - <argument index="2" name="bake_fps" type="int" default="30" /> - <argument index="3" name="state" type="GLTFState" default="null" /> + <argument index="1" name="state" type="GLTFState" /> + <argument index="2" name="flags" type="int" default="0" /> + <argument index="3" name="bake_fps" type="int" default="30" /> + <argument index="4" name="base_path" type="String" default="""" /> <description> - Import a scene from glTF2 ".gltf" or ".glb" file. </description> </method> - <method name="save_scene"> + <method name="append_from_scene"> <return type="int" enum="Error" /> <argument index="0" name="node" type="Node" /> + <argument index="1" name="state" type="GLTFState" /> + <argument index="2" name="flags" type="int" default="0" /> + <argument index="3" name="bake_fps" type="int" default="30" /> + <description> + </description> + </method> + <method name="generate_buffer"> + <return type="PackedByteArray" /> + <argument index="0" name="state" type="GLTFState" /> + <description> + </description> + </method> + <method name="generate_scene"> + <return type="Node" /> + <argument index="0" name="state" type="GLTFState" /> + <argument index="1" name="bake_fps" type="int" default="30" /> + <description> + </description> + </method> + <method name="write_to_filesystem"> + <return type="int" enum="Error" /> + <argument index="0" name="state" type="GLTFState" /> <argument index="1" name="path" type="String" /> - <argument index="2" name="src_path" type="String" /> - <argument index="3" name="flags" type="int" default="0" /> - <argument index="4" name="bake_fps" type="float" default="30" /> - <argument index="5" name="state" type="GLTFState" default="null" /> <description> - Save a scene as a glTF2 ".glb" or ".gltf" file. </description> </method> </methods> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index 390bd3b30b..03b4380ff4 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFDocumentExtension" inherits="Resource" version="4.0"> +<class name="GLTFDocumentExtension" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml index 452eec5f4f..70268fc0c9 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.0"> +<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index b4f03cd1ed..354cd48a06 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFLight" inherits="Resource" version="4.0"> +<class name="GLTFLight" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index 58853217e2..bac351cc20 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFMesh" inherits="Resource" version="4.0"> +<class name="GLTFMesh" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index f27965ea07..e933e6046a 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFNode" inherits="Resource" version="4.0"> +<class name="GLTFNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml index 037c3545a6..dad985e886 100644 --- a/modules/gltf/doc_classes/GLTFSkeleton.xml +++ b/modules/gltf/doc_classes/GLTFSkeleton.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFSkeleton" inherits="Resource" version="4.0"> +<class name="GLTFSkeleton" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml index ad4f017584..b6a2bdb957 100644 --- a/modules/gltf/doc_classes/GLTFSkin.xml +++ b/modules/gltf/doc_classes/GLTFSkin.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFSkin" inherits="Resource" version="4.0"> +<class name="GLTFSkin" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml index 6b8f86ed1c..8433cf8dd7 100644 --- a/modules/gltf/doc_classes/GLTFSpecGloss.xml +++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFSpecGloss" inherits="Resource" version="4.0"> +<class name="GLTFSpecGloss" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 6d03d0ecf8..a59fa900bc 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFState" inherits="Resource" version="4.0"> +<class name="GLTFState" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml index 7c88d2318e..c0bc424168 100644 --- a/modules/gltf/doc_classes/GLTFTexture.xml +++ b/modules/gltf/doc_classes/GLTFTexture.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GLTFTexture" inherits="Resource" version="4.0"> +<class name="GLTFTexture" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp index 25fda7ef3b..95db1c0965 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,20 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if TOOLS_ENABLED +#ifdef TOOLS_ENABLED + #include "editor_scene_exporter_gltf_plugin.h" + +#include "../gltf_document.h" +#include "../gltf_state.h" + #include "core/config/project_settings.h" #include "core/error/error_list.h" #include "core/object/object.h" #include "core/templates/vector.h" +#include "editor/editor_file_dialog.h" #include "editor/editor_file_system.h" -#include "gltf_document.h" +#include "editor/editor_node.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/gui/check_box.h" #include "scene/main/node.h" -#include "editor/editor_node.h" - String SceneExporterGLTFPlugin::get_name() const { return "ConvertGLTF2"; } @@ -50,10 +54,9 @@ bool SceneExporterGLTFPlugin::has_main_screen() const { return false; } -SceneExporterGLTFPlugin::SceneExporterGLTFPlugin(EditorNode *p_node) { - editor = p_node; +SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() { file_export_lib = memnew(EditorFileDialog); - editor->get_gui_base()->add_child(file_export_lib); + EditorNode::get_singleton()->get_gui_base()->add_child(file_export_lib); file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action)); file_export_lib->set_title(TTR("Export Library")); file_export_lib->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); @@ -61,30 +64,41 @@ SceneExporterGLTFPlugin::SceneExporterGLTFPlugin(EditorNode *p_node) { file_export_lib->clear_filters(); file_export_lib->add_filter("*.glb"); file_export_lib->add_filter("*.gltf"); - file_export_lib->set_title(TTR("Export Mesh GLTF2")); - String gltf_scene_name = TTR("Export GLTF..."); - add_tool_menu_item(gltf_scene_name, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2)); + file_export_lib->set_title(TTR("Export Scene to glTF 2.0 File")); + + PopupMenu *menu = get_export_as_menu(); + int idx = menu->get_item_count(); + menu->add_item(TTR("glTF 2.0 Scene...")); + menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2)); } void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) { - Node *root = editor->get_tree()->get_edited_scene_root(); + Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); if (!root) { - editor->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); + EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); return; } List<String> deps; Ref<GLTFDocument> doc; doc.instantiate(); - Error err = doc->save_scene(root, p_file, p_file, 0, 30.0f, Ref<GLTFState>()); + Ref<GLTFState> state; + state.instantiate(); + int32_t flags = 0; + flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; + Error err = doc->append_from_scene(root, state, flags, 30.0f); + if (err != OK) { + ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); + } + err = doc->write_to_filesystem(state, p_file); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } } void SceneExporterGLTFPlugin::convert_scene_to_gltf2() { - Node *root = editor->get_tree()->get_edited_scene_root(); + Node *root = EditorNode::get_singleton()->get_tree()->get_edited_scene_root(); if (!root) { - editor->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); + EditorNode::get_singleton()->show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); return; } String filename = String(root->get_scene_file_path().get_file().get_basename()); diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h index 89a8e27053..5af46bc752 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,15 +31,14 @@ #ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H #define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H -#if TOOLS_ENABLED -#include "editor/editor_plugin.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_plugin.h" #include "editor_scene_importer_gltf.h" class SceneExporterGLTFPlugin : public EditorPlugin { GDCLASS(SceneExporterGLTFPlugin, EditorPlugin); - EditorNode *editor = nullptr; EditorFileDialog *file_export_lib = nullptr; void _gltf2_dialog_action(String p_file); void convert_scene_to_gltf2(); @@ -47,7 +46,9 @@ class SceneExporterGLTFPlugin : public EditorPlugin { public: virtual String get_name() const override; bool has_main_screen() const override; - SceneExporterGLTFPlugin(class EditorNode *p_node); + SceneExporterGLTFPlugin(); }; + #endif // TOOLS_ENABLED + #endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp new file mode 100644 index 0000000000..173d5131cf --- /dev/null +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -0,0 +1,575 @@ +/*************************************************************************/ +/* editor_scene_importer_blend.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "editor_scene_importer_blend.h" + +#ifdef TOOLS_ENABLED + +#include "../gltf_document.h" +#include "../gltf_state.h" + +#include "core/config/project_settings.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" +#include "main/main.h" +#include "scene/main/node.h" +#include "scene/resources/animation.h" + +#ifdef WINDOWS_ENABLED +// Code by Pedro Estebanez (https://github.com/godotengine/godot/pull/59766) +#include <shlwapi.h> +#endif + +uint32_t EditorSceneFormatImporterBlend::get_import_flags() const { + return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; +} + +void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions) const { + r_extensions->push_back("blend"); +} + +Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags, + const Map<StringName, Variant> &p_options, int p_bake_fps, + List<String> *r_missing_deps, Error *r_err) { + // Get global paths for source and sink. + + // Escape paths to be valid Python strings to embed in the script. + const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape(); + const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file( + vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text())); + const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape(); + + // Handle configuration options. + + String parameters_arg; + + if (p_options.has(SNAME("blender/nodes/custom_properties")) && p_options[SNAME("blender/nodes/custom_properties")]) { + parameters_arg += "export_extras=True,"; + } else { + parameters_arg += "export_extras=False,"; + } + if (p_options.has(SNAME("blender/meshes/skins")) && p_options[SNAME("blender/meshes/skins")]) { + int32_t skins = p_options["blender/meshes/skins"]; + if (skins == BLEND_BONE_INFLUENCES_NONE) { + parameters_arg += "export_all_influences=False,"; + } else if (skins == BLEND_BONE_INFLUENCES_COMPATIBLE) { + parameters_arg += "export_all_influences=False,"; + } else if (skins == BLEND_BONE_INFLUENCES_ALL) { + parameters_arg += "export_all_influences=True,"; + } + parameters_arg += "export_skins=True,"; + } else { + parameters_arg += "export_skins=False,"; + } + if (p_options.has(SNAME("blender/materials/export_materials")) && p_options[SNAME("blender/materials/export_materials")]) { + int32_t exports = p_options["blender/materials/export_materials"]; + if (exports == BLEND_MATERIAL_EXPORT_PLACEHOLDER) { + parameters_arg += "export_materials='PLACEHOLDER',"; + } else if (exports == BLEND_MATERIAL_EXPORT_EXPORT) { + parameters_arg += "export_materials='EXPORT',"; + } + } else { + parameters_arg += "export_materials='PLACEHOLDER',"; + } + if (p_options.has(SNAME("blender/nodes/cameras")) && p_options[SNAME("blender/nodes/cameras")]) { + parameters_arg += "export_cameras=True,"; + } else { + parameters_arg += "export_cameras=False,"; + } + if (p_options.has(SNAME("blender/nodes/punctual_lights")) && p_options[SNAME("blender/nodes/punctual_lights")]) { + parameters_arg += "export_lights=True,"; + } else { + parameters_arg += "export_lights=False,"; + } + if (p_options.has(SNAME("blender/meshes/colors")) && p_options[SNAME("blender/meshes/colors")]) { + parameters_arg += "export_colors=True,"; + } else { + parameters_arg += "export_colors=False,"; + } + if (p_options.has(SNAME("blender/nodes/visible")) && p_options[SNAME("blender/nodes/visible")]) { + int32_t visible = p_options["blender/nodes/visible"]; + if (visible == BLEND_VISIBLE_VISIBLE_ONLY) { + parameters_arg += "use_visible=True,"; + } else if (visible == BLEND_VISIBLE_RENDERABLE) { + parameters_arg += "use_renderable=True,"; + } else if (visible == BLEND_VISIBLE_ALL) { + parameters_arg += "use_visible=False,use_renderable=False,"; + } + } else { + parameters_arg += "use_visible=False,use_renderable=False,"; + } + + if (p_options.has(SNAME("blender/meshes/uvs")) && p_options[SNAME("blender/meshes/uvs")]) { + parameters_arg += "export_texcoords=True,"; + } else { + parameters_arg += "export_texcoords=False,"; + } + if (p_options.has(SNAME("blender/meshes/normals")) && p_options[SNAME("blender/meshes/normals")]) { + parameters_arg += "export_normals=True,"; + } else { + parameters_arg += "export_normals=False,"; + } + if (p_options.has(SNAME("blender/meshes/tangents")) && p_options[SNAME("blender/meshes/tangents")]) { + parameters_arg += "export_tangents=True,"; + } else { + parameters_arg += "export_tangents=False,"; + } + if (p_options.has(SNAME("blender/animation/group_tracks")) && p_options[SNAME("blender/animation/group_tracks")]) { + parameters_arg += "export_nla_strips=True,"; + } else { + parameters_arg += "export_nla_strips=False,"; + } + if (p_options.has(SNAME("blender/animation/limit_playback")) && p_options[SNAME("blender/animation/limit_playback")]) { + parameters_arg += "export_frame_range=True,"; + } else { + parameters_arg += "export_frame_range=False,"; + } + if (p_options.has(SNAME("blender/animation/always_sample")) && p_options[SNAME("blender/animation/always_sample")]) { + parameters_arg += "export_force_sampling=True,"; + } else { + parameters_arg += "export_force_sampling=False,"; + } + if (p_options.has(SNAME("blender/meshes/export_bones_deforming_mesh_only")) && p_options[SNAME("blender/meshes/export_bones_deforming_mesh_only")]) { + parameters_arg += "export_def_bones=True,"; + } else { + parameters_arg += "export_def_bones=False,"; + } + if (p_options.has(SNAME("blender/nodes/modifiers")) && p_options[SNAME("blender/nodes/modifiers")]) { + parameters_arg += "export_apply=True"; + } else { + parameters_arg += "export_apply=False"; + } + + String unpack_all; + if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) { + unpack_all = "bpy.ops.file.unpack_all(method='USE_LOCAL');"; + } + + // Prepare Blender export script. + + String common_args = vformat("filepath='%s',", sink_global) + + "export_format='GLTF_SEPARATE'," + "export_yup=True," + + parameters_arg; + String script = + String("import bpy, sys;") + + "print('Blender 3.0 or higher is required.', file=sys.stderr) if bpy.app.version < (3, 0, 0) else None;" + + vformat("bpy.ops.wm.open_mainfile(filepath='%s');", source_global) + + unpack_all + + vformat("bpy.ops.export_scene.gltf(export_keep_originals=True,%s);", common_args); + print_verbose(script); + + // Run script with configured Blender binary. + + String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); + +#ifdef WINDOWS_ENABLED + blender_path = blender_path.plus_file("blender.exe"); +#else + blender_path = blender_path.plus_file("blender"); +#endif + + List<String> args; + args.push_back("--background"); + args.push_back("--python-expr"); + args.push_back(script); + + String standard_out; + int ret; + OS::get_singleton()->execute(blender_path, args, &standard_out, &ret, true); + print_verbose(blender_path); + print_verbose(standard_out); + + if (ret != 0) { + if (r_err) { + *r_err = ERR_SCRIPT_FAILED; + } + ERR_PRINT(vformat("Blend export to glTF failed with error: %d.", ret)); + return nullptr; + } + + // Import the generated glTF. + + // Use GLTFDocument instead of glTF importer to keep image references. + Ref<GLTFDocument> gltf; + gltf.instantiate(); + Ref<GLTFState> state; + state.instantiate(); + String base_dir; + if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) { + base_dir = sink.get_base_dir(); + } + Error err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, p_bake_fps, base_dir); + if (err != OK) { + if (r_err) { + *r_err = FAILED; + } + return nullptr; + } + return gltf->generate_scene(state, p_bake_fps); +} + +Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, + const Map<StringName, Variant> &p_options) { + if (p_path.get_extension().to_lower() != "blend") { + return true; + } + + if (p_option.begins_with("animation/")) { + if (p_option != "animation/import" && !bool(p_options["animation/import"])) { + return false; + } + } + return true; +} + +void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { + if (p_path.get_extension().to_lower() != "blend") { + return; + } +#define ADD_OPTION_BOOL(PATH, VALUE) \ + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, SNAME(PATH)), VALUE)); +#define ADD_OPTION_ENUM(PATH, ENUM_HINT, VALUE) \ + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, SNAME(PATH), PROPERTY_HINT_ENUM, ENUM_HINT), VALUE)); + + ADD_OPTION_ENUM("blender/nodes/visible", "Visible Only,Renderable,All", BLEND_VISIBLE_ALL); + ADD_OPTION_BOOL("blender/nodes/punctual_lights", true); + ADD_OPTION_BOOL("blender/nodes/cameras", true); + ADD_OPTION_BOOL("blender/nodes/custom_properties", true); + ADD_OPTION_ENUM("blender/nodes/modifiers", "No Modifiers,All Modifiers", BLEND_MODIFIERS_ALL); + ADD_OPTION_BOOL("blender/meshes/colors", false); + ADD_OPTION_BOOL("blender/meshes/uvs", true); + ADD_OPTION_BOOL("blender/meshes/normals", true); + ADD_OPTION_BOOL("blender/meshes/tangents", true); + ADD_OPTION_ENUM("blender/meshes/skins", "None,4 Influences (Compatible),All Influences", BLEND_BONE_INFLUENCES_ALL); + ADD_OPTION_BOOL("blender/meshes/export_bones_deforming_mesh_only", false); + ADD_OPTION_BOOL("blender/materials/unpack_enabled", true); + ADD_OPTION_ENUM("blender/materials/export_materials", "Placeholder,Export", BLEND_MATERIAL_EXPORT_EXPORT); + ADD_OPTION_BOOL("blender/animation/limit_playback", true); + ADD_OPTION_BOOL("blender/animation/always_sample", true); + ADD_OPTION_BOOL("blender/animation/group_tracks", true); + +#undef ADD_OPTION_BOOL +#undef ADD_OPTION_ENUM +} + +/////////////////////////// + +static bool _test_blender_path(const String &p_path, String *r_err = nullptr) { + String path = p_path; +#ifdef WINDOWS_ENABLED + path = path.plus_file("blender.exe"); +#else + path = path.plus_file("blender"); +#endif + +#if defined(OSX_ENABLED) + if (!FileAccess::exists(path)) { + path = path.plus_file("Blender"); + } +#endif + + if (!FileAccess::exists(path)) { + if (r_err) { + *r_err = TTR("Path does not contain a Blender installation."); + } + return false; + } + List<String> args; + args.push_back("--version"); + String pipe; + Error err = OS::get_singleton()->execute(path, args, &pipe); + if (err != OK) { + if (r_err) { + *r_err = TTR("Can't excecute Blender binary."); + } + return false; + } + + if (pipe.find("Blender ") != 0) { + if (r_err) { + *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s"), path); + } + return false; + } + pipe = pipe.replace_first("Blender ", ""); + int pp = pipe.find("."); + if (pp == -1) { + if (r_err) { + *r_err = TTR("Path supplied lacks a Blender binary."); + } + return false; + } + String v = pipe.substr(0, pp); + int version = v.to_int(); + if (version < 3) { + if (r_err) { + *r_err = TTR("This Blender installation is too old for this importer (not 3.0+)."); + } + return false; + } + if (version > 3) { + if (r_err) { + *r_err = TTR("This Blender installation is too new for this importer (not 3.x)."); + } + return false; + } + + return true; +} + +bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const { + bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); + + String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); + + if (blend_enabled && !_test_blender_path(blender_path)) { + // Intending to import Blender, but blend not configured. + return true; + } + + return false; +} +Vector<String> EditorFileSystemImportFormatSupportQueryBlend::get_file_extensions() const { + Vector<String> ret; + ret.push_back("blend"); + return ret; +} + +void EditorFileSystemImportFormatSupportQueryBlend::_validate_path(String p_path) { + String error; + bool success = false; + if (p_path == "") { + error = TTR("Path is empty."); + } else { + if (_test_blender_path(p_path, &error)) { + success = true; + if (auto_detected_path == p_path) { + error = TTR("Path to Blender installation is valid (Autodetected)."); + } else { + error = TTR("Path to Blender installation is valid."); + } + } + } + + path_status->set_text(error); + + if (success) { + path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("success_color"), SNAME("Editor"))); + configure_blender_dialog->get_ok_button()->set_disabled(false); + } else { + path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("error_color"), SNAME("Editor"))); + configure_blender_dialog->get_ok_button()->set_disabled(true); + } +} + +bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path(String p_path) { + if (_test_blender_path(p_path)) { + auto_detected_path = p_path; + return true; + } + return false; +} + +void EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed() { + confirmed = true; +} + +void EditorFileSystemImportFormatSupportQueryBlend::_select_install(String p_path) { + blender_path->set_text(p_path); + _validate_path(p_path); +} +void EditorFileSystemImportFormatSupportQueryBlend::_browse_install() { + if (blender_path->get_text() != String()) { + browse_dialog->set_current_dir(blender_path->get_text()); + } + + browse_dialog->popup_centered_ratio(); +} + +bool EditorFileSystemImportFormatSupportQueryBlend::query() { + if (!configure_blender_dialog) { + configure_blender_dialog = memnew(ConfirmationDialog); + configure_blender_dialog->set_title(TTR("Configure Blender Importer")); + configure_blender_dialog->set_flag(Window::FLAG_BORDERLESS, true); // Avoid closing accidentally . + configure_blender_dialog->set_close_on_escape(false); + + VBoxContainer *vb = memnew(VBoxContainer); + vb->add_child(memnew(Label(TTR("Blender 3.0+ is required to import '.blend' files.\nPlease provide a valid path to a Blender installation:")))); + + HBoxContainer *hb = memnew(HBoxContainer); + + blender_path = memnew(LineEdit); + blender_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->add_child(blender_path); + blender_path_browse = memnew(Button); + hb->add_child(blender_path_browse); + blender_path_browse->set_text(TTR("Browse")); + blender_path_browse->connect("pressed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_browse_install)); + hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); + + vb->add_child(hb); + + path_status = memnew(Label); + vb->add_child(path_status); + + configure_blender_dialog->add_child(vb); + + blender_path->connect("text_changed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_validate_path)); + + EditorNode::get_singleton()->get_gui_base()->add_child(configure_blender_dialog); + + configure_blender_dialog->get_ok_button()->set_text(TTR("Confirm Path")); + configure_blender_dialog->get_cancel_button()->set_text(TTR("Disable '.blend' Import")); + configure_blender_dialog->get_cancel_button()->set_tooltip(TTR("Disables Blender '.blend' files import for this project. Can be re-enabled in Project Settings.")); + configure_blender_dialog->connect("confirmed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed)); + + browse_dialog = memnew(EditorFileDialog); + browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR); + browse_dialog->connect("dir_selected", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_select_install)); + + EditorNode::get_singleton()->get_gui_base()->add_child(browse_dialog); + } + + String path = EDITOR_GET("filesystem/import/blender/blender3_path"); + + if (path == "") { + // Autodetect + auto_detected_path = ""; + +#if defined(OSX_ENABLED) + + { + Vector<String> mdfind_paths; + { + List<String> mdfind_args; + mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender"); + + String output; + Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output); + if (err == OK) { + mdfind_paths = output.split("\n"); + } + } + + bool found = false; + for (const String &path : mdfind_paths) { + found = _autodetect_path(path.plus_file("Contents/MacOS")); + if (found) { + break; + } + } + if (!found) { + found = _autodetect_path("/opt/homebrew/bin"); + } + if (!found) { + found = _autodetect_path("/opt/local/bin"); + } + if (!found) { + found = _autodetect_path("/usr/local/bin"); + } + if (!found) { + found = _autodetect_path("/usr/local/opt"); + } + if (!found) { + found = _autodetect_path("/Applications/Blender.app/Contents/MacOS"); + } + } +#elif defined(WINDOWS_ENABLED) + { + char blender_opener_path[MAX_PATH]; + DWORD path_len = MAX_PATH; + HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len); + if (res == S_OK && _autodetect_path(String(blender_opener_path).get_base_dir())) { + // Good. + } else if (_autodetect_path("C:\\Program Files\\Blender Foundation")) { + // Good. + } else { + _autodetect_path("C:\\Program Files (x86)\\Blender Foundation"); + } + } + +#elif defined(UNIX_ENABLED) + if (_autodetect_path("/usr/bin")) { + // Good. + } else if (_autodetect_path("/usr/local/bin")) { + // Good + } else { + _autodetect_path("/opt/blender/bin"); + } +#endif + if (auto_detected_path != "") { + path = auto_detected_path; + } + } + + blender_path->set_text(path); + + _validate_path(path); + + configure_blender_dialog->popup_centered(); + confirmed = false; + + while (true) { + OS::get_singleton()->delay_usec(1); + DisplayServer::get_singleton()->process_events(); + Main::iteration(); + if (!configure_blender_dialog->is_visible() || confirmed) { + break; + } + } + + if (confirmed) { + // Can only confirm a valid path. + EditorSettings::get_singleton()->set("filesystem/import/blender/blender3_path", blender_path->get_text()); + EditorSettings::get_singleton()->save(); + } else { + // Disable Blender import + ProjectSettings::get_singleton()->set("filesystem/import/blender/enabled", false); + ProjectSettings::get_singleton()->save(); + + if (EditorNode::immediate_confirmation_dialog(TTR("Disabling '.blend' file import requires restarting the editor."), TTR("Save & Restart"), TTR("Restart"))) { + EditorNode::get_singleton()->save_all_scenes(); + } + EditorNode::get_singleton()->restart_editor(); + return true; + } + + return false; +} + +EditorFileSystemImportFormatSupportQueryBlend::EditorFileSystemImportFormatSupportQueryBlend() { +} + +#endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h new file mode 100644 index 0000000000..0925333a28 --- /dev/null +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* editor_scene_importer_blend.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITOR_SCENE_IMPORTER_BLEND_H +#define EDITOR_SCENE_IMPORTER_BLEND_H + +#ifdef TOOLS_ENABLED + +#include "editor/editor_file_system.h" +#include "editor/import/resource_importer_scene.h" + +class Animation; +class Node; +class ConfirmationDialog; + +class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter { + GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter); + +public: + enum { + BLEND_VISIBLE_VISIBLE_ONLY, + BLEND_VISIBLE_RENDERABLE, + BLEND_VISIBLE_ALL + }; + enum { + BLEND_BONE_INFLUENCES_NONE, + BLEND_BONE_INFLUENCES_COMPATIBLE, + BLEND_BONE_INFLUENCES_ALL + }; + enum { + BLEND_MATERIAL_EXPORT_PLACEHOLDER, + BLEND_MATERIAL_EXPORT_EXPORT + }; + enum { + BLEND_MODIFIERS_NONE, + BLEND_MODIFIERS_ALL + }; + + virtual uint32_t get_import_flags() const override; + virtual void get_extensions(List<String> *r_extensions) const override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, + const Map<StringName, Variant> &p_options, int p_bake_fps, + List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual void get_import_options(const String &p_path, + List<ResourceImporter::ImportOption> *r_options) override; + virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, + const Map<StringName, Variant> &p_options) override; +}; + +class LineEdit; +class Button; +class EditorFileDialog; +class Label; + +class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImportFormatSupportQuery { + GDCLASS(EditorFileSystemImportFormatSupportQueryBlend, EditorFileSystemImportFormatSupportQuery); + + ConfirmationDialog *configure_blender_dialog = nullptr; + LineEdit *blender_path = nullptr; + Button *blender_path_browse = nullptr; + EditorFileDialog *browse_dialog = nullptr; + Label *path_status = nullptr; + bool confirmed = false; + + String auto_detected_path; + void _validate_path(String p_path); + + bool _autodetect_path(String p_path); + + void _path_confirmed(); + + void _select_install(String p_path); + void _browse_install(); + +public: + virtual bool is_active() const override; + virtual Vector<String> get_file_extensions() const override; + virtual bool query() override; + + EditorFileSystemImportFormatSupportQueryBlend(); +}; + +#endif // TOOLS_ENABLED + +#endif // EDITOR_SCENE_IMPORTER_BLEND_H diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp new file mode 100644 index 0000000000..893d2efcec --- /dev/null +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -0,0 +1,117 @@ +/*************************************************************************/ +/* editor_scene_importer_fbx.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "editor_scene_importer_fbx.h" + +#if TOOLS_ENABLED + +#include "../gltf_document.h" +#include "../gltf_state.h" + +#include "core/config/project_settings.h" +#include "editor/editor_settings.h" +#include "scene/main/node.h" +#include "scene/resources/animation.h" + +uint32_t EditorSceneFormatImporterFBX::get_import_flags() const { + return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; +} + +void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) const { + r_extensions->push_back("fbx"); +} + +Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, + const Map<StringName, Variant> &p_options, int p_bake_fps, + List<String> *r_missing_deps, Error *r_err) { + // Get global paths for source and sink. + + // Don't use `c_escape()` as it can generate broken paths. These paths will be + // enclosed in double quotes by OS::execute(), so we only need to escape those. + // `c_escape_multiline()` seems to do this (escapes `\` and `"` only). + const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline(); + const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file( + vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text())); + const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline(); + + // Run fbx2gltf. + + String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path"); + + List<String> args; + args.push_back("--pbr-metallic-roughness"); + args.push_back("--input"); + args.push_back(source_global); + args.push_back("--output"); + args.push_back(sink_global); + args.push_back("--binary"); + + String standard_out; + int ret; + OS::get_singleton()->execute(fbx2gltf_path, args, &standard_out, &ret, true); + print_verbose(fbx2gltf_path); + print_verbose(standard_out); + + if (ret != 0) { + if (r_err) { + *r_err = ERR_SCRIPT_FAILED; + } + ERR_PRINT(vformat("FBX conversion to glTF failed with error: %d.", ret)); + return nullptr; + } + + // Import the generated glTF. + + // Use GLTFDocument instead of glTF importer to keep image references. + Ref<GLTFDocument> gltf; + gltf.instantiate(); + Ref<GLTFState> state; + state.instantiate(); + print_verbose(vformat("glTF path: %s", sink)); + Error err = gltf->append_from_file(sink, state, p_flags, p_bake_fps); + if (err != OK) { + if (r_err) { + *r_err = FAILED; + } + return nullptr; + } + return gltf->generate_scene(state, p_bake_fps); +} + +Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation, + const String &p_option, const Map<StringName, Variant> &p_options) { + return true; +} + +void EditorSceneFormatImporterFBX::get_import_options(const String &p_path, + List<ResourceImporter::ImportOption> *r_options) { +} + +#endif // TOOLS_ENABLED diff --git a/modules/fbx/tools/validation_tools.cpp b/modules/gltf/editor/editor_scene_importer_fbx.h index 9dbd8bf544..84de7fd1cc 100644 --- a/modules/fbx/tools/validation_tools.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* validation_tools.cpp */ +/* editor_scene_importer_fbx.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,21 +28,31 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "validation_tools.h" +#ifndef EDITOR_SCENE_IMPORTER_FBX_H +#define EDITOR_SCENE_IMPORTER_FBX_H #ifdef TOOLS_ENABLED -#include "core/string/print_string.h" -#include "core/string/ustring.h" +#include "editor/import/resource_importer_scene.h" -ValidationTracker::Entries *ValidationTracker::entries_singleton = memnew(ValidationTracker::Entries); +class Animation; +class Node; -// for printing our CSV to dump validation problems of files -// later we can make some agnostic tooling for this but this is fine for the time being. -void ValidationTracker::Entries::add_validation_error(String asset_path, String message) { - print_error(message); - // note: implementation is static - validation_entries[asset_path].push_back(message); -} +class EditorSceneFormatImporterFBX : public EditorSceneFormatImporter { + GDCLASS(EditorSceneFormatImporterFBX, EditorSceneFormatImporter); + +public: + virtual uint32_t get_import_flags() const override; + virtual void get_extensions(List<String> *r_extensions) const override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, + const Map<StringName, Variant> &p_options, int p_bake_fps, + List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual void get_import_options(const String &p_path, + List<ResourceImporter::ImportOption> *r_options) override; + virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, + const Map<StringName, Variant> &p_options) override; +}; #endif // TOOLS_ENABLED + +#endif // EDITOR_SCENE_IMPORTER_FBX_H diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index 1a172877a0..5e7811ad2b 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if TOOLS_ENABLED +#ifdef TOOLS_ENABLED + #include "editor_scene_importer_gltf.h" -#include "gltf_document.h" -#include "gltf_state.h" +#include "../gltf_document.h" +#include "../gltf_state.h" -#include "scene/3d/node_3d.h" -#include "scene/animation/animation_player.h" +#include "scene/main/node.h" #include "scene/resources/animation.h" uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const { @@ -47,19 +47,21 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c r_extensions->push_back("glb"); } -Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, - uint32_t p_flags, int p_bake_fps, - List<String> *r_missing_deps, - Error *r_err) { +Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, + const Map<StringName, Variant> &p_options, int p_bake_fps, + List<String> *r_missing_deps, Error *r_err) { Ref<GLTFDocument> doc; doc.instantiate(); - return doc->import_scene_gltf(p_path, p_flags, p_bake_fps, Ref<GLTFState>(), r_missing_deps, r_err); -} - -Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path, - uint32_t p_flags, - int p_bake_fps) { - return Ref<Animation>(); + Ref<GLTFState> state; + state.instantiate(); + Error err = doc->append_from_file(p_path, state, p_flags, p_bake_fps); + if (err != OK) { + if (r_err) { + *r_err = err; + } + return nullptr; + } + return doc->generate_scene(state, p_bake_fps); } #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index 28963adc28..b714ada124 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,16 +30,13 @@ #ifndef EDITOR_SCENE_IMPORTER_GLTF_H #define EDITOR_SCENE_IMPORTER_GLTF_H -#ifdef TOOLS_ENABLED -#include "gltf_state.h" -#include "gltf_document_extension.h" +#ifdef TOOLS_ENABLED #include "editor/import/resource_importer_scene.h" -#include "scene/main/node.h" -#include "scene/resources/packed_scene.h" class Animation; +class Node; class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter { GDCLASS(EditorSceneFormatImporterGLTF, EditorSceneFormatImporter); @@ -47,9 +44,11 @@ class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; 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, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, - uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, + const Map<StringName, Variant> &p_options, int p_bake_fps, + List<String> *r_missing_deps, Error *r_err = nullptr) override; }; + #endif // TOOLS_ENABLED + #endif // EDITOR_SCENE_IMPORTER_GLTF_H diff --git a/modules/gltf/gltf_accessor.cpp b/modules/gltf/gltf_accessor.cpp index 85cec3fec4..1daf2f90a7 100644 --- a/modules/gltf/gltf_accessor.cpp +++ b/modules/gltf/gltf_accessor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h index bec511f974..6bf1bf543a 100644 --- a/modules/gltf/gltf_accessor.h +++ b/modules/gltf/gltf_accessor.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_animation.cpp b/modules/gltf/gltf_animation.cpp index 889a8e8870..c857be4b2c 100644 --- a/modules/gltf/gltf_animation.cpp +++ b/modules/gltf/gltf_animation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h index 763494cb8d..ba8ae8a273 100644 --- a/modules/gltf/gltf_animation.h +++ b/modules/gltf/gltf_animation.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_buffer_view.cpp b/modules/gltf/gltf_buffer_view.cpp index d00e0f040f..fc467367c6 100644 --- a/modules/gltf/gltf_buffer_view.cpp +++ b/modules/gltf/gltf_buffer_view.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_buffer_view.h b/modules/gltf/gltf_buffer_view.h index 63af5e7c0d..560d56f35c 100644 --- a/modules/gltf/gltf_buffer_view.h +++ b/modules/gltf/gltf_buffer_view.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_camera.cpp b/modules/gltf/gltf_camera.cpp index 0f895fb989..f3ea6a1c4c 100644 --- a/modules/gltf/gltf_camera.cpp +++ b/modules/gltf/gltf_camera.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_camera.h b/modules/gltf/gltf_camera.h index 843ff417a4..c696d4cc6b 100644 --- a/modules/gltf/gltf_camera.h +++ b/modules/gltf/gltf_camera.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 1c1ee5cd10..082b4ce1ec 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -48,22 +48,24 @@ #include "core/error/error_macros.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" +#include "core/io/file_access_memory.h" #include "core/io/json.h" +#include "core/io/stream_peer.h" #include "core/math/disjoint_set.h" #include "core/math/vector2.h" #include "core/variant/dictionary.h" #include "core/variant/typed_array.h" #include "core/variant/variant.h" #include "core/version.h" -#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/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" +#include "scene/3d/node_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/importer_mesh.h" +#include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/multimesh.h" #include "scene/resources/surface_tool.h" @@ -77,18 +79,51 @@ #include "modules/gridmap/grid_map.h" #endif // MODULE_GRIDMAP_ENABLED +// FIXME: Hardcoded to avoid editor dependency. +#define GLTF_IMPORT_USE_NAMED_SKIN_BINDS 16 +#define GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS 32 + #include <stdio.h> #include <stdlib.h> #include <cstdint> #include <limits> -Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &p_path) { - uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); +static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) { + Ref<ImporterMesh> importer_mesh; + importer_mesh.instantiate(); + if (p_mesh.is_null()) { + return importer_mesh; + } - state->skeleton3d_to_gltf_skeleton.clear(); - state->skin_and_skeleton3d_to_gltf_skin.clear(); + Ref<ArrayMesh> array_mesh = p_mesh; + if (p_mesh->get_blend_shape_count()) { + ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; + if (array_mesh.is_valid()) { + shape_mode = array_mesh->get_blend_shape_mode(); + } + importer_mesh->set_blend_shape_mode(shape_mode); + for (int morph_i = 0; morph_i < p_mesh->get_blend_shape_count(); morph_i++) { + importer_mesh->add_blend_shape(p_mesh->get_blend_shape_name(morph_i)); + } + } + for (int32_t surface_i = 0; surface_i < p_mesh->get_surface_count(); surface_i++) { + Array array = p_mesh->surface_get_arrays(surface_i); + Ref<Material> mat = p_mesh->surface_get_material(surface_i); + String mat_name; + if (mat.is_valid()) { + mat_name = mat->get_name(); + } else { + // Assign default material when no material is assigned. + mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); + } + importer_mesh->add_surface(p_mesh->surface_get_primitive_type(surface_i), + array, p_mesh->surface_get_blend_shape_arrays(surface_i), p_mesh->surface_get_lods(surface_i), mat, + mat_name, p_mesh->surface_get_format(surface_i)); + } + return importer_mesh; +} - _convert_scene_node(state, p_root, -1, -1); +Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { if (!state->buffers.size()) { state->buffers.push_back(Vector<uint8_t>()); } @@ -184,16 +219,6 @@ Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String & return Error::FAILED; } - /* STEP 17 SERIALIZE FILE */ - err = _serialize_file(state, p_path); - if (err != OK) { - return Error::FAILED; - } - uint64_t elapsed = OS::get_singleton()->get_ticks_usec() - begin_time; - float elapsed_sec = double(elapsed) / 1000000.0; - elapsed_sec = Math::snapped(elapsed_sec, 0.01f); - print_verbose("glTF: Export time elapsed seconds " + rtos(elapsed_sec).pad_decimals(2)); - return OK; } @@ -233,8 +258,8 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) { Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { return err; } @@ -255,18 +280,14 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { return OK; } -Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { - Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return err; - } - +Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) { + ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ); uint32_t magic = f->get_32(); ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF f->get_32(); // version f->get_32(); // length - uint32_t chunk_length = f->get_32(); uint32_t chunk_type = f->get_32(); @@ -280,9 +301,9 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { text.parse_utf8((const char *)json_data.ptr(), json_data.size()); JSON json; - err = json.parse(text); + Error err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); + _err_print_error("", "", json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); return err; } @@ -339,9 +360,9 @@ static Transform3D _arr_to_xform(const Array &p_array) { ERR_FAIL_COND_V(p_array.size() != 16, Transform3D()); 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])); + xform.basis.set_column(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2])); + xform.basis.set_column(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6])); + xform.basis.set_column(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10])); xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14])); return xform; @@ -350,17 +371,17 @@ static Transform3D _arr_to_xform(const Array &p_array) { 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); + Vector3 axis_x = p_transform.get_basis().get_column(Vector3::AXIS_X); array.write[0] = axis_x.x; array.write[1] = axis_x.y; array.write[2] = axis_x.z; array.write[3] = 0.0f; - Vector3 axis_y = p_transform.get_basis().get_axis(Vector3::AXIS_Y); + Vector3 axis_y = p_transform.get_basis().get_column(Vector3::AXIS_Y); array.write[4] = axis_y.x; array.write[5] = axis_y.y; array.write[6] = axis_y.z; array.write[7] = 0.0f; - Vector3 axis_z = p_transform.get_basis().get_axis(Vector3::AXIS_Z); + Vector3 axis_z = p_transform.get_basis().get_column(Vector3::AXIS_Z); array.write[8] = axis_z.x; array.write[9] = axis_z.y; array.write[10] = axis_z.z; @@ -677,8 +698,8 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); + if (f.is_null()) { return err; } if (buffer_data.size() == 0) { @@ -686,7 +707,6 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat } f->create(FileAccess::ACCESS_RESOURCES); f->store_buffer(buffer_data.ptr(), buffer_data.size()); - f->close(); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); @@ -710,8 +730,8 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); + if (f.is_null()) { return err; } if (buffer_data.size() == 0) { @@ -719,7 +739,6 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa } f->create(FileAccess::ACCESS_RESOURCES); f->store_buffer(buffer_data.ptr(), buffer_data.size()); - f->close(); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); @@ -753,6 +772,8 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa } buffer_data = _parse_base64_uri(uri); } else { // Relative path to an external image file. + ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); + uri = uri.uri_decode(); uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. buffer_data = FileAccess::get_file_as_array(uri); ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); @@ -1939,20 +1960,20 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, for (int i = 0; i < p_attribs.size(); i++) { Transform3D attrib = p_attribs[i]; Basis basis = attrib.get_basis(); - Vector3 axis_0 = basis.get_axis(Vector3::AXIS_X); + Vector3 axis_0 = basis.get_column(Vector3::AXIS_X); attribs.write[i * element_count + 0] = Math::snapped(axis_0.x, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 1] = Math::snapped(axis_0.y, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 2] = Math::snapped(axis_0.z, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 3] = 0.0; - Vector3 axis_1 = basis.get_axis(Vector3::AXIS_Y); + Vector3 axis_1 = basis.get_column(Vector3::AXIS_Y); attribs.write[i * element_count + 4] = Math::snapped(axis_1.x, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 5] = Math::snapped(axis_1.y, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 6] = Math::snapped(axis_1.z, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 7] = 0.0; - Vector3 axis_2 = basis.get_axis(Vector3::AXIS_Z); + Vector3 axis_2 = basis.get_column(Vector3::AXIS_Z); attribs.write[i * element_count + 8] = Math::snapped(axis_2.x, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 9] = Math::snapped(axis_2.y, CMP_NORMALIZE_TOLERANCE); attribs.write[i * element_count + 10] = Math::snapped(axis_2.z, CMP_NORMALIZE_TOLERANCE); @@ -2084,9 +2105,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); ret.resize(attribs.size() / 9); for (int i = 0; i < ret.size(); i++) { - ret.write[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); - ret.write[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); - ret.write[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); + ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); + ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); + ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); } return ret; } @@ -2102,9 +2123,9 @@ Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); ret.resize(attribs.size() / 16); for (int i = 0; i < ret.size(); i++) { - ret.write[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); - ret.write[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); - ret.write[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); + ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); + ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); + ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); } return ret; @@ -2539,14 +2560,16 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (p.has("mode")) { const int mode = p["mode"]; ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); + // Convert mesh.primitive.mode to Godot Mesh enum. See: + // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode static const Mesh::PrimitiveType primitives2[7] = { - Mesh::PRIMITIVE_POINTS, - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_TRIANGLES, - Mesh::PRIMITIVE_TRIANGLE_STRIP, - Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted + Mesh::PRIMITIVE_POINTS, // 0 POINTS + Mesh::PRIMITIVE_LINES, // 1 LINES + Mesh::PRIMITIVE_LINES, // 2 LINE_LOOP; loop not supported, should be converted + Mesh::PRIMITIVE_LINE_STRIP, // 3 LINE_STRIP + Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES + Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP + Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted #ifndef _MSC_VER #warning line loop and triangle fan are not supported and need to be converted to lines and triangles #endif @@ -2886,34 +2909,43 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } array_copy = blend_surface_tool->commit_to_arrays(); + // Enforce blend shape mask array format + for (int l = 0; l < Mesh::ARRAY_MAX; l++) { + if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << l))) { + array_copy[l] = Variant(); + } + } + morphs.push_back(array_copy); } } - //just add it - Ref<BaseMaterial3D> mat; - if (p.has("material")) { - const int material = p["material"]; - ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT); - Ref<BaseMaterial3D> mat3d = state->materials[material]; - ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); - if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - } - mat = mat3d; + String mat_name; + if (!state->discard_meshes_and_materials) { + if (p.has("material")) { + const int material = p["material"]; + ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT); + Ref<BaseMaterial3D> mat3d = state->materials[material]; + ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); + if (has_vertex_color) { + mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } + mat = mat3d; - } else { - Ref<StandardMaterial3D> mat3d; - mat3d.instantiate(); - if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } else { + Ref<StandardMaterial3D> mat3d; + mat3d.instantiate(); + if (has_vertex_color) { + mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } + mat = mat3d; } - mat = mat3d; + ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT); + mat_name = mat->get_name(); } - ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT); import_mesh->add_surface(primitive, array, morphs, - Dictionary(), mat, mat->get_name(), flags); + Dictionary(), mat, mat_name, flags); } Vector<float> blend_weights; @@ -2952,7 +2984,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path Ref<Image> image = state->images[i]->get_image(); ERR_CONTINUE(image.is_null()); - if (p_path.to_lower().ends_with("glb")) { + if (p_path.to_lower().ends_with("glb") || p_path.is_empty()) { GLTFBufferViewIndex bvi; Ref<GLTFBufferView> bv; @@ -2981,6 +3013,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path d["bufferView"] = bvi; d["mimeType"] = "image/png"; } else { + ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER); String name = state->images[i]->get_name(); if (name.is_empty()) { name = itos(i); @@ -2988,13 +3021,14 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path name = _gen_unique_name(state, name); name = name.pad_zeros(3) + ".png"; String texture_dir = "textures"; - String new_texture_dir = p_path.get_base_dir() + "/" + texture_dir; - DirAccessRef da = DirAccess::open(p_path.get_base_dir()); + String path = p_path.get_base_dir(); + String new_texture_dir = path + "/" + texture_dir; + Ref<DirAccess> da = DirAccess::open(path); if (!da->dir_exists(new_texture_dir)) { da->make_dir(new_texture_dir); } image->save_png(new_texture_dir.plus_file(name)); - d["uri"] = texture_dir.plus_file(name); + d["uri"] = texture_dir.plus_file(name).uri_encode(); } images.push_back(d); } @@ -3010,6 +3044,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path } Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_path) { + ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); if (!state->json.has("images")) { return OK; } @@ -3069,6 +3104,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat } } } else { // Relative path to an external image file. + ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); uri = uri.uri_decode(); uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. // ResourceLoader will rely on the file extension to use the relevant loader. @@ -3240,7 +3276,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Dictionary mr; { Array arr; - const Color c = material->get_albedo().to_linear(); + const Color c = material->get_albedo().srgb_to_linear(); arr.push_back(c.r); arr.push_back(c.g); arr.push_back(c.b); @@ -3383,9 +3419,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { orm_texture_index = _set_texture(state, orm_texture); } if (has_ao) { - Dictionary ot; - ot["index"] = orm_texture_index; - d["occlusionTexture"] = ot; + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; } if (has_roughness || has_metalness) { mrt["index"] = orm_texture_index; @@ -3402,29 +3438,32 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { tex.instantiate(); { Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); - // Code for uncompressing RG normal maps - Ref<Image> img = normal_texture->get_image(); - Ref<ImageTexture> img_tex = img; - if (img_tex.is_valid()) { - 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); - Vector2 red_green = Vector2(c.r, c.g); - red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); - float blue = 1.0f - red_green.dot(red_green); - blue = MAX(0.0f, blue); - c.b = Math::sqrt(blue); - img->set_pixel(x, y, c); + if (normal_texture.is_valid()) { + // Code for uncompressing RG normal maps + Ref<Image> img = normal_texture->get_image(); + if (img.is_valid()) { + Ref<ImageTexture> img_tex = img; + if (img_tex.is_valid()) { + 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); + Vector2 red_green = Vector2(c.r, c.g); + red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); + float blue = 1.0f - red_green.dot(red_green); + blue = MAX(0.0f, blue); + c.b = Math::sqrt(blue); + img->set_pixel(x, y, c); + } + } + tex->create_from_image(img); } } - tex->create_from_image(img); } - Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); @@ -3438,7 +3477,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { - const Color c = material->get_emission().to_srgb(); + const Color c = material->get_emission().linear_to_srgb(); Array arr; arr.push_back(c.r); arr.push_back(c.g); @@ -3520,7 +3559,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (sgm.has("diffuseFactor")) { const Array &arr = sgm["diffuseFactor"]; ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb(); + const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb(); spec_gloss->diffuse_factor = c; material->set_albedo(spec_gloss->diffuse_factor); } @@ -3551,7 +3590,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (mr.has("baseColorFactor")) { const Array &arr = mr["baseColorFactor"]; ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb(); + const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb(); material->set_albedo(c); } @@ -3618,7 +3657,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (d.has("emissiveFactor")) { const Array &arr = d["emissiveFactor"]; ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2]).to_srgb(); + const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); material->set_emission(c); @@ -3702,11 +3741,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re } for (int32_t y = 0; y < r_spec_gloss->spec_gloss_img->get_height(); y++) { for (int32_t x = 0; x < r_spec_gloss->spec_gloss_img->get_width(); x++) { - const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).to_linear(); + const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).srgb_to_linear(); Color specular = Color(specular_pixel.r, specular_pixel.g, specular_pixel.b); specular *= r_spec_gloss->specular_factor; Color diffuse = Color(1.0f, 1.0f, 1.0f); - diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).to_linear(); + diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).srgb_to_linear(); float metallic = 0.0f; Color base_color; spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic); @@ -3723,7 +3762,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re mr.g = 1.0f - mr.g; rm_img->set_pixel(x, y, mr); if (r_spec_gloss->diffuse_img.is_valid()) { - r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.to_srgb()); + r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.linear_to_srgb()); } } } @@ -4591,7 +4630,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { if (d.has("color")) { const Array &arr = d["color"]; ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2]).to_srgb(); + const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); light->color = c; } if (d.has("intensity")) { @@ -5045,39 +5084,16 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst if (p_mesh_instance->get_mesh().is_null()) { return -1; } - Ref<ImporterMesh> current_mesh; - current_mesh.instantiate(); + + Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); + Ref<ImporterMesh> current_mesh = _mesh_to_importer_mesh(import_mesh); Vector<float> blend_weights; - { - Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); - Ref<ArrayMesh> import_array_mesh = p_mesh_instance->get_mesh(); - if (import_mesh->get_blend_shape_count()) { - ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; - if (import_array_mesh.is_valid()) { - shape_mode = import_array_mesh->get_blend_shape_mode(); - } - current_mesh->set_blend_shape_mode(shape_mode); - for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { - current_mesh->add_blend_shape(import_mesh->get_blend_shape_name(morph_i)); - } - } - for (int32_t surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) { - Array array = import_mesh->surface_get_arrays(surface_i); - Ref<Material> mat = import_mesh->surface_get_material(surface_i); - String mat_name; - if (mat.is_valid()) { - mat_name = mat->get_name(); - } - current_mesh->add_surface(import_mesh->surface_get_primitive_type(surface_i), - array, import_mesh->surface_get_blend_shape_arrays(surface_i), import_mesh->surface_get_lods(surface_i), mat, - mat_name, import_mesh->surface_get_format(surface_i)); - } - int32_t blend_count = import_mesh->get_blend_shape_count(); - blend_weights.resize(blend_count); - for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { - blend_weights.write[blend_i] = 0.0f; - } + int32_t blend_count = import_mesh->get_blend_shape_count(); + blend_weights.resize(blend_count); + for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { + blend_weights.write[blend_i] = 0.0f; } + Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); Array instance_materials; @@ -5099,7 +5115,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst return mesh_i; } -ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index) { +ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr); @@ -5119,7 +5135,7 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta return mi; } -Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr); @@ -5171,7 +5187,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, return memnew(Node3D); } -Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr); @@ -5249,7 +5265,7 @@ void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref p_node->position = xform.origin; } -Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; Node3D *spatial = memnew(Node3D); @@ -5329,14 +5345,31 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd if (meshes.size() != 2) { return; } - Ref<Material> mat; - if (csg->get_material_override().is_valid()) { - mat = csg->get_material_override(); + + Ref<ImporterMesh> mesh; + mesh.instantiate(); + { + Ref<Mesh> csg_mesh = csg->get_meshes()[1]; + + for (int32_t surface_i = 0; surface_i < csg_mesh->get_surface_count(); surface_i++) { + Array array = csg_mesh->surface_get_arrays(surface_i); + Ref<Material> mat = csg_mesh->surface_get_material(surface_i); + String mat_name; + if (mat.is_valid()) { + mat_name = mat->get_name(); + } else { + // Assign default material when no material is assigned. + mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); + } + mesh->add_surface(csg_mesh->surface_get_primitive_type(surface_i), + array, csg_mesh->surface_get_blend_shape_arrays(surface_i), csg_mesh->surface_get_lods(surface_i), mat, + mat_name, csg_mesh->surface_get_format(surface_i)); + } } + Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - Ref<ImporterMesh> array_mesh = csg->get_meshes()[1]; - gltf_mesh->set_mesh(array_mesh); + gltf_mesh->set_mesh(mesh); GLTFMeshIndex mesh_i = state->meshes.size(); state->meshes.push_back(gltf_mesh); gltf_node->mesh = mesh_i; @@ -5402,8 +5435,6 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex Vector3 cell_location = cells[k]; int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); - ImporterMeshInstance3D *import_mesh_node = memnew(ImporterMeshInstance3D); - import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell)); Transform3D cell_xform; cell_xform.basis.set_orthogonal_index( p_grid_map->get_cell_item_orientation( @@ -5415,7 +5446,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - gltf_mesh = import_mesh_node; + gltf_mesh->set_mesh(_mesh_to_importer_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell))); new_gltf_node->mesh = state->meshes.size(); state->meshes.push_back(gltf_mesh); new_gltf_node->xform = cell_xform * p_grid_map->get_transform(); @@ -5616,19 +5647,18 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent scene_parent = bone_attachment; } if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, scene_parent, node_index); + current_node = _generate_mesh_instance(state, node_index); } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, scene_parent, node_index); + current_node = _generate_camera(state, node_index); } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, scene_parent, node_index); + current_node = _generate_light(state, node_index); } // We still have not managed to make a node. if (!current_node) { - current_node = _generate_spatial(state, scene_parent, node_index); + current_node = _generate_spatial(state, node_index); } - - scene_parent->add_child(current_node, true); + scene_parent->add_child(current_node); if (current_node != scene_root) { current_node->set_owner(scene_root); } @@ -5699,11 +5729,11 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // We still have not managed to make a node if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, scene_parent, node_index); + current_node = _generate_mesh_instance(state, node_index); } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, scene_parent, node_index); + current_node = _generate_camera(state, node_index); } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, scene_parent, node_index); + current_node = _generate_light(state, node_index); } scene_parent->add_child(current_node, true); @@ -5722,7 +5752,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen } template <class T> -struct EditorSceneFormatImporterGLTFInterpolate { +struct SceneFormatImporterGLTFInterpolate { T lerp(const T &a, const T &b, float c) const { return a + (b - a) * c; } @@ -5748,7 +5778,7 @@ struct EditorSceneFormatImporterGLTFInterpolate { // thank you for existing, partial specialization template <> -struct EditorSceneFormatImporterGLTFInterpolate<Quaternion> { +struct SceneFormatImporterGLTFInterpolate<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."); @@ -5787,7 +5817,7 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T idx++; } - EditorSceneFormatImporterGLTFInterpolate<T> interp; + SceneFormatImporterGLTFInterpolate<T> interp; switch (p_interp) { case GLTFAnimation::INTERP_LINEAR: { @@ -6069,7 +6099,14 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, animation->set_length(length); - ap->add_animation(name, animation); + Ref<AnimationLibrary> library; + if (!ap->has_animation_library("")) { + library.instantiate(); + ap->add_animation_library("", library); + } else { + library = ap->get_animation_library(""); + } + library->add_animation(name, animation); } void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { @@ -6084,7 +6121,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { continue; } MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); - ERR_CONTINUE(!mi); + if (!mi) { + continue; + } Transform3D mi_xform = mi->get_transform(); node->scale = mi_xform.basis.get_scale(); node->rotation = mi_xform.basis.get_rotation_quaternion(); @@ -6282,39 +6321,8 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state ERR_CONTINUE(err != OK); p_track.rotation_track.values.write[key_i] = rotation; } - } else if (path.find(":transform") != -1) { - p_track.position_track.times = times; - p_track.position_track.interpolation = gltf_interpolation; - p_track.rotation_track.times = times; - p_track.rotation_track.interpolation = gltf_interpolation; - p_track.scale_track.times = times; - p_track.scale_track.interpolation = gltf_interpolation; - - p_track.scale_track.values.resize(key_count); - p_track.scale_track.interpolation = gltf_interpolation; - p_track.position_track.values.resize(key_count); - p_track.position_track.interpolation = gltf_interpolation; - p_track.rotation_track.values.resize(key_count); - p_track.rotation_track.interpolation = gltf_interpolation; - for (int32_t key_i = 0; key_i < key_count; key_i++) { - Transform3D xform = p_animation->track_get_key_value(p_track_i, key_i); - p_track.position_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion(); - p_track.scale_track.values.write[key_i] = xform.basis.get_scale(); - } } else if (track_type == Animation::TYPE_VALUE) { - if (path.find("/rotation_quat") != -1) { - p_track.rotation_track.times = times; - p_track.rotation_track.interpolation = gltf_interpolation; - - p_track.rotation_track.values.resize(key_count); - p_track.rotation_track.interpolation = gltf_interpolation; - - for (int32_t key_i = 0; key_i < key_count; key_i++) { - 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(":position") != -1) { + if (path.contains(":position")) { p_track.position_track.times = times; p_track.position_track.interpolation = gltf_interpolation; @@ -6325,7 +6333,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state Vector3 position = p_animation->track_get_key_value(p_track_i, key_i); p_track.position_track.values.write[key_i] = position; } - } else if (path.find(":rotation") != -1) { + } else if (path.contains(":rotation")) { p_track.rotation_track.times = times; p_track.rotation_track.interpolation = gltf_interpolation; @@ -6336,7 +6344,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state 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) { + } else if (path.contains(":scale")) { p_track.scale_track.times = times; p_track.scale_track.interpolation = gltf_interpolation; @@ -6349,7 +6357,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state } } } else if (track_type == Animation::TYPE_BEZIER) { - if (path.find("/scale") != -1) { + if (path.contains("/scale")) { const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS; if (!p_track.scale_track.times.size()) { Vector<real_t> new_times; @@ -6370,16 +6378,16 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state for (int32_t key_i = 0; key_i < keys; key_i++) { Vector3 bezier_track = p_track.scale_track.values[key_i]; - if (path.find("/scale:x") != -1) { + if (path.contains("/scale:x")) { bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - } else if (path.find("/scale:y") != -1) { + } else if (path.contains("/scale:y")) { bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - } else if (path.find("/scale:z") != -1) { + } else if (path.contains("/scale:z")) { bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); } p_track.scale_track.values.write[key_i] = bezier_track; } - } else if (path.find("/position") != -1) { + } else if (path.contains("/position")) { const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS; if (!p_track.position_track.times.size()) { Vector<real_t> new_times; @@ -6396,11 +6404,11 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state for (int32_t key_i = 0; key_i < keys; key_i++) { Vector3 bezier_track = p_track.position_track.values[key_i]; - if (path.find("/position:x") != -1) { + if (path.contains("/position:x")) { bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - } else if (path.find("/position:y") != -1) { + } else if (path.contains("/position:y")) { bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - } else if (path.find("/position:z") != -1) { + } else if (path.contains("/position:z")) { bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); } p_track.position_track.values.write[key_i] = bezier_track; @@ -6421,7 +6429,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, continue; } String orig_track_path = animation->track_get_path(track_i); - if (String(orig_track_path).find(":position") != -1) { + if (String(orig_track_path).contains(":position")) { const Vector<String> node_suffix = String(orig_track_path).split(":position"); const NodePath path = node_suffix[0]; const Node *node = ap->get_parent()->get_node_or_null(path); @@ -6437,7 +6445,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, gltf_animation->get_tracks().insert(node_index, track); } } - } else if (String(orig_track_path).find(":rotation_degrees") != -1) { + } else if (String(orig_track_path).contains(":rotation_degrees")) { const Vector<String> node_suffix = String(orig_track_path).split(":rotation_degrees"); const NodePath path = node_suffix[0]; const Node *node = ap->get_parent()->get_node_or_null(path); @@ -6453,7 +6461,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, gltf_animation->get_tracks().insert(node_index, track); } } - } else if (String(orig_track_path).find(":scale") != -1) { + } else if (String(orig_track_path).contains(":scale")) { const Vector<String> node_suffix = String(orig_track_path).split(":scale"); const NodePath path = node_suffix[0]; const Node *node = ap->get_parent()->get_node_or_null(path); @@ -6469,7 +6477,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, gltf_animation->get_tracks().insert(node_index, track); } } - } else if (String(orig_track_path).find(":transform") != -1) { + } else if (String(orig_track_path).contains(":transform")) { const Vector<String> node_suffix = String(orig_track_path).split(":transform"); const NodePath path = node_suffix[0]; const Node *node = ap->get_parent()->get_node_or_null(path); @@ -6480,8 +6488,8 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, gltf_animation->get_tracks().insert(transform_track_i.key, track); } } - } else if (String(orig_track_path).find(":blend_shapes/") != -1) { - const Vector<String> node_suffix = String(orig_track_path).split(":blend_shapes/"); + } else if (String(orig_track_path).contains(":") && animation->track_get_type(track_i) == Animation::TYPE_BLEND_SHAPE) { + const Vector<String> node_suffix = String(orig_track_path).split(":"); const NodePath path = node_suffix[0]; const String suffix = node_suffix[1]; Node *node = ap->get_parent()->get_node_or_null(path); @@ -6536,7 +6544,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } tracks[mesh_index] = track; } - } else if (String(orig_track_path).find(":") != -1) { + } else if (String(orig_track_path).contains(":")) { //Process skeleton const Vector<String> node_suffix = String(orig_track_path).split(":"); const String node = node_suffix[0]; @@ -6566,7 +6574,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, gltf_animation->get_tracks()[node_i] = track; } } - } else if (String(orig_track_path).find(":") == -1) { + } else if (!String(orig_track_path).contains(":")) { ERR_CONTINUE(!ap->get_parent()); Node *godot_node = ap->get_parent()->get_node_or_null(orig_track_path); for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) { @@ -6589,142 +6597,56 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } -Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binary) { +Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) { Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return err; + if (f.is_null()) { + return FAILED; } + f->seek(0); uint32_t magic = f->get_32(); if (magic == 0x46546C67) { //binary file //text file - err = _parse_glb(p_path, state); - if (err) { - return FAILED; + f->seek(0); + err = _parse_glb(f, state); + if (err != OK) { + return err; } } else { - //text file - err = _parse_json(p_path, state); - if (err) { - return FAILED; + f->seek(0); + String text = f->get_as_utf8_string(); + JSON json; + err = json.parse(text); + if (err != OK) { + _err_print_error("", "", json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); } + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + state->json = json.get_data(); } - f->close(); - - // get file's name, use for scene name if none - state->filename = p_path.get_file().get_slice(".", 0); - ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED); + if (!state->json.has("asset")) { + return ERR_PARSE_ERROR; + } Dictionary asset = state->json["asset"]; - ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED); + if (!asset.has("version")) { + return ERR_PARSE_ERROR; + } String version = asset["version"]; state->major_version = version.get_slice(".", 0).to_int(); state->minor_version = version.get_slice(".", 1).to_int(); - /* STEP 0 PARSE SCENE */ - err = _parse_scenes(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 1 PARSE NODES */ - err = _parse_nodes(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 2 PARSE BUFFERS */ - err = _parse_buffers(state, p_path.get_base_dir()); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 3 PARSE BUFFER VIEWS */ - err = _parse_buffer_views(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 4 PARSE ACCESSORS */ - err = _parse_accessors(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 5 PARSE IMAGES */ - err = _parse_images(state, p_path.get_base_dir()); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 6 PARSE TEXTURES */ - err = _parse_textures(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 7 PARSE TEXTURES */ - err = _parse_materials(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 9 PARSE SKINS */ - err = _parse_skins(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 10 DETERMINE SKELETONS */ - err = _determine_skeletons(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 11 CREATE SKELETONS */ - err = _create_skeletons(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 12 CREATE SKINS */ - err = _create_skins(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 13 PARSE MESHES (we have enough info now) */ - err = _parse_meshes(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 14 PARSE LIGHTS */ - err = _parse_lights(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 15 PARSE CAMERAS */ - err = _parse_cameras(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 16 PARSE ANIMATIONS */ - err = _parse_animations(state); - if (err != OK) { - return Error::FAILED; + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->import_preflight(this); + ERR_FAIL_COND_V(err != OK, FAILED); } - - /* STEP 17 ASSIGN SCENE NAMES */ - _assign_scene_names(state); - + err = _parse_gltf_state(state, p_path, p_bake_fps); + ERR_FAIL_COND_V(err != OK, err); return OK; } @@ -6776,8 +6698,8 @@ Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { Dictionary asset; asset["version"] = version; - String hash = VERSION_HASH; - asset["generator"] = String(VERSION_FULL_NAME) + String("@") + (hash.length() == 0 ? String("unknown") : hash); + String hash = String(VERSION_HASH); + asset["generator"] = String(VERSION_FULL_NAME) + String("@") + (hash.is_empty() ? String("unknown") : hash); state->json["asset"] = asset; ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED); ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED); @@ -6789,8 +6711,8 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { if (p_path.to_lower().ends_with("glb")) { err = _encode_buffer_glb(state, p_path); ERR_FAIL_COND_V(err != OK, err); - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(!f, FAILED); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(f.is_null(), FAILED); String json = Variant(state->json).to_json_string(); @@ -6827,105 +6749,33 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { f->store_8(0); } - - f->close(); } else { err = _encode_buffer_bins(state, p_path); ERR_FAIL_COND_V(err != OK, err); - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(!f, FAILED); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(f.is_null(), FAILED); f->create(FileAccess::ACCESS_RESOURCES); String json = Variant(state->json).to_json_string(); f->store_string(json); - f->close(); } return err; } -Error GLTFDocument::save_scene(Node *p_node, const String &p_path, - const String &p_src_path, uint32_t p_flags, - float p_bake_fps, Ref<GLTFState> r_state) { - ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); - - Ref<GLTFDocument> gltf_document; - gltf_document.instantiate(); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - Error err = ext->export_preflight(this, p_node); - ERR_FAIL_COND_V(err != OK, err); - } - - if (r_state == Ref<GLTFState>()) { - r_state.instantiate(); - } - Error err = gltf_document->serialize(r_state, p_node, p_path); - ERR_FAIL_COND_V(err != OK, err); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - err = ext->export_post(this); - ERR_FAIL_COND_V(err != OK, err); - } - return OK; -} - -Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err) { - // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire - if (r_state == Ref<GLTFState>()) { - r_state.instantiate(); - } - r_state->use_named_skin_binds = - p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; - - Ref<GLTFDocument> gltf_document; - gltf_document.instantiate(); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - Error err = ext->import_preflight(this); - if (r_err) { - *r_err = err; - } - ERR_FAIL_COND_V(err != OK, nullptr); - } - Error err = gltf_document->parse(r_state, p_path); - if (r_err) { - *r_err = err; - } - ERR_FAIL_COND_V(err != Error::OK, nullptr); - - Node3D *root = memnew(Node3D); - for (int32_t root_i = 0; root_i < r_state->root_nodes.size(); root_i++) { - gltf_document->_generate_scene_node(r_state, root, root, r_state->root_nodes[root_i]); - } - gltf_document->_process_mesh_instances(r_state, root); - if (r_state->animations.size()) { - AnimationPlayer *ap = memnew(AnimationPlayer); - root->add_child(ap, true); - ap->set_owner(root); - for (int i = 0; i < r_state->animations.size(); i++) { - gltf_document->_import_animation(r_state, ap, i, p_bake_fps); - } - } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - err = ext->import_post(this, root); - if (r_err) { - *r_err = err; - } - ERR_FAIL_COND_V(err != OK, nullptr); - } - return root; -} - void GLTFDocument::_bind_methods() { - ClassDB::bind_method(D_METHOD("save_scene", "node", "path", "src_path", "flags", "bake_fps", "state"), - &GLTFDocument::save_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>())); - ClassDB::bind_method(D_METHOD("import_scene", "path", "flags", "bake_fps", "state"), - &GLTFDocument::import_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>())); + ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "bake_fps", "base_path"), + &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(30), DEFVAL(String())); + ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags", "bake_fps"), + &GLTFDocument::append_from_buffer, DEFVAL(0), DEFVAL(30)); + ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags", "bake_fps"), + &GLTFDocument::append_from_scene, DEFVAL(0), DEFVAL(30)); + ClassDB::bind_method(D_METHOD("generate_scene", "state", "bake_fps"), + &GLTFDocument::generate_scene, DEFVAL(30)); + ClassDB::bind_method(D_METHOD("generate_buffer", "state"), + &GLTFDocument::generate_buffer); + ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"), + &GLTFDocument::write_to_filesystem); + ClassDB::bind_method(D_METHOD("set_extensions", "extensions"), &GLTFDocument::set_extensions); ClassDB::bind_method(D_METHOD("get_extensions"), @@ -6950,16 +6800,6 @@ void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) { } } -Node *GLTFDocument::import_scene(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state) { - Error err = FAILED; - List<String> deps; - Node *node = import_scene_gltf(p_path, p_flags, p_bake_fps, r_state, &deps, &err); - if (err != OK) { - return nullptr; - } - return node; -} - void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) { document_extensions = p_extensions; } @@ -6977,3 +6817,251 @@ GLTFDocument::GLTFDocument() { extension_editor.instantiate(); document_extensions.push_back(extension_editor); } + +PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error *r_err) { + Error err = _encode_buffer_glb(state, ""); + if (r_err) { + *r_err = err; + } + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + String json = Variant(state->json).to_json_string(); + + const uint32_t magic = 0x46546C67; // GLTF + const int32_t header_size = 12; + const int32_t chunk_header_size = 8; + + for (int32_t pad_i = 0; pad_i < (chunk_header_size + json.utf8().length()) % 4; pad_i++) { + json += " "; + } + CharString cs = json.utf8(); + const uint32_t text_chunk_length = cs.length(); + + const uint32_t text_chunk_type = 0x4E4F534A; //JSON + int32_t binary_data_length = 0; + if (state->buffers.size()) { + binary_data_length = state->buffers[0].size(); + } + const int32_t binary_chunk_length = binary_data_length; + const int32_t binary_chunk_type = 0x004E4942; //BIN + + Ref<StreamPeerBuffer> buffer; + buffer.instantiate(); + buffer->put_32(magic); + buffer->put_32(state->major_version); // version + buffer->put_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length + buffer->put_32(text_chunk_length); + buffer->put_32(text_chunk_type); + buffer->put_data((uint8_t *)&cs[0], cs.length()); + if (binary_chunk_length) { + buffer->put_32(binary_chunk_length); + buffer->put_32(binary_chunk_type); + buffer->put_data(state->buffers[0].ptr(), binary_data_length); + } + return buffer->get_data_array(); +} + +PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> state) { + ERR_FAIL_NULL_V(state, PackedByteArray()); + Error err = _serialize(state, ""); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + PackedByteArray bytes = _serialize_glb_buffer(state, &err); + return bytes; +} + +Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_path) { + ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); + + Error err = _serialize(state, p_path); + if (err != OK) { + return err; + } + + err = _serialize_file(state, p_path); + if (err != OK) { + return Error::FAILED; + } + return OK; +} + +Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { + ERR_FAIL_NULL_V(state, nullptr); + ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr); + GLTFNodeIndex gltf_root = state->root_nodes.write[0]; + Node *gltf_root_node = state->get_scene_node(gltf_root); + Node *root = gltf_root_node->get_parent(); + ERR_FAIL_NULL_V(root, nullptr); + _process_mesh_instances(state, root); + if (state->animations.size()) { + AnimationPlayer *ap = memnew(AnimationPlayer); + root->add_child(ap, true); + ap->set_owner(root); + for (int i = 0; i < state->animations.size(); i++) { + _import_animation(state, ap, i, p_bake_fps); + } + } + + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + Error err = ext->import_post(this, root); + ERR_FAIL_COND_V(err != OK, nullptr); + } + ERR_FAIL_NULL_V(root, nullptr); + return root; +} + +Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { + ERR_FAIL_COND_V(state.is_null(), FAILED); + state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + + _convert_scene_node(state, p_node, -1, -1); + if (!state->buffers.size()) { + state->buffers.push_back(Vector<uint8_t>()); + } + + /* STEP 1 CONVERT MESH INSTANCES */ + _convert_mesh_instances(state); + + /* STEP 2 CREATE SKINS */ + Error err = _serialize_skins(state); + return err; +} + +Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { + ERR_FAIL_COND_V(state.is_null(), FAILED); + // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire + Error err = FAILED; + state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + + Ref<FileAccessMemory> file_access; + file_access.instantiate(); + file_access->open_custom(p_bytes.ptr(), p_bytes.size()); + err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps); + ERR_FAIL_COND_V(err != OK, FAILED); + return OK; +} + +Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps) { + Error err; + + /* PARSE EXTENSIONS */ + err = _parse_gltf_extensions(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE SCENE */ + err = _parse_scenes(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE NODES */ + err = _parse_nodes(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE BUFFERS */ + err = _parse_buffers(state, p_search_path); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE BUFFER VIEWS */ + err = _parse_buffer_views(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE ACCESSORS */ + err = _parse_accessors(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + if (!state->discard_meshes_and_materials) { + /* PARSE IMAGES */ + err = _parse_images(state, p_search_path); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE TEXTURES */ + err = _parse_textures(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE TEXTURES */ + err = _parse_materials(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + } + + /* PARSE SKINS */ + err = _parse_skins(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* DETERMINE SKELETONS */ + err = _determine_skeletons(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* CREATE SKELETONS */ + err = _create_skeletons(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* CREATE SKINS */ + err = _create_skins(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE MESHES (we have enough info now) */ + err = _parse_meshes(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE LIGHTS */ + err = _parse_lights(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE CAMERAS */ + err = _parse_cameras(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE ANIMATIONS */ + err = _parse_animations(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* ASSIGN SCENE NAMES */ + _assign_scene_names(state); + + Node3D *root = memnew(Node3D); + for (int32_t root_i = 0; root_i < state->root_nodes.size(); root_i++) { + _generate_scene_node(state, root, root, state->root_nodes[root_i]); + } + return OK; +} + +Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, int32_t p_bake_fps, String p_base_path) { + // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire + if (r_state == Ref<GLTFState>()) { + r_state.instantiate(); + } + r_state->filename = p_path.get_file().get_basename(); + r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + r_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + Error err; + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); + ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN); + String base_path = p_base_path; + if (base_path.is_empty()) { + base_path = p_path.get_base_dir(); + } + err = _parse(r_state, base_path, f, p_bake_fps); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + return err; +} + +Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) { + ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR); + if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) { + Array extensions_required = state->json["extensionsRequired"]; + if (extensions_required.find("KHR_draco_mesh_compression") != -1) { + ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported."); + return ERR_UNAVAILABLE; + } + } + return OK; +} diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index f8d9521733..19bc507a8d 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,6 +33,7 @@ #include "gltf_animation.h" +#include "core/error/error_list.h" #include "core/variant/dictionary.h" #include "core/variant/variant.h" #include "gltf_document_extension_convert_importer_mesh.h" @@ -120,11 +121,6 @@ protected: static void _bind_methods(); public: - Node *import_scene(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state); - Node *import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err = nullptr); - Error save_scene(Node *p_node, const String &p_path, - const String &p_src_path, uint32_t p_flags, - float p_bake_fps, Ref<GLTFState> r_state); void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions); TypedArray<GLTFDocumentExtension> get_extensions() const; @@ -200,7 +196,7 @@ private: Ref<Texture2D> _get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture); Error _parse_json(const String &p_path, Ref<GLTFState> state); - Error _parse_glb(const String &p_path, Ref<GLTFState> state); + Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state); void _compute_node_heights(Ref<GLTFState> state); Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path); Error _parse_buffer_views(Ref<GLTFState> state); @@ -287,10 +283,10 @@ private: Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index); - ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); - Camera3D *_generate_camera(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); - Node3D *_generate_light(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); - Node3D *_generate_spatial(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); + ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index); void _assign_scene_names(Ref<GLTFState> state); template <class T> T _interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values, @@ -361,6 +357,7 @@ private: GLTFNodeIndex p_node_i); Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path); Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path); + PackedByteArray _serialize_glb_buffer(Ref<GLTFState> state, Error *r_err); Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material); Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material); Error _serialize_version(Ref<GLTFState> state); @@ -384,6 +381,18 @@ private: static float get_max_component(const Color &p_color); public: + Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30, String p_base_path = String()); + Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + +public: + Node *generate_scene(Ref<GLTFState> state, int32_t p_bake_fps = 30.0f); + PackedByteArray generate_buffer(Ref<GLTFState> state); + Error write_to_filesystem(Ref<GLTFState> state, const String &p_path); + +public: + Error _parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps); + Error _parse_gltf_extensions(Ref<GLTFState> state); void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root); void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, @@ -447,8 +456,8 @@ public: MeshInstance3D *p_mesh_instance); void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name); - Error serialize(Ref<GLTFState> state, Node *p_root, const String &p_path); - Error parse(Ref<GLTFState> state, String p_paths, bool p_read_binary = false); + Error _serialize(Ref<GLTFState> state, const String &p_path); + Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps); }; #endif // GLTF_DOCUMENT_H diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp index a423059a9c..192a1d347c 100644 --- a/modules/gltf/gltf_document_extension.cpp +++ b/modules/gltf/gltf_document_extension.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h index 622a65708c..f7a3531282 100644 --- a/modules/gltf/gltf_document_extension.h +++ b/modules/gltf/gltf_document_extension.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp index 56c8f5ca27..47a3e5598f 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/gltf_document_extension_convert_importer_mesh.h index 85ddb4d250..2d51143140 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.h +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_light.cpp b/modules/gltf/gltf_light.cpp index c5aa8d5724..af21a4e804 100644 --- a/modules/gltf/gltf_light.cpp +++ b/modules/gltf/gltf_light.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_light.h b/modules/gltf/gltf_light.h index 62a20d2f16..25e0835a33 100644 --- a/modules/gltf/gltf_light.h +++ b/modules/gltf/gltf_light.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp index 7134345b30..3add8304b1 100644 --- a/modules/gltf/gltf_mesh.cpp +++ b/modules/gltf/gltf_mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "gltf_mesh.h" + #include "scene/resources/importer_mesh.h" void GLTFMesh::_bind_methods() { diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h index cc2be93c09..dc26120b48 100644 --- a/modules/gltf/gltf_mesh.h +++ b/modules/gltf/gltf_mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,7 +32,6 @@ #define GLTF_MESH_H #include "core/io/resource.h" -#include "editor/import/resource_importer_scene.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/resources/importer_mesh.h" #include "scene/resources/mesh.h" @@ -56,4 +55,5 @@ public: Array get_instance_materials(); void set_instance_materials(Array p_instance_materials); }; + #endif // GLTF_MESH_H diff --git a/modules/gltf/gltf_node.cpp b/modules/gltf/gltf_node.cpp index 9f925c7bbc..86280603fa 100644 --- a/modules/gltf/gltf_node.cpp +++ b/modules/gltf/gltf_node.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h index 3b6e061449..929ad3eca0 100644 --- a/modules/gltf/gltf_node.h +++ b/modules/gltf/gltf_node.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_skeleton.cpp b/modules/gltf/gltf_skeleton.cpp index d6c7a25eaf..e80376f130 100644 --- a/modules/gltf/gltf_skeleton.cpp +++ b/modules/gltf/gltf_skeleton.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_skeleton.h b/modules/gltf/gltf_skeleton.h index d6986eb35a..7d07d528cb 100644 --- a/modules/gltf/gltf_skeleton.h +++ b/modules/gltf/gltf_skeleton.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp index 5cf17135ac..283fc34ff5 100644 --- a/modules/gltf/gltf_skin.cpp +++ b/modules/gltf/gltf_skin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h index e32e2d397c..31cb892f19 100644 --- a/modules/gltf/gltf_skin.h +++ b/modules/gltf/gltf_skin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_spec_gloss.cpp b/modules/gltf/gltf_spec_gloss.cpp index 70b182da52..83af91bfcc 100644 --- a/modules/gltf/gltf_spec_gloss.cpp +++ b/modules/gltf/gltf_spec_gloss.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_spec_gloss.h b/modules/gltf/gltf_spec_gloss.h index 3cc6fb09ed..f8a431bdce 100644 --- a/modules/gltf/gltf_spec_gloss.h +++ b/modules/gltf/gltf_spec_gloss.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index ff9778e7d8..6ead2f69c3 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -305,3 +305,11 @@ AnimationPlayer *GLTFState::get_animation_player(int idx) { ERR_FAIL_INDEX_V(idx, animation_players.size(), nullptr); return animation_players[idx]; } + +void GLTFState::set_discard_meshes_and_materials(bool p_discard_meshes_and_materials) { + discard_meshes_and_materials = p_discard_meshes_and_materials; +} + +bool GLTFState::get_discard_meshes_and_materials() { + return discard_meshes_and_materials; +} diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 61faba0dc5..42ca079f1c 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -62,6 +62,7 @@ class GLTFState : public Resource { Vector<uint8_t> glb_data; bool use_named_skin_binds = false; + bool discard_meshes_and_materials = false; Vector<Ref<GLTFNode>> nodes; Vector<Vector<uint8_t>> buffers; @@ -112,6 +113,9 @@ public: bool get_use_named_skin_binds(); void set_use_named_skin_binds(bool p_use_named_skin_binds); + bool get_discard_meshes_and_materials(); + void set_discard_meshes_and_materials(bool p_discard_meshes_and_materials); + Array get_nodes(); void set_nodes(Array p_nodes); diff --git a/modules/gltf/gltf_texture.cpp b/modules/gltf/gltf_texture.cpp index 0482c1064e..2a21cb3df8 100644 --- a/modules/gltf/gltf_texture.cpp +++ b/modules/gltf/gltf_texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/gltf_texture.h b/modules/gltf/gltf_texture.h index 4659725502..54dd61f9a5 100644 --- a/modules/gltf/gltf_texture.h +++ b/modules/gltf/gltf_texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 5a60c2d328..b8bac79584 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,9 +30,8 @@ #include "register_types.h" -#include "editor/editor_node.h" -#include "editor_scene_exporter_gltf_plugin.h" -#include "editor_scene_importer_gltf.h" +#ifndef _3D_DISABLED + #include "gltf_accessor.h" #include "gltf_animation.h" #include "gltf_buffer_view.h" @@ -49,43 +48,105 @@ #include "gltf_state.h" #include "gltf_texture.h" -#ifndef _3D_DISABLED #ifdef TOOLS_ENABLED +#include "core/config/project_settings.h" +#include "editor/editor_node.h" +#include "editor/editor_scene_exporter_gltf_plugin.h" +#include "editor/editor_scene_importer_blend.h" +#include "editor/editor_scene_importer_fbx.h" +#include "editor/editor_scene_importer_gltf.h" +#include "editor/editor_settings.h" + static void _editor_init() { Ref<EditorSceneFormatImporterGLTF> import_gltf; import_gltf.instantiate(); - ResourceImporterScene::get_singleton()->add_importer(import_gltf); + ResourceImporterScene::add_importer(import_gltf); + + // Blend to glTF importer. + + bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); + // Defined here because EditorSettings doesn't exist in `register_gltf_types` yet. + EDITOR_DEF_RST("filesystem/import/blender/blender3_path", ""); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, + "filesystem/import/blender/blender3_path", PROPERTY_HINT_GLOBAL_DIR)); + if (blend_enabled) { + Ref<EditorSceneFormatImporterBlend> importer; + importer.instantiate(); + ResourceImporterScene::add_importer(importer); + + Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query; + blend_import_query.instantiate(); + EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query); + } + + // FBX to glTF importer. + + bool fbx_enabled = GLOBAL_GET("filesystem/import/fbx/enabled"); + // Defined here because EditorSettings doesn't exist in `register_gltf_types` yet. + String fbx2gltf_path = EDITOR_DEF_RST("filesystem/import/fbx/fbx2gltf_path", ""); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, + "filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE)); + if (fbx_enabled) { + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (fbx2gltf_path.is_empty()) { + WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported."); + } else if (!da->file_exists(fbx2gltf_path)) { + WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to a valid FBX2glTF executable. FBX files will not be imported."); + } else { + Ref<EditorSceneFormatImporterFBX> importer; + importer.instantiate(); + ResourceImporterScene::add_importer(importer); + } + } } -#endif -#endif +#endif // TOOLS_ENABLED + +void initialize_gltf_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { + // glTF API available at runtime. + GDREGISTER_CLASS(GLTFAccessor); + GDREGISTER_CLASS(GLTFAnimation); + GDREGISTER_CLASS(GLTFBufferView); + GDREGISTER_CLASS(GLTFCamera); + GDREGISTER_CLASS(GLTFDocument); + GDREGISTER_CLASS(GLTFDocumentExtension); + GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh); + GDREGISTER_CLASS(GLTFLight); + GDREGISTER_CLASS(GLTFMesh); + GDREGISTER_CLASS(GLTFNode); + GDREGISTER_CLASS(GLTFSkeleton); + GDREGISTER_CLASS(GLTFSkin); + GDREGISTER_CLASS(GLTFSpecGloss); + GDREGISTER_CLASS(GLTFState); + GDREGISTER_CLASS(GLTFTexture); + } -void register_gltf_types() { -#ifndef _3D_DISABLED #ifdef TOOLS_ENABLED - ClassDB::APIType prev_api = ClassDB::get_current_api(); - ClassDB::set_current_api(ClassDB::API_EDITOR); - GDREGISTER_CLASS(EditorSceneFormatImporterGLTF); - GDREGISTER_CLASS(GLTFMesh); - EditorPlugins::add_by_type<SceneExporterGLTFPlugin>(); - ClassDB::set_current_api(prev_api); - EditorNode::add_init_callback(_editor_init); -#endif - 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(GLTFDocumentExtensionConvertImporterMesh); - GDREGISTER_CLASS(GLTFDocumentExtension); - GDREGISTER_CLASS(GLTFDocument); -#endif + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + // Editor-specific API. + ClassDB::APIType prev_api = ClassDB::get_current_api(); + ClassDB::set_current_api(ClassDB::API_EDITOR); + + GDREGISTER_CLASS(EditorSceneFormatImporterGLTF); + EditorPlugins::add_by_type<SceneExporterGLTFPlugin>(); + + // Project settings defined here so doctool finds them. + GLOBAL_DEF_RST("filesystem/import/blender/enabled", true); + GLOBAL_DEF_RST("filesystem/import/fbx/enabled", true); + GDREGISTER_CLASS(EditorSceneFormatImporterBlend); + GDREGISTER_CLASS(EditorSceneFormatImporterFBX); + + ClassDB::set_current_api(prev_api); + EditorNode::add_init_callback(_editor_init); + } + +#endif // TOOLS_ENABLED } -void unregister_gltf_types() { +void uninitialize_gltf_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } + +#endif // _3D_DISABLED diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h index fefacb1106..90b9a83c88 100644 --- a/modules/gltf/register_types.h +++ b/modules/gltf/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,5 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -void register_gltf_types(); -void unregister_gltf_types(); +#include "modules/register_module_types.h" + +void initialize_gltf_module(ModuleInitializationLevel p_level); +void uninitialize_gltf_module(ModuleInitializationLevel p_level); diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub index 970ce534f0..52777235b8 100644 --- a/modules/gridmap/SCsub +++ b/modules/gridmap/SCsub @@ -5,4 +5,7 @@ Import("env_modules") env_gridmap = env_modules.Clone() +# Godot's own source files env_gridmap.add_source_files(env.modules_sources, "*.cpp") +if env["tools"]: + env_gridmap.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 73315350ff..407ce961c8 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GridMap" inherits="Node3D" version="4.0"> +<class name="GridMap" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Node for 3D tile-based maps. </brief_description> @@ -67,7 +67,7 @@ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32. </description> </method> - <method name="get_meshes"> + <method name="get_meshes" qualifiers="const"> <return type="Array" /> <description> Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space. @@ -79,6 +79,13 @@ Returns an array of [Vector3] with the non-empty cell coordinates in the grid map. </description> </method> + <method name="get_used_cells_by_item" qualifiers="const"> + <return type="Array" /> + <argument index="0" name="item" type="int" /> + <description> + Returns an array of all cells with the given item index specified in [code]item[/code]. + </description> + </method> <method name="make_baked_meshes"> <return type="void" /> <argument index="0" name="gen_lightmap_uv" type="bool" default="false" /> @@ -110,15 +117,6 @@ Optionally, the item's orientation can be passed. For valid orientation values, see [method Basis.get_orthogonal_index]. </description> </method> - <method name="set_clip"> - <return type="void" /> - <argument index="0" name="enabled" type="bool" /> - <argument index="1" name="clipabove" type="bool" default="true" /> - <argument index="2" name="floor" type="int" default="0" /> - <argument index="3" name="axis" type="int" enum="Vector3.Axis" default="0" /> - <description> - </description> - </method> <method name="set_collision_layer_value"> <return type="void" /> <argument index="0" name="layer_number" type="int" /> @@ -181,6 +179,9 @@ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> The navigation layers the GridMap generates its navigable regions in. </member> + <member name="physics_material" type="PhysicsMaterial" setter="set_physics_material" getter="get_physics_material"> + Overrides the default friction and bounce physics properties for the whole [GridMap]. + </member> </members> <signals> <signal name="cell_size_changed"> diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index c2169c6335..2f613768ee 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -29,13 +29,16 @@ /*************************************************************************/ #include "grid_map_editor_plugin.h" + +#ifdef TOOLS_ENABLED + #include "core/input/input.h" +#include "core/os/keyboard.h" +#include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" - -#include "core/os/keyboard.h" #include "scene/main/window.h" void GridMapEditor::_node_removed(Node *p_node) { @@ -62,17 +65,6 @@ void GridMapEditor::_menu_option(int p_option) { floor->set_value(floor->get_value() + 1); } break; - case MENU_OPTION_CLIP_DISABLED: - case MENU_OPTION_CLIP_ABOVE: - case MENU_OPTION_CLIP_BELOW: { - clip_mode = ClipMode(p_option - MENU_OPTION_CLIP_DISABLED); - for (int i = 0; i < 3; i++) { - int index = options->get_popup()->get_item_index(MENU_OPTION_CLIP_DISABLED + i); - options->get_popup()->set_item_checked(index, i == clip_mode); - } - - _update_clip(); - } break; case MENU_OPTION_X_AXIS: case MENU_OPTION_Y_AXIS: case MENU_OPTION_Z_AXIS: { @@ -97,7 +89,6 @@ void GridMapEditor::_menu_option(int p_option) { } edit_axis = Vector3::Axis(new_axis); update_grid(); - _update_clip(); } break; case MENU_OPTION_CURSOR_ROTATE_Y: { @@ -834,7 +825,7 @@ void GridMapEditor::_icon_size_changed(float p_value) { void GridMapEditor::update_palette() { int selected = mesh_library_palette->get_current(); - float min_size = EDITOR_DEF("editors/grid_map/preview_size", 64); + float min_size = EDITOR_GET("editors/grid_map/preview_size"); min_size *= EDSCALE; mesh_library_palette->clear(); @@ -889,7 +880,7 @@ void GridMapEditor::update_palette() { name = "#" + itos(id); } - if (!filter.is_empty() && !filter.is_subsequence_ofi(name)) { + if (!filter.is_empty() && !filter.is_subsequence_ofn(name)) { continue; } @@ -923,7 +914,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { _update_selection_transform(); _update_paste_indicator(); - spatial_editor = Object::cast_to<Node3DEditorPlugin>(editor->get_editor_plugin_screen()); + spatial_editor = Object::cast_to<Node3DEditorPlugin>(EditorNode::get_singleton()->get_editor_plugin_screen()); if (!node) { set_process(false); @@ -942,24 +933,12 @@ void GridMapEditor::edit(GridMap *p_gridmap) { set_process(true); - clip_mode = p_gridmap->has_meta("_editor_clip_") ? ClipMode(p_gridmap->get_meta("_editor_clip_").operator int()) : CLIP_DISABLED; - _draw_grids(node->get_cell_size()); update_grid(); - _update_clip(); node->connect("cell_size_changed", callable_mp(this, &GridMapEditor::_draw_grids)); } -void GridMapEditor::_update_clip() { - node->set_meta("_editor_clip_", clip_mode); - if (clip_mode == CLIP_DISABLED) { - node->set_clip(false); - } else { - node->set_clip(true, clip_mode == CLIP_ABOVE, edit_floor[edit_axis], edit_axis); - } -} - void GridMapEditor::update_grid() { grid_xform.origin.x -= 1; // Force update in hackish way. @@ -978,7 +957,7 @@ void GridMapEditor::update_grid() { } void GridMapEditor::_draw_grids(const Vector3 &cell_size) { - Vector3 edited_floor = node->has_meta("_editor_floor_") ? node->get_meta("_editor_floor_") : Variant(); + Vector3 edited_floor = node->get_meta("_editor_floor_", Vector3()); for (int i = 0; i < 3; i++) { RS::get_singleton()->mesh_clear(grid[i]); @@ -1028,6 +1007,13 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) { } } +void GridMapEditor::_update_theme() { + options->set_icon(get_theme_icon(SNAME("GridMap"), SNAME("EditorIcons"))); + search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + mode_thumbnail->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"))); + mode_list->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"))); +} + void GridMapEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -1048,6 +1034,7 @@ void GridMapEditor::_notification(int p_what) { _update_selection_transform(); _update_paste_indicator(); + _update_theme(); } break; case NOTIFICATION_EXIT_TREE: { @@ -1088,8 +1075,7 @@ void GridMapEditor::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - options->set_icon(get_theme_icon(SNAME("GridMap"), SNAME("EditorIcons"))); - search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + _update_theme(); } break; case NOTIFICATION_APPLICATION_FOCUS_OUT: { @@ -1139,7 +1125,6 @@ void GridMapEditor::_floor_changed(float p_value) { edit_floor[edit_axis] = p_value; node->set_meta("_editor_floor_", Vector3(edit_floor[0], edit_floor[1], edit_floor[2])); update_grid(); - _update_clip(); _update_selection_transform(); } @@ -1152,9 +1137,8 @@ void GridMapEditor::_bind_methods() { ClassDB::bind_method("_set_selection", &GridMapEditor::_set_selection); } -GridMapEditor::GridMapEditor(EditorNode *p_editor) { - editor = p_editor; - undo_redo = p_editor->get_undo_redo(); +GridMapEditor::GridMapEditor() { + undo_redo = EditorNode::get_singleton()->get_undo_redo(); int mw = EDITOR_DEF("editors/grid_map/palette_min_width", 230); Control *ec = memnew(Control); @@ -1191,11 +1175,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { 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(); - options->get_popup()->add_radio_check_item(TTR("Clip Disabled"), MENU_OPTION_CLIP_DISABLED); - options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_CLIP_DISABLED), true); - options->get_popup()->add_radio_check_item(TTR("Clip Above"), MENU_OPTION_CLIP_ABOVE); - options->get_popup()->add_radio_check_item(TTR("Clip Below"), MENU_OPTION_CLIP_BELOW); - options->get_popup()->add_separator(); options->get_popup()->add_radio_check_item(TTR("Edit X Axis"), MENU_OPTION_X_AXIS, Key::Z); options->get_popup()->add_radio_check_item(TTR("Edit Y Axis"), MENU_OPTION_Y_AXIS, Key::X); options->get_popup()->add_radio_check_item(TTR("Edit Z Axis"), MENU_OPTION_Z_AXIS, Key::C); @@ -1230,7 +1209,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { settings_pick_distance->set_max(10000.0f); settings_pick_distance->set_min(500.0f); settings_pick_distance->set_step(1.0f); - settings_pick_distance->set_value(EDITOR_DEF("editors/grid_map/pick_distance", 5000.0)); + settings_pick_distance->set_value(EDITOR_GET("editors/grid_map/pick_distance")); settings_vbc->add_margin_child(TTR("Pick Distance:"), settings_pick_distance); options->get_popup()->connect("id_pressed", callable_mp(this, &GridMapEditor::_menu_option)); @@ -1250,7 +1229,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { mode_thumbnail->set_flat(true); mode_thumbnail->set_toggle_mode(true); mode_thumbnail->set_pressed(true); - mode_thumbnail->set_icon(p_editor->get_gui_base()->get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"))); hb->add_child(mode_thumbnail); mode_thumbnail->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode), varray(DISPLAY_THUMBNAIL)); @@ -1258,7 +1236,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { mode_list->set_flat(true); mode_list->set_toggle_mode(true); mode_list->set_pressed(false); - mode_list->set_icon(p_editor->get_gui_base()->get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"))); hb->add_child(mode_list); mode_list->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode), varray(DISPLAY_LIST)); @@ -1451,15 +1428,17 @@ GridMapEditor::~GridMapEditor() { } void GridMapEditorPlugin::_notification(int p_what) { - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) { - case 0: { // Left. - Node3DEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 0); - } break; - case 1: { // Right. - Node3DEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 1); - } break; - } + switch (p_what) { + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) { + case 0: { // Left. + Node3DEditor::get_singleton()->move_control_to_left_panel(grid_map_editor); + } break; + case 1: { // Right. + Node3DEditor::get_singleton()->move_control_to_right_panel(grid_map_editor); + } break; + } + } break; } } @@ -1484,19 +1463,17 @@ void GridMapEditorPlugin::make_visible(bool p_visible) { } } -GridMapEditorPlugin::GridMapEditorPlugin(EditorNode *p_node) { - editor = p_node; - +GridMapEditorPlugin::GridMapEditorPlugin() { EDITOR_DEF("editors/grid_map/editor_side", 1); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/grid_map/editor_side", PROPERTY_HINT_ENUM, "Left,Right")); - grid_map_editor = memnew(GridMapEditor(editor)); + grid_map_editor = memnew(GridMapEditor); switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) { case 0: { // Left. - add_control_to_container(CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, grid_map_editor); + Node3DEditor::get_singleton()->add_control_to_left_panel(grid_map_editor); } break; case 1: { // Right. - add_control_to_container(CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT, grid_map_editor); + Node3DEditor::get_singleton()->add_control_to_right_panel(grid_map_editor); } break; } grid_map_editor->hide(); @@ -1504,3 +1481,5 @@ GridMapEditorPlugin::GridMapEditorPlugin(EditorNode *p_node) { GridMapEditorPlugin::~GridMapEditorPlugin() { } + +#endif // TOOLS_ENABLED diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index 1a6b1310d8..3b29397502 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,9 +31,13 @@ #ifndef GRID_MAP_EDITOR_PLUGIN_H #define GRID_MAP_EDITOR_PLUGIN_H -#include "editor/editor_node.h" +#ifdef TOOLS_ENABLED + +#include "../grid_map.h" #include "editor/editor_plugin.h" -#include "grid_map.h" +#include "scene/gui/item_list.h" +#include "scene/gui/slider.h" +#include "scene/gui/spin_box.h" class Node3DEditorPlugin; @@ -53,32 +57,26 @@ class GridMapEditor : public VBoxContainer { INPUT_PASTE, }; - enum ClipMode { - CLIP_DISABLED, - CLIP_ABOVE, - CLIP_BELOW - }; - enum DisplayMode { DISPLAY_THUMBNAIL, DISPLAY_LIST }; - UndoRedo *undo_redo; + UndoRedo *undo_redo = nullptr; InputAction input_action = INPUT_NONE; - Panel *panel; - MenuButton *options; - SpinBox *floor; + Panel *panel = nullptr; + MenuButton *options = nullptr; + SpinBox *floor = nullptr; double accumulated_floor_delta = 0.0; - Button *mode_thumbnail; - Button *mode_list; - LineEdit *search_box; - HSlider *size_slider; - HBoxContainer *spatial_editor_hb; - ConfirmationDialog *settings_dialog; - VBoxContainer *settings_vbc; - SpinBox *settings_pick_distance; - Label *spin_box_label; + Button *mode_thumbnail = nullptr; + Button *mode_list = nullptr; + LineEdit *search_box = nullptr; + HSlider *size_slider = nullptr; + HBoxContainer *spatial_editor_hb = nullptr; + ConfirmationDialog *settings_dialog = nullptr; + VBoxContainer *settings_vbc = nullptr; + SpinBox *settings_pick_distance = nullptr; + Label *spin_box_label = nullptr; struct SetItem { Vector3i position; @@ -91,8 +89,7 @@ class GridMapEditor : public VBoxContainer { List<SetItem> set_items; GridMap *node = nullptr; - MeshLibrary *last_mesh_library; - ClipMode clip_mode = CLIP_DISABLED; + MeshLibrary *last_mesh_library = nullptr; Transform3D grid_xform; Transform3D edit_grid_xform; @@ -157,9 +154,6 @@ class GridMapEditor : public VBoxContainer { MENU_OPTION_NEXT_LEVEL, MENU_OPTION_PREV_LEVEL, MENU_OPTION_LOCK_VIEW, - MENU_OPTION_CLIP_DISABLED, - MENU_OPTION_CLIP_ABOVE, - MENU_OPTION_CLIP_BELOW, MENU_OPTION_X_AXIS, MENU_OPTION_Y_AXIS, MENU_OPTION_Z_AXIS, @@ -179,17 +173,15 @@ class GridMapEditor : public VBoxContainer { }; - Node3DEditorPlugin *spatial_editor; + Node3DEditorPlugin *spatial_editor = nullptr; struct AreaDisplay { RID mesh; RID instance; }; - ItemList *mesh_library_palette; - Label *info_message; - - EditorNode *editor; + ItemList *mesh_library_palette = nullptr; + Label *info_message = nullptr; void update_grid(); // Change which and where the grid is displayed void _draw_grids(const Vector3 &cell_size); @@ -200,7 +192,7 @@ class GridMapEditor : public VBoxContainer { void _item_selected_cbk(int idx); void _update_cursor_transform(); void _update_cursor_instance(); - void _update_clip(); + void _update_theme(); void _text_changed(const String &p_text); void _sbox_input(const Ref<InputEvent> &p_ie); @@ -235,16 +227,14 @@ public: EditorPlugin::AfterGUIInput forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event); void edit(GridMap *p_gridmap); - GridMapEditor() {} - GridMapEditor(EditorNode *p_editor); + GridMapEditor(); ~GridMapEditor(); }; class GridMapEditorPlugin : public EditorPlugin { GDCLASS(GridMapEditorPlugin, EditorPlugin); - GridMapEditor *grid_map_editor; - EditorNode *editor; + GridMapEditor *grid_map_editor = nullptr; protected: void _notification(int p_what); @@ -257,8 +247,10 @@ public: virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; - GridMapEditorPlugin(EditorNode *p_node); + GridMapEditorPlugin(); ~GridMapEditorPlugin(); }; -#endif // CUBE_GRID_MAP_EDITOR_PLUGIN_H +#endif // TOOLS_ENABLED + +#endif // GRID_MAP_EDITOR_PLUGIN_H diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index c9d8f2b42b..3c7bd5eb70 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,6 +34,8 @@ #include "core/object/message_queue.h" #include "scene/3d/light_3d.h" #include "scene/resources/mesh_library.h" +#include "scene/resources/physics_material.h" +#include "scene/resources/primitive_meshes.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" @@ -181,12 +183,39 @@ void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) { set_collision_mask(mask); } +void GridMap::set_physics_material(Ref<PhysicsMaterial> p_material) { + physics_material = p_material; + _recreate_octant_data(); +} + +Ref<PhysicsMaterial> GridMap::get_physics_material() const { + return physics_material; +} + bool GridMap::get_collision_mask_value(int p_layer_number) const { ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive."); ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive."); return get_collision_mask() & (1 << (p_layer_number - 1)); } +Array GridMap::get_collision_shapes() const { + Array shapes; + for (const KeyValue<OctantKey, Octant *> &E : octant_map) { + Octant *g = E.value; + RID body = g->static_body; + Transform3D body_xform = PhysicsServer3D::get_singleton()->body_get_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM); + int nshapes = PhysicsServer3D::get_singleton()->body_get_shape_count(body); + for (int i = 0; i < nshapes; i++) { + RID shape = PhysicsServer3D::get_singleton()->body_get_shape(body, i); + Transform3D xform = PhysicsServer3D::get_singleton()->body_get_shape_transform(body, i); + shapes.push_back(body_xform * xform); + shapes.push_back(shape); + } + } + + return shapes; +} + void GridMap::set_bake_navigation(bool p_bake_navigation) { bake_navigation = p_bake_navigation; _recreate_octant_data(); @@ -316,6 +345,10 @@ void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id()); PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer); PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask); + if (physics_material.is_valid()) { + PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_FRICTION, physics_material->get_friction()); + PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material->get_bounce()); + } SceneTree *st = SceneTree::get_singleton(); if (st && st->is_debugging_collisions_hint()) { @@ -670,8 +703,8 @@ void GridMap::_notification(int p_what) { RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, get_world_3d()->get_scenario()); RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform()); } - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { Transform3D new_xform = get_global_transform(); if (new_xform == last_transform) { @@ -688,6 +721,7 @@ void GridMap::_notification(int p_what) { RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform()); } } break; + case NOTIFICATION_EXIT_WORLD: { for (const KeyValue<OctantKey, Octant *> &E : octant_map) { _octant_exit_world(E.key); @@ -699,8 +733,8 @@ void GridMap::_notification(int p_what) { for (int i = 0; i < baked_meshes.size(); i++) { RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID()); } - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_visibility(); } break; @@ -763,7 +797,7 @@ void GridMap::clear() { clear_baked_meshes(); } -void GridMap::resource_changed(const RES &p_res) { +void GridMap::resource_changed(const Ref<Resource> &p_res) { _recreate_octant_data(); } @@ -780,6 +814,7 @@ void GridMap::_update_octants_callback() { } while (to_delete.front()) { + memdelete(octant_map[to_delete.front()->get()]); octant_map.erase(to_delete.front()->get()); to_delete.pop_front(); } @@ -801,6 +836,9 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value); ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value); + ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &GridMap::set_physics_material); + ClassDB::bind_method(D_METHOD("get_physics_material"), &GridMap::get_physics_material); + ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation); ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation); @@ -836,11 +874,10 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_center_z", "enable"), &GridMap::set_center_z); ClassDB::bind_method(D_METHOD("get_center_z"), &GridMap::get_center_z); - ClassDB::bind_method(D_METHOD("set_clip", "enabled", "clipabove", "floor", "axis"), &GridMap::set_clip, DEFVAL(true), DEFVAL(0), DEFVAL(Vector3::AXIS_X)); - ClassDB::bind_method(D_METHOD("clear"), &GridMap::clear); ClassDB::bind_method(D_METHOD("get_used_cells"), &GridMap::get_used_cells); + ClassDB::bind_method(D_METHOD("get_used_cells_by_item", "item"), &GridMap::get_used_cells_by_item); ClassDB::bind_method(D_METHOD("get_meshes"), &GridMap::get_meshes); ClassDB::bind_method(D_METHOD("get_bake_meshes"), &GridMap::get_bake_meshes); @@ -850,6 +887,7 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1)); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material", "get_physics_material"); ADD_GROUP("Cell", "cell_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size"); @@ -869,28 +907,6 @@ void GridMap::_bind_methods() { ADD_SIGNAL(MethodInfo("cell_size_changed", PropertyInfo(Variant::VECTOR3, "cell_size"))); } -void GridMap::set_clip(bool p_enabled, bool p_clip_above, int p_floor, Vector3::Axis p_axis) { - if (!p_enabled && !clip) { - return; - } - if (clip && p_enabled && clip_floor == p_floor && p_clip_above == clip_above && p_axis == clip_axis) { - return; - } - - clip = p_enabled; - clip_floor = p_floor; - clip_axis = p_axis; - clip_above = p_clip_above; - - //make it all update - for (KeyValue<OctantKey, Octant *> &E : octant_map) { - Octant *g = E.value; - g->dirty = true; - } - awaiting_update = true; - _update_octants_callback(); -} - void GridMap::set_cell_scale(float p_scale) { cell_scale = p_scale; _recreate_octant_data(); @@ -912,7 +928,19 @@ Array GridMap::get_used_cells() const { return a; } -Array GridMap::get_meshes() { +Array GridMap::get_used_cells_by_item(int p_item) const { + Array a; + for (const KeyValue<IndexKey, Cell> &E : cell_map) { + if (E.value.item == p_item) { + Vector3 p(E.key.x, E.key.y, E.key.z); + a.push_back(p); + } + } + + return a; +} + +Array GridMap::get_meshes() const { if (mesh_library.is_null()) { return Array(); } @@ -920,7 +948,7 @@ Array GridMap::get_meshes() { Vector3 ofs = _get_offset(); Array meshes; - for (KeyValue<IndexKey, Cell> &E : cell_map) { + for (const KeyValue<IndexKey, Cell> &E : cell_map) { int id = E.value.item; if (!mesh_library->has_item(id)) { continue; diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 879489fc70..5e367e149d 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -38,6 +38,8 @@ //heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done.. //should scale better with hardware that supports instancing +class PhysicsMaterial; + class GridMap : public Node3D { GDCLASS(GridMap, Node3D); @@ -134,6 +136,7 @@ class GridMap : public Node3D { uint32_t collision_layer = 1; uint32_t collision_mask = 1; + Ref<PhysicsMaterial> physics_material; bool bake_navigation = false; uint32_t navigation_layers = 1; @@ -147,14 +150,8 @@ class GridMap : public Node3D { bool center_z = true; float cell_scale = 1.0; - bool clip = false; - bool clip_above = true; - int clip_floor = 0; - bool recreating_octants = false; - Vector3::Axis clip_axis = Vector3::AXIS_Z; - Ref<MeshLibrary> mesh_library; Map<OctantKey, Octant *> octant_map; @@ -184,7 +181,7 @@ class GridMap : public Node3D { void _queue_octants_dirty(); void _update_octants_callback(); - void resource_changed(const RES &p_res); + void resource_changed(const Ref<Resource> &p_res); void _clear_internal(); @@ -223,6 +220,11 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_physics_material(Ref<PhysicsMaterial> p_material); + Ref<PhysicsMaterial> get_physics_material() const; + + Array get_collision_shapes() const; + void set_bake_navigation(bool p_bake_navigation); bool is_baking_navigation(); @@ -252,14 +254,13 @@ public: Vector3i world_to_map(const Vector3 &p_world_position) const; Vector3 map_to_world(const Vector3i &p_map_position) const; - void set_clip(bool p_enabled, bool p_clip_above = true, int p_floor = 0, Vector3::Axis p_axis = Vector3::AXIS_X); - void set_cell_scale(float p_scale); float get_cell_scale() const; Array get_used_cells() const; + Array get_used_cells_by_item(int p_item) const; - Array get_meshes(); + Array get_meshes() const; void clear_baked_meshes(); void make_baked_meshes(bool p_gen_lightmap_uv = false, float p_lightmap_uv_texel_size = 0.1); diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp index 85739d202e..9efd18a265 100644 --- a/modules/gridmap/register_types.cpp +++ b/modules/gridmap/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,21 +28,32 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "register_types.h" #ifndef _3D_DISABLED + +#include "register_types.h" + #include "core/object/class_db.h" #include "grid_map.h" -#include "grid_map_editor_plugin.h" -#endif -void register_gridmap_types() { -#ifndef _3D_DISABLED - GDREGISTER_CLASS(GridMap); #ifdef TOOLS_ENABLED - EditorPlugins::add_by_type<GridMapEditorPlugin>(); +#include "editor/grid_map_editor_plugin.h" #endif + +void initialize_gridmap_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { + GDREGISTER_CLASS(GridMap); + } +#ifdef TOOLS_ENABLED + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + EditorPlugins::add_by_type<GridMapEditorPlugin>(); + } #endif } -void unregister_gridmap_types() { +void uninitialize_gridmap_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } + +#endif // _3D_DISABLED diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h index b977f4c5da..28f14cd398 100644 --- a/modules/gridmap/register_types.h +++ b/modules/gridmap/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef GRIDMAP_REGISTER_TYPES_H #define GRIDMAP_REGISTER_TYPES_H -void register_gridmap_types(); -void unregister_gridmap_types(); +#include "modules/register_module_types.h" + +void initialize_gridmap_module(ModuleInitializationLevel p_level); +void uninitialize_gridmap_module(ModuleInitializationLevel p_level); #endif // GRIDMAP_REGISTER_TYPES_H diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index ea28d0c0c8..eca689e87a 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,7 +33,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { String header = f->get_token(); ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + "."); @@ -132,7 +132,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force ptr[2] * exp / 255.0); if (p_force_linear) { - c = c.to_linear(); + c = c.srgb_to_linear(); } *(uint32_t *)ptr = c.to_rgbe9995(); diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h index 33fcdd1245..f2d53cc206 100644 --- a/modules/hdr/image_loader_hdr.h +++ b/modules/hdr/image_loader_hdr.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,7 +35,7 @@ class ImageLoaderHDR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderHDR(); }; diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp index 5a4a1993e0..b988bf4587 100644 --- a/modules/hdr/register_types.cpp +++ b/modules/hdr/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,19 @@ static ImageLoaderHDR *image_loader_hdr = nullptr; -void register_hdr_types() { +void initialize_hdr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + image_loader_hdr = memnew(ImageLoaderHDR); ImageLoader::add_image_format_loader(image_loader_hdr); } -void unregister_hdr_types() { +void uninitialize_hdr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + memdelete(image_loader_hdr); } diff --git a/modules/hdr/register_types.h b/modules/hdr/register_types.h index c85bc84dce..0254e43b6c 100644 --- a/modules/hdr/register_types.h +++ b/modules/hdr/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef HDR_REGISTER_TYPES_H #define HDR_REGISTER_TYPES_H -void register_hdr_types(); -void unregister_hdr_types(); +#include "modules/register_module_types.h" + +void initialize_hdr_module(ModuleInitializationLevel p_level); +void uninitialize_hdr_module(ModuleInitializationLevel p_level); #endif // HDR_REGISTER_TYPES_H diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index b5e4753e8d..51358876a4 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -103,7 +103,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p return OK; } -Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -113,8 +113,6 @@ Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force f->get_buffer(&w[0], src_image_len); - f->close(); - Error err = jpeg_load_image_from_buffer(p_image.ptr(), w, src_image_len); return err; diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h index be265b280c..de9700faec 100644 --- a/modules/jpg/image_loader_jpegd.h +++ b/modules/jpg/image_loader_jpegd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,7 +35,7 @@ class ImageLoaderJPG : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderJPG(); }; diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp index a6ae96635f..b8b48a550f 100644 --- a/modules/jpg/register_types.cpp +++ b/modules/jpg/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,19 @@ static ImageLoaderJPG *image_loader_jpg = nullptr; -void register_jpg_types() { +void initialize_jpg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + image_loader_jpg = memnew(ImageLoaderJPG); ImageLoader::add_image_format_loader(image_loader_jpg); } -void unregister_jpg_types() { +void uninitialize_jpg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + memdelete(image_loader_jpg); } diff --git a/modules/jpg/register_types.h b/modules/jpg/register_types.h index 577e9b06f7..f0a205f6a8 100644 --- a/modules/jpg/register_types.h +++ b/modules/jpg/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef JPG_REGISTER_TYPES_H #define JPG_REGISTER_TYPES_H -void register_jpg_types(); -void unregister_jpg_types(); +#include "modules/register_module_types.h" + +void initialize_jpg_module(ModuleInitializationLevel p_level); +void uninitialize_jpg_module(ModuleInitializationLevel p_level); #endif // JPG_REGISTER_TYPES_H diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp index 3d0759d83e..91774fe1f6 100644 --- a/modules/jsonrpc/jsonrpc.cpp +++ b/modules/jsonrpc/jsonrpc.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/jsonrpc/jsonrpc.h b/modules/jsonrpc/jsonrpc.h index 9fd016602d..3144746f6d 100644 --- a/modules/jsonrpc/jsonrpc.h +++ b/modules/jsonrpc/jsonrpc.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/jsonrpc/register_types.cpp b/modules/jsonrpc/register_types.cpp index 8fdf6fe1aa..6d35d6aeb8 100644 --- a/modules/jsonrpc/register_types.cpp +++ b/modules/jsonrpc/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,9 +32,16 @@ #include "core/object/class_db.h" #include "jsonrpc.h" -void register_jsonrpc_types() { +void initialize_jsonrpc_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(JSONRPC); } -void unregister_jsonrpc_types() { +void uninitialize_jsonrpc_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/jsonrpc/register_types.h b/modules/jsonrpc/register_types.h index 6a21a12444..83d315a9eb 100644 --- a/modules/jsonrpc/register_types.h +++ b/modules/jsonrpc/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef JSONRPC_REGISTER_TYPES_H #define JSONRPC_REGISTER_TYPES_H -void register_jsonrpc_types(); -void unregister_jsonrpc_types(); +#include "modules/register_module_types.h" + +void initialize_jsonrpc_module(ModuleInitializationLevel p_level); +void uninitialize_jsonrpc_module(ModuleInitializationLevel p_level); #endif // JSONRPC_REGISTER_TYPES_H diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 37e969db4d..214c60091c 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "lightmapper_rd.h" + #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" #include "lm_blendseams.glsl.gen.h" @@ -174,7 +175,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ } if (p_step_function) { - p_step_function(0.1, TTR("Determining optimal atlas size"), p_bake_userdata, true); + p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true); } atlas_size = Size2i(max, max); @@ -243,7 +244,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ emission_images.resize(atlas_slices); if (p_step_function) { - p_step_function(0.2, TTR("Blitting albedo and emission"), p_bake_userdata, true); + p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true); } for (int i = 0; i < atlas_slices; i++) { @@ -295,7 +296,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i for (int m_i = 0; m_i < mesh_instances.size(); m_i++) { if (p_step_function) { float p = float(m_i + 1) / mesh_instances.size() * 0.1; - p_step_function(0.3 + p, vformat(TTR("Plotting mesh into acceleration structure %d/%d"), m_i + 1, mesh_instances.size()), p_bake_userdata, false); + p_step_function(0.3 + p, vformat(RTR("Plotting mesh into acceleration structure %d/%d"), m_i + 1, mesh_instances.size()), p_bake_userdata, false); } HashMap<Edge, EdgeUV2, EdgeHash> edges; @@ -409,7 +410,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i seams.sort(); if (p_step_function) { - p_step_function(0.4, TTR("Optimizing acceleration structure"), p_bake_userdata, true); + p_step_function(0.4, RTR("Optimizing acceleration structure"), p_bake_userdata, true); } //fill list of triangles in grid @@ -618,14 +619,14 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; - u.ids.push_back(dest_light_tex); + u.append_id(dest_light_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - u.ids.push_back(source_light_tex); + u.append_id(source_light_tex); uniforms.push_back(u); } } @@ -668,7 +669,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata) { if (p_step_function) { - p_step_function(0.0, TTR("Begin Bake"), p_bake_userdata, true); + p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true); } bake_textures.clear(); int grid_size = 128; @@ -775,11 +776,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } else { 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++) { - panorama_tex->set_pixel(i, j, Color(0, 0, 0, 1)); - } - } + panorama_tex->fill(Color(0, 0, 0, 1)); } RD::TextureFormat tfp; @@ -823,7 +820,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d _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, 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); + p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true); } //shaders @@ -860,70 +857,70 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; - u.ids.push_back(vertex_buffer); + u.append_id(vertex_buffer); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; - u.ids.push_back(triangle_buffer); + u.append_id(triangle_buffer); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; - u.ids.push_back(triangle_cell_indices_buffer); + u.append_id(triangle_cell_indices_buffer); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; - u.ids.push_back(lights_buffer); + u.append_id(lights_buffer); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; - u.ids.push_back(seams_buffer); + u.append_id(seams_buffer); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; - u.ids.push_back(probe_positions_buffer); + u.append_id(probe_positions_buffer); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 7; - u.ids.push_back(grid_texture); + u.append_id(grid_texture); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 8; - u.ids.push_back(albedo_array_tex); + u.append_id(albedo_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; - u.ids.push_back(emission_array_tex); + u.append_id(emission_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; - u.ids.push_back(sampler); + u.append_id(sampler); base_uniforms.push_back(u); } } @@ -1031,17 +1028,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d push_constant.atlas_slice = 0; push_constant.region_ofs[0] = 0; push_constant.region_ofs[1] = 0; - push_constant.environment_xform[0] = p_environment_transform.elements[0][0]; - push_constant.environment_xform[1] = p_environment_transform.elements[1][0]; - push_constant.environment_xform[2] = p_environment_transform.elements[2][0]; + push_constant.environment_xform[0] = p_environment_transform.rows[0][0]; + push_constant.environment_xform[1] = p_environment_transform.rows[1][0]; + push_constant.environment_xform[2] = p_environment_transform.rows[2][0]; push_constant.environment_xform[3] = 0; - push_constant.environment_xform[4] = p_environment_transform.elements[0][1]; - push_constant.environment_xform[5] = p_environment_transform.elements[1][1]; - push_constant.environment_xform[6] = p_environment_transform.elements[2][1]; + push_constant.environment_xform[4] = p_environment_transform.rows[0][1]; + push_constant.environment_xform[5] = p_environment_transform.rows[1][1]; + push_constant.environment_xform[6] = p_environment_transform.rows[2][1]; push_constant.environment_xform[7] = 0; - push_constant.environment_xform[8] = p_environment_transform.elements[0][2]; - push_constant.environment_xform[9] = p_environment_transform.elements[1][2]; - push_constant.environment_xform[10] = p_environment_transform.elements[2][2]; + push_constant.environment_xform[8] = p_environment_transform.rows[0][2]; + push_constant.environment_xform[9] = p_environment_transform.rows[1][2]; + push_constant.environment_xform[10] = p_environment_transform.rows[2][2]; push_constant.environment_xform[11] = 0; } @@ -1050,7 +1047,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d rd->sync(); if (p_step_function) { - p_step_function(0.49, TTR("Un-occluding geometry"), p_bake_userdata, true); + p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true); } /* UNOCCLUDE */ @@ -1061,14 +1058,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; - u.ids.push_back(position_tex); + u.append_id(position_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; - u.ids.push_back(unocclude_tex); //will be unused + u.append_id(unocclude_tex); //will be unused uniforms.push_back(u); } } @@ -1090,7 +1087,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } if (p_step_function) { - p_step_function(0.5, TTR("Plot direct lighting"), p_bake_userdata, true); + p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true); } /* PRIMARY (direct) LIGHT PASS */ @@ -1101,42 +1098,42 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; - u.ids.push_back(light_source_tex); + u.append_id(light_source_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - u.ids.push_back(light_dest_tex); //will be unused + u.append_id(light_dest_tex); //will be unused uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - u.ids.push_back(position_tex); + u.append_id(position_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; - u.ids.push_back(normal_tex); + u.append_id(normal_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; - u.ids.push_back(light_accum_tex); + u.append_id(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; - u.ids.push_back(light_primary_dynamic_tex); + u.append_id(light_primary_dynamic_tex); uniforms.push_back(u); } } @@ -1170,7 +1167,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d /* SECONDARY (indirect) LIGHT PASS(ES) */ if (p_step_function) { - p_step_function(0.6, TTR("Integrate indirect lighting"), p_bake_userdata, true); + p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true); } if (p_bounces > 0) { @@ -1180,57 +1177,57 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; - u.ids.push_back(light_dest_tex); + u.append_id(light_dest_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - u.ids.push_back(light_source_tex); + u.append_id(light_source_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - u.ids.push_back(position_tex); + u.append_id(position_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; - u.ids.push_back(normal_tex); + u.append_id(normal_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; - u.ids.push_back(light_accum_tex); + u.append_id(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; - u.ids.push_back(unocclude_tex); //reuse unocclude tex + u.append_id(unocclude_tex); //reuse unocclude tex uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; - u.ids.push_back(light_environment_tex); + u.append_id(light_environment_tex); uniforms.push_back(u); } } RID secondary_uniform_set[2]; secondary_uniform_set[0] = rd->uniform_set_create(uniforms, compute_shader_secondary, 1); - uniforms.write[0].ids.write[0] = light_source_tex; - uniforms.write[1].ids.write[0] = light_dest_tex; + uniforms.write[0].set_id(0, light_source_tex); + uniforms.write[1].set_id(0, light_dest_tex); secondary_uniform_set[1] = rd->uniform_set_create(uniforms, compute_shader_secondary, 1); switch (p_quality) { @@ -1248,7 +1245,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } break; } - push_constant.ray_count = CLAMP(push_constant.ray_count, 16, 8192); + push_constant.ray_count = CLAMP(push_constant.ray_count, 16u, 8192u); int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/lightmapping/bake_performance/region_size"))); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_pass"); @@ -1302,7 +1299,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d int total = (atlas_slices * x_regions * y_regions * ray_iterations); int percent = count * 100 / total; float p = float(count) / total * 0.1; - p_step_function(0.6 + p, vformat(TTR("Bounce %d/%d: Integrate indirect lighting %d%%"), b + 1, p_bounces, percent), p_bake_userdata, false); + p_step_function(0.6 + p, vformat(RTR("Bounce %d/%d: Integrate indirect lighting %d%%"), b + 1, p_bounces, percent), p_bake_userdata, false); } } } @@ -1327,7 +1324,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d light_probe_buffer = rd->storage_buffer_create(sizeof(float) * 4 * 9 * probe_positions.size()); if (p_step_function) { - p_step_function(0.7, TTR("Baking lightprobes"), p_bake_userdata, true); + p_step_function(0.7, RTR("Baking lightprobes"), p_bake_userdata, true); } Vector<RD::Uniform> uniforms; @@ -1336,28 +1333,28 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; - u.ids.push_back(light_probe_buffer); + u.append_id(light_probe_buffer); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - u.ids.push_back(light_dest_tex); + u.append_id(light_dest_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - u.ids.push_back(light_primary_dynamic_tex); + u.append_id(light_primary_dynamic_tex); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; - u.ids.push_back(light_environment_tex); + u.append_id(light_environment_tex); uniforms.push_back(u); } } @@ -1379,7 +1376,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } push_constant.atlas_size[0] = probe_positions.size(); - push_constant.ray_count = CLAMP(push_constant.ray_count, 16, 8192); + push_constant.ray_count = CLAMP(push_constant.ray_count, 16u, 8192u); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_probe_pass"); int ray_iterations = (push_constant.ray_count - 1) / max_rays + 1; @@ -1402,7 +1399,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d if (p_step_function) { int percent = i * 100 / ray_iterations; float p = float(i) / ray_iterations * 0.1; - p_step_function(0.7 + p, vformat(TTR("Integrating light probes %d%%"), percent), p_bake_userdata, false); + p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false); } } @@ -1438,7 +1435,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d if (p_use_denoiser) { if (p_step_function) { - p_step_function(0.8, TTR("Denoising"), p_bake_userdata, true); + p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true); } Ref<LightmapDenoiser> denoiser = LightmapDenoiser::create(); @@ -1535,7 +1532,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - u.ids.push_back(light_accum_tex2); + u.append_id(light_accum_tex2); uniforms.push_back(u); } } @@ -1643,7 +1640,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } #endif if (p_step_function) { - p_step_function(0.9, TTR("Retrieving textures"), p_bake_userdata, true); + p_step_function(0.9, RTR("Retrieving textures"), p_bake_userdata, true); } for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h index 51ab60fc29..503f5f7009 100644 --- a/modules/lightmapper_rd/lightmapper_rd.h +++ b/modules/lightmapper_rd/lightmapper_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/lightmapper_rd/lm_blendseams.glsl b/modules/lightmapper_rd/lm_blendseams.glsl index 374c48082e..70164e27c4 100644 --- a/modules/lightmapper_rd/lm_blendseams.glsl +++ b/modules/lightmapper_rd/lm_blendseams.glsl @@ -11,7 +11,7 @@ triangles = "#define MODE_TRIANGLES"; #include "lm_common_inc.glsl" -layout(push_constant, binding = 0, std430) uniform Params { +layout(push_constant, std430) uniform Params { uint base_index; uint slice; vec2 uv_offset; @@ -78,7 +78,7 @@ void main() { #include "lm_common_inc.glsl" -layout(push_constant, binding = 0, std430) uniform Params { +layout(push_constant, std430) uniform Params { uint base_index; uint slice; vec2 uv_offset; diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 7bb8346c47..0b6b72a310 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -70,7 +70,7 @@ layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2DArray de layout(set = 1, binding = 1) uniform texture2DArray source_light; #endif -layout(push_constant, binding = 0, std430) uniform Params { +layout(push_constant, std430) uniform Params { ivec2 atlas_size; // x used for light probe mode total probes uint ray_count; uint ray_to; diff --git a/modules/lightmapper_rd/lm_raster.glsl b/modules/lightmapper_rd/lm_raster.glsl index a86968a4f3..875c3e967a 100644 --- a/modules/lightmapper_rd/lm_raster.glsl +++ b/modules/lightmapper_rd/lm_raster.glsl @@ -14,7 +14,7 @@ layout(location = 4) flat out uvec3 vertex_indices; layout(location = 5) flat out vec3 face_normal; layout(location = 6) flat out uint fragment_action; -layout(push_constant, binding = 0, std430) uniform Params { +layout(push_constant, std430) uniform Params { vec2 atlas_size; vec2 uv_offset; vec3 to_cell_size; @@ -69,7 +69,7 @@ void main() { #include "lm_common_inc.glsl" -layout(push_constant, binding = 0, std430) uniform Params { +layout(push_constant, std430) uniform Params { vec2 atlas_size; vec2 uv_offset; vec3 to_cell_size; diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp index ae9c5fc390..0e0330c1a1 100644 --- a/modules/lightmapper_rd/register_types.cpp +++ b/modules/lightmapper_rd/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -40,7 +40,11 @@ static Lightmapper *create_lightmapper_rd() { } #endif -void register_lightmapper_rd_types() { +void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_ray_count", 16); GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_ray_count", 64); GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_ray_count", 256); @@ -59,5 +63,8 @@ void register_lightmapper_rd_types() { #endif } -void unregister_lightmapper_rd_types() { +void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/lightmapper_rd/register_types.h b/modules/lightmapper_rd/register_types.h index 622d6e37a7..42e0ebbf77 100644 --- a/modules/lightmapper_rd/register_types.h +++ b/modules/lightmapper_rd/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef LIGHTMAPPER_RD_REGISTER_TYPES_H #define LIGHTMAPPER_RD_REGISTER_TYPES_H -void register_lightmapper_rd_types(); -void unregister_lightmapper_rd_types(); +#include "modules/register_module_types.h" + +void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level); +void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level); #endif // XATLAS_UNWRAP_REGISTER_TYPES_H diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub index 4fcbe8fb43..9133fdef35 100644 --- a/modules/mbedtls/SCsub +++ b/modules/mbedtls/SCsub @@ -29,6 +29,7 @@ if env["builtin_mbedtls"]: "cipher_wrap.c", "cmac.c", "ctr_drbg.c", + "constant_time.c", "debug.c", "des.c", "dhm.c", @@ -48,8 +49,9 @@ if env["builtin_mbedtls"]: "md4.c", "md5.c", "md.c", - "md_wrap.c", "memory_buffer_alloc.c", + "mps_reader.c", + "mps_trace.c", "net_sockets.c", "nist_kw.c", "oid.c", @@ -75,9 +77,11 @@ if env["builtin_mbedtls"]: "ssl_ciphersuites.c", "ssl_cli.c", "ssl_cookie.c", + "ssl_msg.c", "ssl_srv.c", "ssl_ticket.c", "ssl_tls.c", + "ssl_tls13_keys.c", "threading.c", "timing.c", "version.c", diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index 9d985e16d4..e62581ab40 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -55,14 +55,13 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use"); PackedByteArray out; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator - memdelete(f); int ret = 0; if (p_public_only) { @@ -79,8 +78,8 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { } Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); unsigned char w[16000]; memset(w, 0, sizeof(w)); @@ -92,14 +91,12 @@ Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w)); } if (ret != 0) { - memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written. ERR_FAIL_V_MSG(FAILED, "Error writing key '" + itos(ret) + "'."); } size_t len = strlen((char *)w); f->store_buffer(w, len); - memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize temporary buffer. return OK; } @@ -143,14 +140,13 @@ Error X509CertificateMbedTLS::load(String p_path) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is in use"); PackedByteArray out; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator - memdelete(f); int ret = mbedtls_x509_crt_parse(&cert, out.ptr(), out.size()); ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing some certificates: " + itos(ret)); @@ -167,8 +163,8 @@ Error X509CertificateMbedTLS::load_from_memory(const uint8_t *p_buffer, int p_le } Error X509CertificateMbedTLS::save(String p_path) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'."); mbedtls_x509_crt *crt = &cert; while (crt) { @@ -176,14 +172,12 @@ Error X509CertificateMbedTLS::save(String p_path) { size_t wrote = 0; int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote); if (ret != 0 || wrote == 0) { - memdelete(f); ERR_FAIL_V_MSG(FAILED, "Error writing certificate '" + itos(ret) + "'."); } f->store_buffer(w, wrote - 1); // don't write the string terminator crt = crt->next; } - memdelete(f); return OK; } diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h index afa1ea7a64..5ba7e9cbf6 100644 --- a/modules/mbedtls/crypto_mbedtls.h +++ b/modules/mbedtls/crypto_mbedtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp index b1b6b3844b..dedf0651a0 100644 --- a/modules/mbedtls/dtls_server_mbedtls.cpp +++ b/modules/mbedtls/dtls_server_mbedtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/dtls_server_mbedtls.h b/modules/mbedtls/dtls_server_mbedtls.h index 9f0c9670e7..29370062c4 100644 --- a/modules/mbedtls/dtls_server_mbedtls.h +++ b/modules/mbedtls/dtls_server_mbedtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp index 114bf49e9e..1296a4587c 100644 --- a/modules/mbedtls/packet_peer_mbed_dtls.cpp +++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,11 +35,11 @@ #include "core/io/stream_peer_ssl.h" int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx; + PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); @@ -53,11 +53,11 @@ int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len } int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx; + PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); @@ -115,7 +115,7 @@ Error PacketPeerMbedDTLS::_do_handshake() { } Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs, const String &p_for_hostname, Ref<X509Certificate> p_ca_certs) { - ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_connected_to_host(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER); base = p_base; int ret = 0; diff --git a/modules/mbedtls/packet_peer_mbed_dtls.h b/modules/mbedtls/packet_peer_mbed_dtls.h index 92e6ab88c4..5f2f42cd30 100644 --- a/modules/mbedtls/packet_peer_mbed_dtls.h +++ b/modules/mbedtls/packet_peer_mbed_dtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/register_types.cpp b/modules/mbedtls/register_types.cpp index e483030b94..2d4a18b3fc 100644 --- a/modules/mbedtls/register_types.cpp +++ b/modules/mbedtls/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -39,14 +39,22 @@ #include "tests/test_crypto_mbedtls.h" #endif -void register_mbedtls_types() { +void initialize_mbedtls_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + CryptoMbedTLS::initialize_crypto(); StreamPeerMbedTLS::initialize_ssl(); PacketPeerMbedDTLS::initialize_dtls(); DTLSServerMbedTLS::initialize(); } -void unregister_mbedtls_types() { +void uninitialize_mbedtls_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + DTLSServerMbedTLS::finalize(); PacketPeerMbedDTLS::finalize_dtls(); StreamPeerMbedTLS::finalize_ssl(); diff --git a/modules/mbedtls/register_types.h b/modules/mbedtls/register_types.h index 46ffb8522b..ebe76f44f1 100644 --- a/modules/mbedtls/register_types.h +++ b/modules/mbedtls/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef MBEDTLS_REGISTER_TYPES_H #define MBEDTLS_REGISTER_TYPES_H -void register_mbedtls_types(); -void unregister_mbedtls_types(); +#include "modules/register_module_types.h" + +void initialize_mbedtls_module(ModuleInitializationLevel p_level); +void uninitialize_mbedtls_module(ModuleInitializationLevel p_level); #endif // MBEDTLS_REGISTER_TYPES_H diff --git a/modules/mbedtls/ssl_context_mbedtls.cpp b/modules/mbedtls/ssl_context_mbedtls.cpp index cbb532587f..e2dad074cc 100644 --- a/modules/mbedtls/ssl_context_mbedtls.cpp +++ b/modules/mbedtls/ssl_context_mbedtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/ssl_context_mbedtls.h b/modules/mbedtls/ssl_context_mbedtls.h index 5692dec1b6..dd49792abd 100644 --- a/modules/mbedtls/ssl_context_mbedtls.h +++ b/modules/mbedtls/ssl_context_mbedtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp index 5727f5f82f..1818048877 100644 --- a/modules/mbedtls/stream_peer_mbedtls.cpp +++ b/modules/mbedtls/stream_peer_mbedtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,11 @@ #include "core/io/stream_peer_tcp.h" int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx; + StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); @@ -54,11 +54,11 @@ int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) } int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx; + StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h index 407479e3cc..98b91e65ab 100644 --- a/modules/mbedtls/stream_peer_mbedtls.h +++ b/modules/mbedtls/stream_peer_mbedtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.cpp b/modules/mbedtls/tests/test_crypto_mbedtls.cpp index 8762838883..f88012c6cd 100644 --- a/modules/mbedtls/tests/test_crypto_mbedtls.cpp +++ b/modules/mbedtls/tests/test_crypto_mbedtls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mbedtls/tests/test_crypto_mbedtls.h b/modules/mbedtls/tests/test_crypto_mbedtls.h index b798717e52..6f920e5b34 100644 --- a/modules/mbedtls/tests/test_crypto_mbedtls.h +++ b/modules/mbedtls/tests/test_crypto_mbedtls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp index 77cc82a4e2..3e212360c0 100644 --- a/modules/meshoptimizer/register_types.cpp +++ b/modules/meshoptimizer/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,17 +32,31 @@ #include "scene/resources/surface_tool.h" #include "thirdparty/meshoptimizer/meshoptimizer.h" -void register_meshoptimizer_types() { +void initialize_meshoptimizer_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + 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; + SurfaceTool::generate_remap_func = meshopt_generateVertexRemap; + SurfaceTool::remap_vertex_func = meshopt_remapVertexBuffer; + SurfaceTool::remap_index_func = meshopt_remapIndexBuffer; } -void unregister_meshoptimizer_types() { +void uninitialize_meshoptimizer_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + SurfaceTool::optimize_vertex_cache_func = nullptr; SurfaceTool::simplify_func = nullptr; SurfaceTool::simplify_scale_func = nullptr; SurfaceTool::simplify_sloppy_func = nullptr; + SurfaceTool::generate_remap_func = nullptr; + SurfaceTool::remap_vertex_func = nullptr; + SurfaceTool::remap_index_func = nullptr; } diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h index 5b15503acd..99c71efceb 100644 --- a/modules/meshoptimizer/register_types.h +++ b/modules/meshoptimizer/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef MESHOPTIMIZER_REGISTER_TYPES_H #define MESHOPTIMIZER_REGISTER_TYPES_H -void register_meshoptimizer_types(); -void unregister_meshoptimizer_types(); +#include "modules/register_module_types.h" + +void initialize_meshoptimizer_module(ModuleInitializationLevel p_level); +void uninitialize_meshoptimizer_module(ModuleInitializationLevel p_level); #endif // PVR_REGISTER_TYPES_H diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 17406b7263..b5b51403f7 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -83,7 +83,7 @@ void AudioStreamPlaybackMP3::start(float p_from_pos) { active = true; seek(p_from_pos); loops = 0; - _begin_resample(); + begin_resample(); } void AudioStreamPlaybackMP3::stop() { diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h index e3adfe683b..c1a60ddccb 100644 --- a/modules/minimp3/audio_stream_mp3.h +++ b/modules/minimp3/audio_stream_mp3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml index e4f56614ee..f5f7d3ef17 100644 --- a/modules/minimp3/doc_classes/AudioStreamMP3.xml +++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamMP3" inherits="AudioStream" version="4.0"> +<class name="AudioStreamMP3" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> MP3 audio stream driver. </brief_description> diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp index 63f2589f42..9d1b56abdf 100644 --- a/modules/minimp3/register_types.cpp +++ b/modules/minimp3/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,7 +37,11 @@ #include "resource_importer_mp3.h" #endif -void register_minimp3_types() { +void initialize_minimp3_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { Ref<ResourceImporterMP3> mp3_import; @@ -48,5 +52,8 @@ void register_minimp3_types() { GDREGISTER_CLASS(AudioStreamMP3); } -void unregister_minimp3_types() { +void uninitialize_minimp3_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h index 96227c272e..9e5eb85abe 100644 --- a/modules/minimp3/register_types.h +++ b/modules/minimp3/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef MINIMP3_REGISTER_TYPES_H #define MINIMP3_REGISTER_TYPES_H -void register_minimp3_types(); -void unregister_minimp3_types(); +#include "modules/register_module_types.h" + +void initialize_minimp3_module(ModuleInitializationLevel p_level); +void uninitialize_minimp3_module(ModuleInitializationLevel p_level); #endif // MINIMP3_REGISTER_TYPES_H diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index b2a755e23b..6cd710e792 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -75,9 +75,8 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_OPEN); uint64_t len = f->get_length(); @@ -87,8 +86,6 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s f->get_buffer(w, len); - memdelete(f); - Ref<AudioStreamMP3> mp3_stream; mp3_stream.instantiate(); diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h index 356ec77d22..75890228b9 100644 --- a/modules/minimp3/resource_importer_mp3.h +++ b/modules/minimp3/resource_importer_mp3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml index df099f2c98..db186079b0 100644 --- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml +++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MobileVRInterface" inherits="XRInterface" version="4.0"> +<class name="MobileVRInterface" inherits="XRInterface" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Generic mobile VR implementation. </brief_description> diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index ba7353ace2..5876b6cbf3 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -112,9 +112,9 @@ Basis MobileVRInterface::combine_acc_mag(const Vector3 &p_grav, const Vector3 &p // We use our gravity and magnetometer vectors to construct our matrix Basis acc_mag_m3; - acc_mag_m3.elements[0] = -magneto_east; - acc_mag_m3.elements[1] = up; - acc_mag_m3.elements[2] = magneto; + acc_mag_m3.rows[0] = -magneto_east; + acc_mag_m3.rows[1] = up; + acc_mag_m3.rows[2] = magneto; return acc_mag_m3; }; @@ -175,12 +175,13 @@ void MobileVRInterface::set_position_from_sensors() { if (has_gyro) { // start with applying our gyro (do NOT smooth our gyro!) Basis rotate; - rotate.rotate(orientation.get_axis(0), gyro.x * delta_time); - rotate.rotate(orientation.get_axis(1), gyro.y * delta_time); - rotate.rotate(orientation.get_axis(2), gyro.z * delta_time); + rotate.rotate(orientation.get_column(0), gyro.x * delta_time); + rotate.rotate(orientation.get_column(1), gyro.y * delta_time); + rotate.rotate(orientation.get_column(2), gyro.z * delta_time); orientation = rotate * orientation; tracking_state = XRInterface::XR_NORMAL_TRACKING; + tracking_confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; }; ///@TODO improve this, the magnetometer is very fidgety sometimes flipping the axis for no apparent reason (probably a bug on my part) @@ -193,6 +194,7 @@ void MobileVRInterface::set_position_from_sensors() { orientation = Basis(transform_quat); tracking_state = XRInterface::XR_NORMAL_TRACKING; + tracking_confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; } else if (has_grav) { // use gravity vector to make sure down is down... // transform gravity into our world space @@ -461,7 +463,7 @@ CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, double return eye; }; -Vector<BlitToScreen> MobileVRInterface::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { +Vector<BlitToScreen> MobileVRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { _THREAD_SAFE_METHOD_ Vector<BlitToScreen> blit_to_screen; @@ -512,7 +514,7 @@ void MobileVRInterface::process() { if (head.is_valid()) { // Set our head position, note in real space, reference frame and world scale is applied later - head->set_pose("default", head_transform, Vector3(), Vector3()); + head->set_pose("default", head_transform, Vector3(), Vector3(), tracking_confidence); } }; }; diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index b5bf966247..8ecca3a2ae 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,8 +35,6 @@ #include "servers/xr/xr_positional_tracker.h" /** - @author Bastiaan Olij <mux213@gmail.com> - The mobile interface is a native VR interface that can be used on Android and iOS phones. It contains a basic implementation supporting 3DOF tracking if a gyroscope and accelerometer are present and sets up the proper projection matrices based on the values provided. @@ -53,6 +51,7 @@ class MobileVRInterface : public XRInterface { private: bool initialized = false; XRInterface::TrackingStatus tracking_state; + XRPose::TrackingConfidence tracking_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; // Just set some defaults for these. At some point we need to look at adding a lookup table for common device + headset combos and/or support reading cardboard QR codes double eye_height = 1.85; @@ -152,7 +151,7 @@ public: 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, double p_aspect, double p_z_near, double p_z_far) override; - virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void process() override; @@ -160,4 +159,4 @@ public: ~MobileVRInterface(); }; -#endif // !MOBILE_VR_INTERFACE_H +#endif // MOBILE_VR_INTERFACE_H diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp index 233c16531a..4df8af9009 100644 --- a/modules/mobile_vr/register_types.cpp +++ b/modules/mobile_vr/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,7 +34,11 @@ Ref<MobileVRInterface> mobile_vr; -void register_mobile_vr_types() { +void initialize_mobile_vr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(MobileVRInterface); if (XRServer::get_singleton()) { @@ -43,7 +47,11 @@ void register_mobile_vr_types() { } } -void unregister_mobile_vr_types() { +void uninitialize_mobile_vr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + if (mobile_vr.is_valid()) { // uninitialise our interface if it is initialised if (mobile_vr->is_initialized()) { diff --git a/modules/mobile_vr/register_types.h b/modules/mobile_vr/register_types.h index 9f20f252a4..26812af512 100644 --- a/modules/mobile_vr/register_types.h +++ b/modules/mobile_vr/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef MOBILE_VR_REGISTER_TYPES_H #define MOBILE_VR_REGISTER_TYPES_H -void register_mobile_vr_types(); -void unregister_mobile_vr_types(); +#include "modules/register_module_types.h" + +void initialize_mobile_vr_module(ModuleInitializationLevel p_level); +void uninitialize_mobile_vr_module(ModuleInitializationLevel p_level); #endif // MOBILE_VR_REGISTER_TYPES_H diff --git a/modules/modules_builders.py b/modules/modules_builders.py index 2243162555..13d5a2075a 100644 --- a/modules/modules_builders.py +++ b/modules/modules_builders.py @@ -14,13 +14,10 @@ def generate_modules_enabled(target, source, env): def generate_modules_tests(target, source, env): import os - import glob with open(target[0].path, "w") as f: - for name, path in env.module_list.items(): - headers = glob.glob(os.path.join(path, "tests", "*.h")) - for h in headers: - f.write('#include "%s"\n' % (os.path.normpath(h))) + for header in source: + f.write('#include "%s"\n' % (os.path.normpath(header.path))) if __name__ == "__main__": diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 95c959235c..3bafa351a9 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -63,3 +63,4 @@ elif env["platform"] == "android": if env["tools"]: env_mono.add_source_files(env.modules_sources, "editor/*.cpp") + SConscript("editor/script_templates/SCsub") diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py index 93a66ebf6f..43c1ec8f8a 100644 --- a/modules/mono/build_scripts/mono_reg_utils.py +++ b/modules/mono/build_scripts/mono_reg_utils.py @@ -96,10 +96,10 @@ def find_msbuild_tools_path_reg(): raise ValueError("Cannot find `installationPath` entry") except ValueError as e: print("Error reading output from vswhere: " + e.message) - except OSError: - pass # Fine, vswhere not found - except (subprocess.CalledProcessError, OSError): - pass + except subprocess.CalledProcessError as e: + print(e.output) + except OSError as e: + print(e) # Try to find 14.0 in the Registry diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 0da06131af..9253f105bb 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -238,11 +238,10 @@ 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 + "'."); + Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'."); 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/class_db_api_json.h b/modules/mono/class_db_api_json.h index 6698a6260f..1d2000b033 100644 --- a/modules/mono/class_db_api_json.h +++ b/modules/mono/class_db_api_json.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 0ceb45d425..5875a0fbd4 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -45,16 +45,17 @@ #ifdef TOOLS_ENABLED #include "core/os/keyboard.h" #include "editor/bindings_generator.h" +#include "editor/editor_internal_calls.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/node_dock.h" +#include "editor/script_templates/templates.gen.h" #endif #ifdef DEBUG_METHODS_ENABLED #include "class_db_api_json.h" #endif -#include "editor/editor_internal_calls.h" #include "godotsharp_dirs.h" #include "mono_gd/gd_mono_cache.h" #include "mono_gd/gd_mono_class.h" @@ -351,57 +352,35 @@ static String get_base_class_name(const String &p_base_class_name, const String return base_class; } -Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - String script_template = "using " BINDINGS_NAMESPACE ";\n" - "using System;\n" - "\n" - "public partial class %CLASS% : %BASE%\n" - "{\n" - " // Declare member variables here. Examples:\n" - " // private int a = 2;\n" - " // private string b = \"text\";\n" - "\n" - " // Called when the node enters the scene tree for the first time.\n" - " public override void _Ready()\n" - " {\n" - " \n" - " }\n" - "\n" - "// // Called every frame. 'delta' is the elapsed time since the previous frame.\n" - "// public override void _Process(float delta)\n" - "// {\n" - "// \n" - "// }\n" - "}\n"; - - // Replaces all spaces in p_class_name with underscores to prevent - // 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); - script_template = script_template.replace("%BASE%", base_class_name) - .replace("%CLASS%", class_name_no_spaces); +bool CSharpLanguage::is_using_templates() { + return true; +} +Ref<Script> CSharpLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { Ref<CSharpScript> script; script.instantiate(); - script->set_source_code(script_template); - script->set_name(class_name_no_spaces); + 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); + String processed_template = p_template; + processed_template = processed_template.replace("_BINDINGS_NAMESPACE_", BINDINGS_NAMESPACE) + .replace("_BASE_", base_class_name) + .replace("_CLASS_", class_name_no_spaces) + .replace("_TS_", _get_indentation()); + script->set_source_code(processed_template); return script; } -bool CSharpLanguage::is_using_templates() { - return true; -} - -void CSharpLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { - String src = p_script->get_source_code(); - 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); - src = src.replace("%BASE%", base_class_name) - .replace("%CLASS%", class_name_no_spaces) - .replace("%TS%", _get_indentation()); - p_script->set_source_code(src); +Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(StringName p_object) { + Vector<ScriptLanguage::ScriptTemplate> templates; +#ifdef TOOLS_ENABLED + for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) { + if (TEMPLATES[i].inherit == p_object) { + templates.append(TEMPLATES[i]); + } + } +#endif + return templates; } String CSharpLanguage::validate_path(const String &p_path) const { @@ -409,7 +388,7 @@ String CSharpLanguage::validate_path(const String &p_path) const { List<String> keywords; get_reserved_words(&keywords); if (keywords.find(class_name)) { - return TTR("Class name can't be a reserved keyword"); + return RTR("Class name can't be a reserved keyword"); } return ""; } @@ -550,10 +529,10 @@ String CSharpLanguage::make_function(const String &, const String &, const Packe String CSharpLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", 0); + bool use_space_indentation = EDITOR_GET("text_editor/behavior/indent/type"); if (use_space_indentation) { - int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4); + int indent_size = EDITOR_GET("text_editor/behavior/indent/size"); String space_indent = ""; for (int i = 0; i < indent_size; i++) { @@ -945,7 +924,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { for (Ref<CSharpScript> &script : scripts) { while (script->instances.front()) { Object *obj = script->instances.front()->get(); - obj->set_script(REF()); // Remove script and existing script instances (placeholder are not removed before domain reload) + obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload) } script->_clear(); @@ -1191,8 +1170,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { #ifdef TOOLS_ENABLED // FIXME: Hack to refresh editor in order to display new properties and signals. See if there is a better alternative. if (Engine::get_singleton()->is_editor_hint()) { - EditorNode::get_singleton()->get_inspector()->update_tree(); - NodeDock::singleton->update_lists(); + InspectorDock::get_inspector_singleton()->update_tree(); + NodeDock::get_singleton()->update_lists(); } #endif } @@ -1762,7 +1741,16 @@ void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Va ManagedType managedType; - GDMonoField *field = script->script_class->get_field(state_pair.first); + GDMonoField *field = nullptr; + GDMonoClass *top = script->script_class; + while (top && top != script->native) { + field = top->get_field(state_pair.first); + if (field) { + break; + } + + top = top->get_parent_class(); + } if (!field) { continue; // Properties ignored. We get the property baking fields instead. } @@ -1907,7 +1895,7 @@ bool CSharpInstance::has_method(const StringName &p_method) const { return false; } -Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { ERR_FAIL_COND_V(!script.is_valid(), Variant()); GD_MONO_SCOPE_THREAD_ATTACH; @@ -2922,7 +2910,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage } #endif -Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (unlikely(GDMono::get_singleton() == nullptr)) { // Probably not the best error but eh. r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; @@ -2950,7 +2938,7 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i } // No static method found. Try regular instance calls - return Script::call(p_method, p_args, p_argcount, r_error); + return Script::callp(p_method, p_args, p_argcount, r_error); } void CSharpScript::_resource_path_changed() { @@ -3009,6 +2997,7 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon CRASH_COND(p_script->native == nullptr); p_script->valid = true; + p_script->reload_invalidated = false; update_script_class_info(p_script); @@ -3232,10 +3221,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native)); - REF ref; + Ref<RefCounted> ref; RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { - ref = REF(r); + ref = Ref<RefCounted>(r); } CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error); @@ -3258,6 +3247,8 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { CRASH_COND(!valid); #endif + GD_MONO_SCOPE_THREAD_ATTACH; + if (native) { StringName native_name = NATIVE_GDMONOCLASS_NAME(native); if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) { @@ -3270,8 +3261,6 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { } } - GD_MONO_SCOPE_THREAD_ATTACH; - Callable::CallError unchecked_error; return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error); } @@ -3365,13 +3354,13 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const { } Error CSharpScript::reload(bool p_keep_state) { - bool has_instances; - { - MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex); - has_instances = instances.size(); + if (!reload_invalidated) { + return OK; } - ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE); + // In the case of C#, reload doesn't really do any script reloading. + // That's done separately via domain reloading. + reload_invalidated = false; GD_MONO_SCOPE_THREAD_ATTACH; @@ -3558,6 +3547,7 @@ void CSharpScript::_update_name() { void CSharpScript::_clear() { tool = false; valid = false; + reload_invalidated = true; base = nullptr; native = nullptr; @@ -3596,7 +3586,7 @@ void CSharpScript::get_members(Set<StringName> *p_members) { /*************** RESOURCE ***************/ -RES ResourceFormatLoaderCSharpScript::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<Resource> ResourceFormatLoaderCSharpScript::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_FILE_CANT_OPEN; } @@ -3609,7 +3599,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p #if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED) Error err = script->load_source_code(p_path); - ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load C# script file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load C# script file '" + p_path + "'."); #endif script->set_path(p_original_path); @@ -3635,7 +3625,7 @@ String ResourceFormatLoaderCSharpScript::get_resource_type(const String &p_path) return p_path.get_extension().to_lower() == "cs" ? CSharpLanguage::get_singleton()->get_type() : ""; } -Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { +Error ResourceFormatSaverCSharpScript::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { Ref<CSharpScript> sqscr = p_resource; ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); @@ -3651,20 +3641,18 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r } #endif - Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'."); + { + Error err; + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'."); - file->store_string(source); + file->store_string(source); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); - return ERR_CANT_CREATE; + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } } - file->close(); - memdelete(file); - #ifdef TOOLS_ENABLED if (ScriptServer::is_reload_scripts_on_save_enabled()) { CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false); @@ -3674,13 +3662,13 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r return OK; } -void ResourceFormatSaverCSharpScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { +void ResourceFormatSaverCSharpScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const { if (Object::cast_to<CSharpScript>(p_resource.ptr())) { p_extensions->push_back("cs"); } } -bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const { +bool ResourceFormatSaverCSharpScript::recognize(const Ref<Resource> &p_resource) const { return Object::cast_to<CSharpScript>(p_resource.ptr()) != nullptr; } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index c998d9c1e4..41b54248a3 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -53,8 +53,9 @@ class CSharpLanguage; #ifdef NO_SAFE_CAST template <typename TScriptInstance, typename TScriptLanguage> TScriptInstance *cast_script_instance(ScriptInstance *p_inst) { - if (!p_inst) + if (!p_inst) { return nullptr; + } return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : nullptr; } #else @@ -101,8 +102,7 @@ private: bool tool = false; bool valid = false; - - bool builtin; + bool reload_invalidated = false; GDMonoClass *base = nullptr; GDMonoClass *native = nullptr; @@ -184,7 +184,7 @@ private: protected: static void _bind_methods(); - Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; + Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; void _resource_path_changed() override; bool _get(const StringName &p_name, Variant &r_ret) const; bool _set(const StringName &p_name, const Variant &p_value); @@ -202,9 +202,9 @@ public: void set_source_code(const String &p_code) override; #ifdef TOOLS_ENABLED - virtual const Vector<DocData::ClassDoc> &get_documentation() const override { + virtual Vector<DocData::ClassDoc> get_documentation() const override { // TODO - static Vector<DocData::ClassDoc> docs; + Vector<DocData::ClassDoc> docs; return docs; } #endif // TOOLS_ENABLED @@ -295,7 +295,7 @@ public: void get_method_list(List<MethodInfo> *p_list) const override; bool has_method(const StringName &p_method) const override; - Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; + Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; void mono_object_disposed(MonoObject *p_obj); @@ -463,9 +463,9 @@ public: 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; + virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; + virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) 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; @@ -534,7 +534,7 @@ public: class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader { public: - 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) override; + Ref<Resource> 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) override; void get_recognized_extensions(List<String> *p_extensions) const override; bool handles_type(const String &p_type) const override; String get_resource_type(const String &p_path) const override; @@ -542,9 +542,9 @@ public: class ResourceFormatSaverCSharpScript : public ResourceFormatSaver { public: - Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) override; - void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const override; - bool recognize(const RES &p_resource) const override; + Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0) override; + void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; + bool recognize(const Ref<Resource> &p_resource) const override; }; #endif // CSHARP_SCRIPT_H diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml index 14c62b4bb0..f8293fb107 100644 --- a/modules/mono/doc_classes/CSharpScript.xml +++ b/modules/mono/doc_classes/CSharpScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSharpScript" inherits="Script" version="4.0"> +<class name="CSharpScript" inherits="Script" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A script implemented in the C# programming language (Mono-enabled builds only). </brief_description> diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml index a148072245..9de6b48e9e 100644 --- a/modules/mono/doc_classes/GodotSharp.xml +++ b/modules/mono/doc_classes/GodotSharp.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GodotSharp" inherits="Object" version="4.0"> +<class name="GodotSharp" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Bridge between Godot and the Mono runtime (Mono-enabled builds only). </brief_description> diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs index ce2b378623..7a4641dbbc 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs @@ -47,9 +47,13 @@ namespace GodotTools.OpenVisualStudio if (dte == null) { // Open a new instance + dte = TryVisualStudioLaunch("VisualStudio.DTE.17.0"); - var visualStudioDteType = Type.GetTypeFromProgID("VisualStudio.DTE.16.0", throwOnError: true); - dte = (DTE)Activator.CreateInstance(visualStudioDteType); + if (dte == null) + { + // Launch of VS 2022 failed, fallback to 2019 + dte = TryVisualStudioLaunch("VisualStudio.DTE.16.0"); + } dte.UserControl = true; @@ -133,6 +137,21 @@ namespace GodotTools.OpenVisualStudio return 0; } + private static DTE TryVisualStudioLaunch(string version) + { + try + { + var visualStudioDteType = Type.GetTypeFromProgID(version, throwOnError: true); + var dte = (DTE)Activator.CreateInstance(visualStudioDteType); + + return dte; + } + catch (COMException) + { + return null; + } + } + private static DTE FindInstanceEditingSolution(string solutionPath) { if (GetRunningObjectTable(0, out IRunningObjectTable pprot) != 0) @@ -164,7 +183,7 @@ namespace GodotTools.OpenVisualStudio continue; // The digits after the colon are the process ID - if (!Regex.IsMatch(ppszDisplayName, "!VisualStudio.DTE.16.0:[0-9]")) + if (!Regex.IsMatch(ppszDisplayName, "!VisualStudio.DTE.1[6-7].0:[0-9]")) continue; if (pprot.GetObject(moniker[0], out object ppunkObject) == 0) diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index 56fca6b5cb..ebdaca0ce8 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -334,8 +334,13 @@ namespace GodotTools.Build } } - private void IssuesListRmbSelected(int index, Vector2 atPosition) + private void IssuesListClicked(int index, Vector2 atPosition, int mouseButtonIndex) { + if (mouseButtonIndex != (int)MouseButton.Right) + { + return; + } + _ = index; // Unused _issuesListContextMenu.Clear(); @@ -350,7 +355,7 @@ namespace GodotTools.Build if (_issuesListContextMenu.ItemCount > 0) { - _issuesListContextMenu.Position = (Vector2i)(_issuesList.RectGlobalPosition + atPosition); + _issuesListContextMenu.Position = (Vector2i)(_issuesList.GlobalPosition + atPosition); _issuesListContextMenu.Popup(); } } @@ -375,7 +380,7 @@ namespace GodotTools.Build }; _issuesList.ItemActivated += IssueActivated; _issuesList.AllowRmbSelect = true; - _issuesList.ItemRmbSelected += IssuesListRmbSelected; + _issuesList.ItemClicked += IssuesListClicked; hsc.AddChild(_issuesList); _issuesListContextMenu = new PopupMenu(); diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs index e9cf7911be..9e8f7ef1b1 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs @@ -126,7 +126,7 @@ namespace GodotTools.Build { base._Ready(); - RectMinSize = new Vector2(0, 228) * EditorScale; + MinimumSize = new Vector2(0, 228) * EditorScale; SizeFlagsVertical = (int)SizeFlags.ExpandFill; var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill }; @@ -147,7 +147,7 @@ namespace GodotTools.Build Icon = GetThemeIcon("StatusError", "EditorIcons"), ExpandIcon = false, ToggleMode = true, - Pressed = true, + ButtonPressed = true, FocusMode = FocusModeEnum.None }; _errorsBtn.Toggled += ErrorsToggled; @@ -159,7 +159,7 @@ namespace GodotTools.Build Icon = GetThemeIcon("NodeWarning", "EditorIcons"), ExpandIcon = false, ToggleMode = true, - Pressed = true, + ButtonPressed = true, FocusMode = FocusModeEnum.None }; _warningsBtn.Toggled += WarningsToggled; @@ -169,7 +169,7 @@ namespace GodotTools.Build { Text = "Show Output".TTR(), ToggleMode = true, - Pressed = true, + ButtonPressed = true, FocusMode = FocusModeEnum.None }; _viewLogBtn.Toggled += ViewLogToggled; diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 37e6a34977..e2f4d2f5fd 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -107,7 +107,7 @@ namespace GodotTools.Export ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir); // The Godot exporter expects us to pass the abi in the tags parameter - exporter.AddSharedObject(soFilePath, tags: new[] { abi }); + exporter.AddSharedObject(soFilePath, tags: new[] { abi }, ""); } } } @@ -134,7 +134,7 @@ namespace GodotTools.Export if (platform == OS.Platforms.MacOS) { - exporter.AddSharedObject(tempOutputFilePath, tags: null); + exporter.AddSharedObject(tempOutputFilePath, tags: null, ""); } else { @@ -537,7 +537,6 @@ MONO_AOT_MODE_LAST = 1000, { var iosArchs = new[] { - "armv7", "arm64" }; diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 98c6881166..69960bdbeb 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -428,7 +428,7 @@ namespace GodotTools Shortcut = buildSolutionShortcut, ShortcutInTooltip = true }; - _toolBarBuildButton.PressedSignal += BuildSolutionPressed; + _toolBarBuildButton.Pressed += BuildSolutionPressed; AddControlToContainer(CustomControlContainer.Toolbar, _toolBarBuildButton); if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath)) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 148a6796d2..54c65c21e8 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -100,6 +100,9 @@ #define BINDINGS_GENERATOR_VERSION UINT32_C(13) +// Types that will be ignored by the generator and won't be available in C#. +const Vector<String> ignored_types = { "PhysicsServer3DExtension" }; + const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n"); static String fix_doc_description(const String &p_bbcode) { @@ -278,11 +281,12 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } else if (code_tag) { xml_output.append("["); pos = brk_pos + 1; - } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) { - String link_target = tag.substr(tag.find(" ") + 1, tag.length()); - String link_tag = tag.substr(0, tag.find(" ")); + } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ")) { + const int tag_end = tag.find(" "); + const String link_tag = tag.substr(0, tag_end); + const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" "); - Vector<String> link_target_parts = link_target.split("."); + const Vector<String> link_target_parts = link_target.split("."); if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) { ERR_PRINT("Invalid reference format: '" + tag + "'."); @@ -310,175 +314,18 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } if (link_tag == "method") { - if (!target_itype || !target_itype->is_object_type) { - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); - } else { - const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname); - - if (target_imethod) { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); - xml_output.append(target_itype->proxy_name); - xml_output.append("."); - xml_output.append(target_imethod->proxy_name); - xml_output.append("\"/>"); - } - } + _append_xml_method(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "member") { - if (!target_itype || !target_itype->is_object_type) { - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); - } else { - const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname); - - if (target_iprop) { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); - xml_output.append(target_itype->proxy_name); - xml_output.append("."); - xml_output.append(target_iprop->proxy_name); - xml_output.append("\"/>"); - } - } + _append_xml_member(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "signal") { - // We do not declare signals in any way in C#, so there is nothing to reference - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); + _append_xml_signal(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "enum") { - StringName search_cname = !target_itype ? target_cname : StringName(target_itype->name + "." + (String)target_cname); - - const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname); - - if (!enum_match && search_cname != target_cname) { - enum_match = enum_types.find(target_cname); - } - - if (enum_match) { - const TypeInterface &target_enum_itype = enum_match->value(); - - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); - xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve enum reference in documentation: '" + link_target + "'."); - - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); - } + _append_xml_enum(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "constant") { - if (!target_itype || !target_itype->is_object_type) { - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); - } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) { - String target_name = (String)target_cname; - - // Try to find as a global constant - const ConstantInterface *target_iconst = find_constant_by_name(target_name, global_constants); - - if (target_iconst) { - // Found global constant - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS "."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - // Try to find as global enum constant - const EnumInterface *target_ienum = nullptr; - - for (const EnumInterface &ienum : global_enums) { - target_ienum = &ienum; - target_iconst = find_constant_by_name(target_name, target_ienum->constants); - if (target_iconst) { - break; - } - } - - if (target_iconst) { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); - xml_output.append(target_ienum->cname); - xml_output.append("."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve global constant reference in documentation: '" + link_target + "'."); - - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); - } - } - } else { - String target_name = (String)target_cname; - - // Try to find the constant in the current class - const ConstantInterface *target_iconst = find_constant_by_name(target_name, target_itype->constants); - - if (target_iconst) { - // Found constant in current class - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); - xml_output.append(target_itype->proxy_name); - xml_output.append("."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - // Try to find as enum constant in the current class - const EnumInterface *target_ienum = nullptr; - - for (const EnumInterface &ienum : target_itype->enums) { - target_ienum = &ienum; - target_iconst = find_constant_by_name(target_name, target_ienum->constants); - if (target_iconst) { - break; - } - } - - if (target_iconst) { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); - xml_output.append(target_itype->proxy_name); - xml_output.append("."); - xml_output.append(target_ienum->cname); - xml_output.append("."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve constant reference in documentation: '" + link_target + "'."); - - xml_output.append("<c>"); - xml_output.append(link_target); - xml_output.append("</c>"); - } - } - } + _append_xml_constant(xml_output, target_itype, target_cname, link_target, link_target_parts); + } else if (link_tag == "theme_item") { + // We do not declare theme_items in any way in C#, so there is nothing to reference + _append_xml_undeclared(xml_output, link_target); } pos = brk_end + 1; @@ -643,6 +490,240 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf return xml_output.as_string(); } +void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { + if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) { + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Cannot resolve @GlobalScope method reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else if (!p_target_itype || !p_target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + if (p_target_cname == "_init") { + // The _init method is not declared in C#, reference the constructor instead + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("()\"/>"); + } else { + const MethodInterface *target_imethod = p_target_itype->find_method_by_name(p_target_cname); + + if (target_imethod) { + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_imethod->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve method reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } + } +} + +void BindingsGenerator::_append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { + if (p_link_target.find("/") >= 0) { + // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference. + _append_xml_undeclared(p_xml_output, p_link_target); + } else if (!p_target_itype || !p_target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + const TypeInterface *current_itype = p_target_itype; + const PropertyInterface *target_iprop = nullptr; + + while (target_iprop == nullptr && current_itype != nullptr) { + target_iprop = current_itype->find_property_by_name(p_target_cname); + if (target_iprop == nullptr) { + current_itype = _get_type_or_null(TypeReference(current_itype->base_name)); + } + } + + if (target_iprop) { + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(current_itype->proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_iprop->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve member reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } +} + +void BindingsGenerator::_append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { + if (!p_target_itype || !p_target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve signal reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from signal reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + const SignalInterface *target_isignal = p_target_itype->find_signal_by_name(p_target_cname); + + if (target_isignal) { + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_isignal->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve signal reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } +} + +void BindingsGenerator::_append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { + const StringName search_cname = !p_target_itype ? p_target_cname : StringName(p_target_itype->name + "." + (String)p_target_cname); + + const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname); + + if (!enum_match && search_cname != p_target_cname) { + enum_match = enum_types.find(p_target_cname); + } + + if (enum_match) { + const TypeInterface &target_enum_itype = enum_match->value(); + + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve enum reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } +} + +void BindingsGenerator::_append_xml_constant(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { + if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) { + _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target); + } else if (!p_target_itype || !p_target_itype->is_object_type) { + // Search in @GlobalScope as a last resort if no class was specified + if (p_link_target_parts.size() == 1) { + _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target); + return; + } + + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + // Try to find the constant in the current class + const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, p_target_itype->constants); + + if (target_iconst) { + // Found constant in current class + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else { + // Try to find as enum constant in the current class + const EnumInterface *target_ienum = nullptr; + + for (const EnumInterface &ienum : p_target_itype->enums) { + target_ienum = &ienum; + target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants); + if (target_iconst) { + break; + } + } + + if (target_iconst) { + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_ienum->cname); + p_xml_output.append("."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else if (p_link_target_parts.size() == 1) { + // Also search in @GlobalScope as a last resort if no class was specified + _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target); + } else { + ERR_PRINT("Cannot resolve constant reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } + } +} + +void BindingsGenerator::_append_xml_constant_in_global_scope(StringBuilder &p_xml_output, const String &p_target_cname, const String &p_link_target) { + // Try to find as a global constant + const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, global_constants); + + if (target_iconst) { + // Found global constant + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS "."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else { + // Try to find as global enum constant + const EnumInterface *target_ienum = nullptr; + + for (const EnumInterface &ienum : global_enums) { + target_ienum = &ienum; + target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants); + if (target_iconst) { + break; + } + } + + if (target_iconst) { + p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + p_xml_output.append(target_ienum->cname); + p_xml_output.append("."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve global constant reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } +} + +void BindingsGenerator::_append_xml_undeclared(StringBuilder &p_xml_output, const String &p_link_target) { + p_xml_output.append("<c>"); + p_xml_output.append(p_link_target); + p_xml_output.append("</c>"); +} + int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { CRASH_COND(p_ienum.constants.is_empty()); @@ -690,11 +771,11 @@ void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumI continue; } - if (parts[curr_prefix_length][0] >= '0' && parts[curr_prefix_length][0] <= '9') { + if (is_digit(parts[curr_prefix_length][0])) { // The name of enum constants may begin with a numeric digit when strip from the enum prefix, // so we make the prefix for this constant one word shorter in those cases. for (curr_prefix_length = curr_prefix_length - 1; curr_prefix_length > 0; curr_prefix_length--) { - if (parts[curr_prefix_length][0] < '0' || parts[curr_prefix_length][0] > '9') { + if (!is_digit(parts[curr_prefix_length][0])) { break; } } @@ -721,10 +802,13 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type); - String im_sig = "IntPtr " CS_PARAM_METHODBIND ", "; - String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr,IntPtr"; + String im_sig = "IntPtr " CS_PARAM_METHODBIND; + String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr"; - im_sig += "IntPtr " CS_PARAM_INSTANCE; + if (!imethod.is_static) { + im_sig += ", IntPtr " CS_PARAM_INSTANCE; + im_unique_sig += ",IntPtr"; + } // Get arguments information int i = 0; @@ -951,8 +1035,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(p_proj_dir)) { Error err = da->make_dir_recursive(p_proj_dir); @@ -1086,8 +1170,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(p_proj_dir)) { Error err = da->make_dir_recursive(p_proj_dir); @@ -1196,8 +1280,8 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) { String output_dir = path::abspath(path::realpath(p_output_dir)); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(output_dir)) { Error err = da->make_dir_recursive(output_dir); @@ -1652,8 +1736,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf String arguments_sig; String cs_in_statements; - String icall_params = method_bind_field + ", "; - icall_params += sformat(p_itype.cs_in, "this"); + String icall_params = method_bind_field; + if (!p_imethod.is_static) { + icall_params += ", " + sformat(p_itype.cs_in, "this"); + } StringBuilder default_args_doc; @@ -1811,7 +1897,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output.append(MEMBER_BEGIN); p_output.append(p_imethod.is_internal ? "internal " : "public "); - if (p_itype.is_singleton) { + if (p_itype.is_singleton || p_imethod.is_static) { p_output.append("static "); } else if (p_imethod.is_virtual) { p_output.append("virtual "); @@ -2122,8 +2208,9 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { } output.append("#ifdef TOOLS_ENABLED\n"); - for (const InternalCall &internal_call : editor_custom_icalls) + for (const InternalCall &internal_call : editor_custom_icalls) { ADD_INTERNAL_CALL_REGISTRATION(internal_call); + } output.append("#endif // TOOLS_ENABLED\n"); for (const InternalCall &internal_call : method_icalls) { @@ -2168,12 +2255,10 @@ uint32_t BindingsGenerator::get_version() { } Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE); - - ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'."); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'."); file->store_string(p_content.as_string()); - file->close(); return OK; } @@ -2189,7 +2274,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte String argc_str = itos(p_imethod.arguments.size()); - String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE; + String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND; + if (!p_imethod.is_static) { + c_func_sig += ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE; + } String c_in_statements; String c_args_var_content; @@ -2281,17 +2369,21 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "nullptr" : return_type->c_type_out + "()"; - if (return_type->ret_as_byref_arg) { - p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = "); - p_output.append(fail_ret); - p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n"); - } else { - p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", "); - p_output.append(fail_ret); - p_output.append(");\n"); + if (!p_imethod.is_static) { + if (return_type->ret_as_byref_arg) { + p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = "); + p_output.append(fail_ret); + p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n"); + } else { + p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", "); + p_output.append(fail_ret); + p_output.append(");\n"); + } } } else { - p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n"); + if (!p_imethod.is_static) { + p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n"); + } } if (p_imethod.arguments.size()) { @@ -2335,7 +2427,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } } - p_output.append(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", "); + p_output.append(CS_PARAM_METHODBIND "->call("); + p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE); + p_output.append(", "); p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "nullptr"); p_output.append(", total_length, vcall_error);\n"); @@ -2346,7 +2440,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } } } else { - p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", "); + p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall("); + p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE); + p_output.append(", "); p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "nullptr, "); p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "nullptr);\n"); } @@ -2566,6 +2662,12 @@ bool BindingsGenerator::_populate_object_type_interfaces() { continue; } + if (ignored_types.has(type_cname)) { + _log("Ignoring type '%s' because it's in the list of ignored types\n", String(type_cname).utf8().get_data()); + class_list.pop_front(); + continue; + } + if (!ClassDB::is_class_exposed(type_cname)) { _log("Ignoring type '%s' because it's not exposed\n", String(type_cname).utf8().get_data()); class_list.pop_front(); @@ -2684,6 +2786,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() { imethod.name = method_info.name; imethod.cname = cname; + if (method_info.flags & METHOD_FLAG_STATIC) { + imethod.is_static = true; + } + if (method_info.flags & METHOD_FLAG_VIRTUAL) { imethod.is_virtual = true; } @@ -3096,7 +3202,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar if (transform == Transform2D()) { r_iarg.default_argument = "Transform2D.Identity"; } else { - r_iarg.default_argument = "new Transform2D(new Vector2" + transform.elements[0].operator String() + ", new Vector2" + transform.elements[1].operator String() + ", new Vector2" + transform.elements[2].operator String() + ")"; + r_iarg.default_argument = "new Transform2D(new Vector2" + transform.columns[0].operator String() + ", new Vector2" + transform.columns[1].operator String() + ", new Vector2" + transform.columns[2].operator String() + ")"; } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index a7879e96c8..dec4fae8cd 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -137,6 +137,11 @@ class BindingsGenerator { bool is_vararg = false; /** + * Determines if the method is static. + */ + bool is_static = false; + + /** * Virtual methods ("virtual" as defined by the Godot API) are methods that by default do nothing, * but can be overridden by the user to add custom functionality. * e.g.: _ready, _process, etc. @@ -366,6 +371,16 @@ class BindingsGenerator { return nullptr; } + const MethodInterface *find_method_by_proxy_name(const String &p_proxy_name) const { + for (const MethodInterface &E : methods) { + if (E.proxy_name == p_proxy_name) { + return &E; + } + } + + return nullptr; + } + const PropertyInterface *find_property_by_name(const StringName &p_cname) const { for (const PropertyInterface &E : properties) { if (E.cname == p_cname) { @@ -386,8 +401,18 @@ class BindingsGenerator { return nullptr; } - const MethodInterface *find_method_by_proxy_name(const String &p_proxy_name) const { - for (const MethodInterface &E : methods) { + const SignalInterface *find_signal_by_name(const StringName &p_cname) const { + for (const SignalInterface &E : signals_) { + if (E.cname == p_cname) { + return &E; + } + } + + return nullptr; + } + + const SignalInterface *find_signal_by_proxy_name(const String &p_proxy_name) const { + for (const SignalInterface &E : signals_) { if (E.proxy_name == p_proxy_name) { return &E; } @@ -638,6 +663,14 @@ class BindingsGenerator { String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype); + void _append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts); + void _append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts); + void _append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts); + void _append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts); + void _append_xml_constant(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts); + void _append_xml_constant_in_global_scope(StringBuilder &p_xml_output, const String &p_target_cname, const String &p_link_target); + void _append_xml_undeclared(StringBuilder &p_xml_output, const String &p_link_target); + int _determine_enum_prefix(const EnumInterface &p_ienum); void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length); diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index 61d0890288..79015686c3 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -120,7 +120,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr } break; case CompletionKind::NODE_PATHS: { { - // AutoLoads + // Autoloads. OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { @@ -144,7 +144,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr } } break; case CompletionKind::SCENE_PATHS: { - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); List<String> directories; directories.push_back(dir_access->get_current_dir()); diff --git a/modules/mono/editor/code_completion.h b/modules/mono/editor/code_completion.h index 7f7521672b..82b592003b 100644 --- a/modules/mono/editor/code_completion.h +++ b/modules/mono/editor/code_completion.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 9a61b63c12..f7f710f3f1 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,6 +34,7 @@ #include <unistd.h> // access #endif +#include "core/config/project_settings.h" #include "core/os/os.h" #include "core/version.h" #include "editor/debugger/editor_debugger_node.h" diff --git a/modules/mono/editor/editor_internal_calls.h b/modules/mono/editor/editor_internal_calls.h index 24080cd867..a899634d57 100644 --- a/modules/mono/editor/editor_internal_calls.h +++ b/modules/mono/editor/editor_internal_calls.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index 54dbaebf38..f9ea403334 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h index 0e9d689618..60620b5f4d 100644 --- a/modules/mono/editor/godotsharp_export.h +++ b/modules/mono/editor/godotsharp_export.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs new file mode 100644 index 0000000000..2ca81ab7cd --- /dev/null +++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs @@ -0,0 +1,41 @@ +// meta-description: Classic movement for gravity games (platformer, ...) + +using _BINDINGS_NAMESPACE_; +using System; + +public partial class _CLASS_ : _BASE_ +{ + public const float Speed = 300.0f; + public const float JumpVelocity = -400.0f; + + // Get the gravity from the project settings to be synced with RigidDynamicBody nodes. + public float gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity"); + + public override void _PhysicsProcess(float delta) + { + Vector2 velocity = Velocity; + + // Add the gravity. + if (!IsOnFloor()) + velocity.y += gravity * delta; + + // Handle Jump. + if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) + velocity.y = JumpVelocity; + + // Get the input direction and handle the movement/deceleration. + // As good practice, you should replace UI actions with custom gameplay actions. + Vector2 direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down"); + if (direction != Vector2.Zero) + { + velocity.x = direction.x * Speed; + } + else + { + velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed); + } + + Velocity = velocity; + MoveAndSlide(); + } +} diff --git a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs new file mode 100644 index 0000000000..a6935fe497 --- /dev/null +++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs @@ -0,0 +1,44 @@ +// meta-description: Classic movement for gravity games (FPS, TPS, ...) + +using _BINDINGS_NAMESPACE_; +using System; + +public partial class _CLASS_ : _BASE_ +{ + public const float Speed = 5.0f; + public const float JumpVelocity = 4.5f; + + // Get the gravity from the project settings to be synced with RigidDynamicBody nodes. + public float gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity"); + + public override void _PhysicsProcess(float delta) + { + Vector3 velocity = Velocity; + + // Add the gravity. + if (!IsOnFloor()) + velocity.y -= gravity * delta; + + // Handle Jump. + if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) + velocity.y = JumpVelocity; + + // Get the input direction and handle the movement/deceleration. + // As good practice, you should replace UI actions with custom gameplay actions. + Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down"); + Vector3 direction = Transform.basis.Xform(new Vector3(inputDir.x, 0, inputDir.y)).Normalized(); + if (direction != Vector3.Zero) + { + velocity.x = direction.x * Speed; + velocity.z = direction.z * Speed; + } + else + { + velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed); + velocity.z = Mathf.MoveToward(Velocity.z, 0, Speed); + } + + Velocity = velocity; + MoveAndSlide(); + } +} diff --git a/modules/mono/editor/script_templates/EditorPlugin/plugin.cs b/modules/mono/editor/script_templates/EditorPlugin/plugin.cs new file mode 100644 index 0000000000..eba5fd12a4 --- /dev/null +++ b/modules/mono/editor/script_templates/EditorPlugin/plugin.cs @@ -0,0 +1,20 @@ +// meta-description: Basic plugin template + +#if TOOLS +using _BINDINGS_NAMESPACE_; +using System; + +[Tool] +public partial class _CLASS_ : _BASE_ +{ + public override void _EnterTree() + { + // Initialization of the plugin goes here. + } + + public override void _ExitTree() + { + // Clean-up of the plugin goes here. + } +} +#endif diff --git a/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs b/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs new file mode 100644 index 0000000000..1b347edc1c --- /dev/null +++ b/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs @@ -0,0 +1,15 @@ +// meta-description: Basic editor script template + +#if TOOLS +using _BINDINGS_NAMESPACE_; +using System; + +[Tool] +public partial class _CLASS_ : _BASE_ +{ + // Called when the script is executed (using File -> Run in Script Editor). + public override void _Run() + { + } +} +#endif diff --git a/modules/mono/editor/script_templates/Node/default.cs b/modules/mono/editor/script_templates/Node/default.cs new file mode 100644 index 0000000000..4c86d1666f --- /dev/null +++ b/modules/mono/editor/script_templates/Node/default.cs @@ -0,0 +1,17 @@ +// meta-description: Base template for Node with default Godot cycle methods + +using _BINDINGS_NAMESPACE_; +using System; + +public partial class _CLASS_ : _BASE_ +{ + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + } + + // Called every frame. 'delta' is the elapsed time since the previous frame. + public override void _Process(float delta) + { + } +} diff --git a/modules/mono/editor/script_templates/Object/empty.cs b/modules/mono/editor/script_templates/Object/empty.cs new file mode 100644 index 0000000000..34526d514f --- /dev/null +++ b/modules/mono/editor/script_templates/Object/empty.cs @@ -0,0 +1,8 @@ +// meta-description: Empty template suitable for all Objects + +using _BINDINGS_NAMESPACE_; +using System; + +public partial class _CLASS_ : _BASE_ +{ +} diff --git a/modules/mono/editor/script_templates/SCsub b/modules/mono/editor/script_templates/SCsub new file mode 100644 index 0000000000..39f6cb5c01 --- /dev/null +++ b/modules/mono/editor/script_templates/SCsub @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +Import("env") + +import editor.template_builders as build_template_cs + +env["BUILDERS"]["MakeCSharpTemplateBuilder"] = Builder( + action=env.Run(build_template_cs.make_templates, "Generating C# templates header."), + suffix=".h", + src_suffix=".cs", +) + +# Template files +templates_sources = Glob("*/*.cs") + +env.Alias("editor_template_cs", [env.MakeCSharpTemplateBuilder("templates.gen.h", templates_sources)]) diff --git a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs new file mode 100644 index 0000000000..a1b93e7daa --- /dev/null +++ b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs @@ -0,0 +1,62 @@ +// meta-description: Visual shader's node plugin template + +using _BINDINGS_NAMESPACE_; +using System; + +public partial class VisualShaderNode_CLASS_ : _BASE_ +{ + public override string _GetName() + { + return "_CLASS_"; + } + + public override string _GetCategory() + { + return ""; + } + + public override string _GetDescription() + { + return ""; + } + + public override int _GetReturnIconType() + { + return 0; + } + + public override int _GetInputPortCount() + { + return 0; + } + + public override string _GetInputPortName(int port) + { + return ""; + } + + public override int _GetInputPortType(int port) + { + return 0; + } + + public override int _GetOutputPortCount() + { + return 1; + } + + public override string _GetOutputPortName(int port) + { + return "result"; + } + + public override int _GetOutputPortType(int port) + { + return 0; + } + + public override string _GetCode(Godot.Collections.Array inputVars, Godot.Collections.Array outputVars, Shader.Mode mode, VisualShader.Type type) + { + return ""; + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 656796c5c7..37bdc42c2d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -526,10 +526,10 @@ namespace Godot /// <summary> /// Introduce an additional rotation around the given <paramref name="axis"/> - /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector. + /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> - /// <param name="phi">The angle to rotate, in radians.</param> + /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated basis matrix.</returns> public Basis Rotated(Vector3 axis, real_t phi) { @@ -770,10 +770,10 @@ namespace Godot /// <summary> /// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/> - /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector. + /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> - /// <param name="phi">The angle to rotate, in radians.</param> + /// <param name="angle">The angle to rotate, in radians.</param> public Basis(Vector3 axis, real_t phi) { Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 75240b0c09..e80b6af68f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -320,6 +320,9 @@ namespace Godot.Collections internal static extern void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value); [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void godot_icall_Dictionary_KeyValuePairAt_Generic(IntPtr ptr, int index, out object key, out object value, int valueTypeEncoding, IntPtr valueTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -485,7 +488,7 @@ namespace Godot.Collections private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) { - Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value); + Dictionary.godot_icall_Dictionary_KeyValuePairAt_Generic(GetPtr(), index, out object key, out object value, valTypeEncoding, valTypeClass); return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index c664463e86..74aa38386f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -400,7 +400,7 @@ namespace Godot /// </summary> /// <param name="seed"> /// Seed to use to generate the random number. - /// If a different seed is used, its value will be modfied. + /// If a different seed is used, its value will be modified. /// </param> /// <returns>A random <see langword="uint"/> number.</returns> public static uint RandFromSeed(ref ulong seed) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index bfe9600084..ce213da6a7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -180,6 +180,24 @@ namespace Godot } /// <summary> + /// Cubic interpolates between two values by a normalized value with pre and post values. + /// </summary> + /// <param name="from">The start value for interpolation.</param> + /// <param name="to">The destination value for interpolation.</param> + /// <param name="pre">The value which before "from" value for interpolation.</param> + /// <param name="post">The value which after "to" value for interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <returns>The resulting value of the interpolation.</returns> + public static real_t CubicInterpolate(real_t from, real_t to, real_t pre, real_t post, real_t weight) + { + return 0.5f * + ((from * 2.0f) + + (-pre + to) * weight + + (2.0f * pre - 5.0f * from + 4.0f * to - post) * (weight * weight) + + (-pre + 3.0f * from - 3.0f * to + post) * (weight * weight * weight)); + } + + /// <summary> /// Converts an angle expressed in degrees to radians. /// </summary> /// <param name="deg">An angle expressed in degrees.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 68e6422c19..a1f058ffe5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -266,7 +266,7 @@ namespace Godot /// <returns>The capitalized string.</returns> public static string Capitalize(this string instance) { - string aux = instance.Replace("_", " ").ToLower(); + string aux = instance.CamelcaseToUnderscore(true).Replace("_", " ").Trim(); string cap = string.Empty; for (int i = 0; i < aux.GetSliceCount(" "); i++) @@ -284,6 +284,51 @@ namespace Godot return cap; } + private static string CamelcaseToUnderscore(this string instance, bool lowerCase) + { + string newString = string.Empty; + int startIndex = 0; + + for (int i = 1; i < instance.Length; i++) + { + bool isUpper = char.IsUpper(instance[i]); + bool isNumber = char.IsDigit(instance[i]); + + bool areNext2Lower = false; + bool isNextLower = false; + bool isNextNumber = false; + bool wasPrecedentUpper = char.IsUpper(instance[i - 1]); + bool wasPrecedentNumber = char.IsDigit(instance[i - 1]); + + if (i + 2 < instance.Length) + { + areNext2Lower = char.IsLower(instance[i + 1]) && char.IsLower(instance[i + 2]); + } + + if (i + 1 < instance.Length) + { + isNextLower = char.IsLower(instance[i + 1]); + isNextNumber = char.IsDigit(instance[i + 1]); + } + + bool condA = isUpper && !wasPrecedentUpper && !wasPrecedentNumber; + bool condB = wasPrecedentUpper && isUpper && areNext2Lower; + bool condC = isNumber && !wasPrecedentNumber; + bool canBreakNumberLetter = isNumber && !wasPrecedentNumber && isNextLower; + bool canBreakLetterNumber = !isNumber && wasPrecedentNumber && (isNextLower || isNextNumber); + + bool shouldSplit = condA || condB || condC || canBreakNumberLetter || canBreakLetterNumber; + if (shouldSplit) + { + newString += instance.Substring(startIndex, i - startIndex) + "_"; + startIndex = i; + } + } + + newString += instance.Substring(startIndex, instance.Length - startIndex); + return lowerCase ? newString.ToLower() : newString; + } + /// <summary> /// Performs a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. /// </summary> @@ -694,7 +739,7 @@ namespace Godot /// <summary> /// Returns <see langword="true"/> if the string is a path to a file or - /// directory and its startign point is explicitly defined. This includes + /// directory and its starting point is explicitly defined. This includes /// <c>res://</c>, <c>user://</c>, <c>C:\</c>, <c>/</c>, etc. /// </summary> /// <seealso cref="IsRelativePath(string)"/> @@ -727,7 +772,7 @@ namespace Godot /// <summary> /// Check whether this string is a subsequence of the given string. /// </summary> - /// <seealso cref="IsSubsequenceOfI(string, string)"/> + /// <seealso cref="IsSubsequenceOfN(string, string)"/> /// <param name="instance">The subsequence to search.</param> /// <param name="text">The string that contains the subsequence.</param> /// <param name="caseSensitive">If <see langword="true"/>, the check is case sensitive.</param> @@ -779,7 +824,7 @@ namespace Godot /// <param name="instance">The subsequence to search.</param> /// <param name="text">The string that contains the subsequence.</param> /// <returns>If the string is a subsequence of the given string.</returns> - public static bool IsSubsequenceOfI(this string instance, string text) + public static bool IsSubsequenceOfN(this string instance, string text) { return instance.IsSubsequenceOf(text, caseSensitive: false); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 8e253388bf..89947899cb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -297,9 +297,9 @@ namespace Godot } /// <summary> - /// Rotates the transform by <paramref name="phi"/> (in radians), using matrix multiplication. + /// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication. /// </summary> - /// <param name="phi">The angle to rotate, in radians.</param> + /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> public Transform2D Rotated(real_t phi) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 5d9aabdd2f..7b211b6577 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -186,11 +186,11 @@ namespace Godot } /// <summary> - /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="phi"/> (in radians), + /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians), /// using matrix multiplication. The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> - /// <param name="phi">The angle to rotate, in radians.</param> + /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> public Transform3D Rotated(Vector3 axis, real_t phi) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 1f5282e88f..9e990ce83e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -81,6 +81,15 @@ namespace Godot } } + /// <summary> + /// Helper method for deconstruction into a tuple. + /// </summary> + public void Deconstruct(out real_t x, out real_t y) + { + x = this.x; + y = this.y; + } + internal void Normalize() { real_t lengthsq = LengthSquared(); @@ -204,20 +213,10 @@ namespace Godot /// <returns>The interpolated vector.</returns> public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight) { - Vector2 p0 = preA; - Vector2 p1 = this; - Vector2 p2 = b; - Vector2 p3 = postB; - - real_t t = weight; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return 0.5f * ( - (p1 * 2.0f) + - ((-p0 + p2) * t) + - (((2.0f * p0) - (5.0f * p1) + (4 * p2) - p3) * t2) + - ((-p0 + (3.0f * p1) - (3.0f * p2) + p3) * t3) + return new Vector2 + ( + Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight), + Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight) ); } @@ -471,9 +470,9 @@ namespace Godot } /// <summary> - /// Rotates this vector by <paramref name="phi"/> radians. + /// Rotates this vector by <paramref name="angle"/> radians. /// </summary> - /// <param name="phi">The angle to rotate by, in radians.</param> + /// <param name="angle">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> public Vector2 Rotated(real_t phi) { @@ -512,24 +511,25 @@ namespace Godot /// Returns the result of the spherical linear interpolation between /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. /// - /// Note: Both vectors must be normalized. + /// This method also handles interpolating the lengths if the input vectors + /// have different lengths. For the special case of one or both input vectors + /// having zero length, this method behaves like <see cref="Lerp"/>. /// </summary> - /// <param name="to">The destination vector for interpolation. Must be normalized.</param> + /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> public Vector2 Slerp(Vector2 to, real_t weight) { -#if DEBUG - if (!IsNormalized()) - { - throw new InvalidOperationException("Vector2.Slerp: From vector is not normalized."); + real_t startLengthSquared = LengthSquared(); + real_t endLengthSquared = to.LengthSquared(); + if (startLengthSquared == 0.0 || endLengthSquared == 0.0) { + // Zero length vectors have no angle, so the best we can do is either lerp or throw an error. + return Lerp(to, weight); } - if (!to.IsNormalized()) - { - throw new InvalidOperationException($"Vector2.Slerp: `{nameof(to)}` is not normalized."); - } -#endif - return Rotated(AngleTo(to) * weight); + real_t startLength = Mathf.Sqrt(startLengthSquared); + real_t resultLength = Mathf.Lerp(startLength, Mathf.Sqrt(endLengthSquared), weight); + real_t angle = AngleTo(to); + return Rotated(angle * weight) * (resultLength / startLength); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index 9b51de5c8c..412a885daa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -82,6 +82,15 @@ namespace Godot } /// <summary> + /// Helper method for deconstruction into a tuple. + /// </summary> + public void Deconstruct(out int x, out int y) + { + x = this.x; + y = this.y; + } + + /// <summary> /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 433a5d9dc9..56859da7f2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -96,6 +96,16 @@ namespace Godot } } + /// <summary> + /// Helper method for deconstruction into a tuple. + /// </summary> + public void Deconstruct(out real_t x, out real_t y, out real_t z) + { + x = this.x; + y = this.y; + z = this.z; + } + internal void Normalize() { real_t lengthsq = LengthSquared(); @@ -195,19 +205,11 @@ namespace Godot /// <returns>The interpolated vector.</returns> public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight) { - Vector3 p0 = preA; - Vector3 p1 = this; - Vector3 p2 = b; - Vector3 p3 = postB; - - real_t t = weight; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return 0.5f * ( - (p1 * 2.0f) + ((-p0 + p2) * t) + - (((2.0f * p0) - (5.0f * p1) + (4f * p2) - p3) * t2) + - ((-p0 + (3.0f * p1) - (3.0f * p2) + p3) * t3) + return new Vector3 + ( + Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight), + Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight), + Mathf.CubicInterpolate(z, b.z, preA.z, postB.z, weight) ); } @@ -486,11 +488,11 @@ namespace Godot } /// <summary> - /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="phi"/> radians. + /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="angle"/> (in radians). /// The <paramref name="axis"/> vector must be a normalized vector. /// </summary> /// <param name="axis">The vector to rotate around. Must be normalized.</param> - /// <param name="phi">The angle to rotate by, in radians.</param> + /// <param name="angle">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> public Vector3 Rotated(Vector3 axis, real_t phi) { @@ -549,25 +551,25 @@ namespace Godot /// Returns the result of the spherical linear interpolation between /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. /// - /// Note: Both vectors must be normalized. + /// This method also handles interpolating the lengths if the input vectors + /// have different lengths. For the special case of one or both input vectors + /// having zero length, this method behaves like <see cref="Lerp"/>. /// </summary> - /// <param name="to">The destination vector for interpolation. Must be normalized.</param> + /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> public Vector3 Slerp(Vector3 to, real_t weight) { -#if DEBUG - if (!IsNormalized()) - { - throw new InvalidOperationException("Vector3.Slerp: From vector is not normalized."); + real_t startLengthSquared = LengthSquared(); + real_t endLengthSquared = to.LengthSquared(); + if (startLengthSquared == 0.0 || endLengthSquared == 0.0) { + // Zero length vectors have no angle, so the best we can do is either lerp or throw an error. + return Lerp(to, weight); } - if (!to.IsNormalized()) - { - throw new InvalidOperationException($"Vector3.Slerp: `{nameof(to)}` is not normalized."); - } -#endif - real_t theta = AngleTo(to); - return Rotated(Cross(to), theta * weight); + real_t startLength = Mathf.Sqrt(startLengthSquared); + real_t resultLength = Mathf.Lerp(startLength, Mathf.Sqrt(endLengthSquared), weight); + real_t angle = AngleTo(to); + return Rotated(Cross(to).Normalized(), angle * weight) * (resultLength / startLength); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index eb06d2b87e..abfd2ae720 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -97,6 +97,16 @@ namespace Godot } /// <summary> + /// Helper method for deconstruction into a tuple. + /// </summary> + public void Deconstruct(out int x, out int y, out int z) + { + x = this.x; + y = this.y; + z = this.z; + } + + /// <summary> /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns> diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h index 9ba6a05ac6..4405809887 100644 --- a/modules/mono/glue/arguments_vector.h +++ b/modules/mono/glue/arguments_vector.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,7 +37,7 @@ template <typename T, int POOL_SIZE = 5> struct ArgumentsVector { private: T pool[POOL_SIZE]; - T *_ptr; + T *_ptr = nullptr; int size; ArgumentsVector() = delete; diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 6c5503a3bd..b10d78c593 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -148,7 +148,7 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) { RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); if (rc) { - REF r = rc; + Ref<RefCounted> r = rc; if (!r.is_valid()) { return nullptr; } @@ -199,7 +199,7 @@ MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoStrin } Callable::CallError error; - Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error); + Variant result = p_ptr->callp(StringName(name), args.ptr(), argc, error); *r_result = GDMonoMarshal::variant_to_mono_object(result); diff --git a/modules/mono/glue/callable_glue.cpp b/modules/mono/glue/callable_glue.cpp index 54b65fdb94..e59b34313c 100644 --- a/modules/mono/glue/callable_glue.cpp +++ b/modules/mono/glue/callable_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index e367ecb7d6..8a9f30459c 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -237,10 +237,14 @@ int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Arra } void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) { - Array *keys = godot_icall_Dictionary_Keys(ptr); - Array *values = godot_icall_Dictionary_Values(ptr); - *key = GDMonoMarshal::variant_to_mono_object(keys->get(index)); - *value = GDMonoMarshal::variant_to_mono_object(values->get(index)); + *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index)); + *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index)); +} + +void godot_icall_Dictionary_KeyValuePairAt_Generic(Dictionary *ptr, int index, MonoObject **key, MonoObject **value, uint32_t value_type_encoding, GDMonoClass *value_type_class) { + ManagedType type(value_type_encoding, value_type_class); + *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index)); + *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index), type); } void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { @@ -353,6 +357,7 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt_Generic", godot_icall_Dictionary_KeyValuePairAt_Generic); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains); diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp index 07ddf5d945..8aead217cf 100644 --- a/modules/mono/glue/gd_glue.cpp +++ b/modules/mono/glue/gd_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 074220bb9b..9638b23410 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp index 4ddb94e1a8..0ea9814b1a 100644 --- a/modules/mono/glue/nodepath_glue.cpp +++ b/modules/mono/glue/nodepath_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp index f464e63a81..3e09564539 100644 --- a/modules/mono/glue/rid_glue.cpp +++ b/modules/mono/glue/rid_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp index 5a6fd69db8..c60e7c4869 100644 --- a/modules/mono/glue/scene_tree_glue.cpp +++ b/modules/mono/glue/scene_tree_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp index bb80a836ad..fc6b13ceb3 100644 --- a/modules/mono/glue/string_glue.cpp +++ b/modules/mono/glue/string_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp index f537896559..46d15316ba 100644 --- a/modules/mono/glue/string_name_glue.cpp +++ b/modules/mono/glue/string_name_glue.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h index 273dba52f9..e5f1abe8d7 100644 --- a/modules/mono/godotsharp_defs.h +++ b/modules/mono/godotsharp_defs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 2b4cc7fcc3..cb2b60fcce 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,7 +36,7 @@ #ifdef TOOLS_ENABLED #include "core/version.h" -#include "editor/editor_settings.h" +#include "editor/editor_paths.h" #endif #ifdef ANDROID_ENABLED @@ -68,8 +68,15 @@ String _get_mono_user_dir() { } else { String settings_path; + // Self-contained mode if a `._sc_` or `_sc_` file is present in executable dir. String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir(); - DirAccessRef d = DirAccess::create_for_path(exe_dir); + + // On macOS, look outside .app bundle, since .app bundle is read-only. + if (OS::get_singleton()->has_feature("macos") && exe_dir.ends_with("MacOS") && exe_dir.plus_file("..").simplify_path().ends_with("Contents")) { + exe_dir = exe_dir.plus_file("../../..").simplify_path(); + } + + Ref<DirAccess> d = DirAccess::create_for_path(exe_dir); if (d->file_exists("._sc_") || d->file_exists("_sc_")) { // contain yourself diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h index 3a3c6f980e..da25e0778f 100644 --- a/modules/mono/godotsharp_dirs.h +++ b/modules/mono/godotsharp_dirs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp index 6d868b527c..8ed21c323f 100644 --- a/modules/mono/managed_callable.cpp +++ b/modules/mono/managed_callable.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h index c620eee60d..d50a8a7b08 100644 --- a/modules/mono/managed_callable.h +++ b/modules/mono/managed_callable.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -43,7 +43,7 @@ class ManagedCallable : public CallableCustom { friend class CSharpLanguage; MonoGCHandleData delegate_handle; - GDMonoMethod *delegate_invoke; + GDMonoMethod *delegate_invoke = nullptr; #ifdef GD_MONO_HOT_RELOAD SelfList<ManagedCallable> self_instance = this; diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp index 8583065016..f3dafa6ecf 100644 --- a/modules/mono/mono_gc_handle.cpp +++ b/modules/mono/mono_gc_handle.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h index a18a4ce646..ab9e508c99 100644 --- a/modules/mono/mono_gc_handle.h +++ b/modules/mono/mono_gc_handle.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/android_mono_config.h b/modules/mono/mono_gd/android_mono_config.h index 9d7cfe1b7c..9ee4bcf590 100644 --- a/modules/mono/mono_gd/android_mono_config.h +++ b/modules/mono/mono_gd/android_mono_config.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 52447bc59b..e98ce8f6c1 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -52,10 +52,6 @@ #include "gd_mono_marshal.h" #include "gd_mono_utils.h" -#ifdef TOOLS_ENABLED -#include "main/main.h" -#endif - #ifdef ANDROID_ENABLED #include "android_mono_config.h" #include "support/android_support.h" @@ -143,7 +139,7 @@ void gd_mono_debug_init() { if (Engine::get_singleton()->is_editor_hint() || ProjectSettings::get_singleton()->get_resource_path().is_empty() || - Main::is_project_manager()) { + Engine::get_singleton()->is_project_manager_hint()) { if (da_args.size() == 0) { return; } @@ -155,8 +151,9 @@ void gd_mono_debug_init() { .utf8(); } #else - if (da_args.length() == 0) + if (da_args.length() == 0) { return; // Exported games don't use the project settings to setup the debugger agent + } #endif // Debugging enabled @@ -230,8 +227,9 @@ void GDMono::add_mono_shared_libs_dir_to_path() { path_value += mono_reg_info.bin_dir; } #else - if (DirAccess::exists(bundled_bin_dir)) + if (DirAccess::exists(bundled_bin_dir)) { path_value += bundled_bin_dir; + } #endif // TOOLS_ENABLED #else @@ -423,7 +421,7 @@ void GDMono::initialize_load_assemblies() { bool tool_assemblies_loaded = _load_tools_assemblies(); CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies."); - if (Main::is_project_manager()) { + if (Engine::get_singleton()->is_project_manager_hint()) { return; } #endif @@ -645,9 +643,8 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const // Create destination directory if needed if (!DirAccess::exists(dst_dir)) { - DirAccess *da = DirAccess::create_for_path(dst_dir); + Ref<DirAccess> da = DirAccess::create_for_path(dst_dir); Error err = da->make_dir_recursive(dst_dir); - memdelete(da); if (err != OK) { ERR_PRINT("Failed to create destination directory for the API assemblies. Error: " + itos(err) + "."); @@ -655,7 +652,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const } } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String xml_file = assembly_name + ".xml"; if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) { @@ -815,7 +812,7 @@ bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, c // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date // If running the project manager, load it from the prebuilt API directory - String assembly_dir = !Main::is_project_manager() + String assembly_dir = !Engine::get_singleton()->is_project_manager_hint() ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config); @@ -848,7 +845,7 @@ bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date // If running the project manager, load it from the prebuilt API directory - String assembly_dir = !Main::is_project_manager() + String assembly_dir = !Engine::get_singleton()->is_project_manager_hint() ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config); @@ -932,7 +929,7 @@ void GDMono::_load_api_assemblies() { // this time update them from the prebuilt assemblies directory before trying to load them again. // Shouldn't happen. The project manager loads the prebuilt API assemblies - CRASH_COND_MSG(Main::is_project_manager(), "Failed to load one of the prebuilt API assemblies."); + CRASH_COND_MSG(Engine::get_singleton()->is_project_manager_hint(), "Failed to load one of the prebuilt API assemblies."); // 1. Unload the scripts domain Error domain_unload_err = _unload_scripts_domain(); @@ -1273,8 +1270,9 @@ GDMono::~GDMono() { print_verbose("Mono: Finalizing scripts domain..."); - if (mono_domain_get() != root_domain) + if (mono_domain_get() != root_domain) { mono_domain_set(root_domain, true); + } finalizing_scripts_domain = true; diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index a18fa6c6b4..51fd0f8483 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -94,16 +94,16 @@ private: UnhandledExceptionPolicy unhandled_exception_policy; - MonoDomain *root_domain; - MonoDomain *scripts_domain; + MonoDomain *root_domain = nullptr; + MonoDomain *scripts_domain = nullptr; HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies; - GDMonoAssembly *corlib_assembly; - GDMonoAssembly *project_assembly; + GDMonoAssembly *corlib_assembly = nullptr; + GDMonoAssembly *project_assembly = nullptr; #ifdef TOOLS_ENABLED - GDMonoAssembly *tools_assembly; - GDMonoAssembly *tools_project_editor_assembly; + GDMonoAssembly *tools_assembly = nullptr; + GDMonoAssembly *tools_project_editor_assembly = nullptr; #endif LoadedApiAssembly core_api_assembly; @@ -150,7 +150,7 @@ private: void _init_godot_api_hashes(); void _init_exception_policy(); - GDMonoLog *gdmono_log; + GDMonoLog *gdmono_log = nullptr; #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) MonoRegInfo mono_reg_info; @@ -250,7 +250,7 @@ public: namespace gdmono { class ScopeDomain { - MonoDomain *prev_domain; + MonoDomain *prev_domain = nullptr; public: ScopeDomain(MonoDomain *p_domain) { @@ -270,7 +270,7 @@ public: }; class ScopeExitDomainUnload { - MonoDomain *domain; + MonoDomain *domain = nullptr; public: ScopeExitDomainUnload(MonoDomain *p_domain) : diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 67f38bf127..3991b14612 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 6191c491f4..a96357b082 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -68,8 +68,8 @@ class GDMonoAssembly { }; String name; - MonoImage *image; - MonoAssembly *assembly; + MonoImage *image = nullptr; + MonoAssembly *assembly = nullptr; bool attrs_fetched = false; MonoCustomAttrInfo *attributes = nullptr; diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index 60277e0652..d8fd244067 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 5101907bd6..4000342c94 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -41,91 +41,91 @@ struct CachedData { // corlib classes // Let's use the no-namespace format for these too - GDMonoClass *class_MonoObject; // object - GDMonoClass *class_bool; // bool - GDMonoClass *class_int8_t; // sbyte - GDMonoClass *class_int16_t; // short - GDMonoClass *class_int32_t; // int - GDMonoClass *class_int64_t; // long - GDMonoClass *class_uint8_t; // byte - GDMonoClass *class_uint16_t; // ushort - GDMonoClass *class_uint32_t; // uint - GDMonoClass *class_uint64_t; // ulong - GDMonoClass *class_float; // float - GDMonoClass *class_double; // double - GDMonoClass *class_String; // string - GDMonoClass *class_IntPtr; // System.IntPtr - - GDMonoClass *class_System_Collections_IEnumerable; - GDMonoClass *class_System_Collections_ICollection; - GDMonoClass *class_System_Collections_IDictionary; + GDMonoClass *class_MonoObject = nullptr; // object + GDMonoClass *class_bool = nullptr; // bool + GDMonoClass *class_int8_t = nullptr; // sbyte + GDMonoClass *class_int16_t = nullptr; // short + GDMonoClass *class_int32_t = nullptr; // int + GDMonoClass *class_int64_t = nullptr; // long + GDMonoClass *class_uint8_t = nullptr; // byte + GDMonoClass *class_uint16_t = nullptr; // ushort + GDMonoClass *class_uint32_t = nullptr; // uint + GDMonoClass *class_uint64_t = nullptr; // ulong + GDMonoClass *class_float = nullptr; // float + GDMonoClass *class_double = nullptr; // double + GDMonoClass *class_String = nullptr; // string + GDMonoClass *class_IntPtr = nullptr; // System.IntPtr + + GDMonoClass *class_System_Collections_IEnumerable = nullptr; + GDMonoClass *class_System_Collections_ICollection = nullptr; + GDMonoClass *class_System_Collections_IDictionary = nullptr; #ifdef DEBUG_ENABLED - GDMonoClass *class_System_Diagnostics_StackTrace; + GDMonoClass *class_System_Diagnostics_StackTrace = nullptr; GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr; #endif - GDMonoClass *class_KeyNotFoundException; + GDMonoClass *class_KeyNotFoundException = nullptr; - MonoClass *rawclass_Dictionary; + MonoClass *rawclass_Dictionary = nullptr; // ----------------------------------------------- - GDMonoClass *class_Vector2; - GDMonoClass *class_Vector2i; - GDMonoClass *class_Rect2; - GDMonoClass *class_Rect2i; - GDMonoClass *class_Transform2D; - GDMonoClass *class_Vector3; - GDMonoClass *class_Vector3i; - GDMonoClass *class_Basis; - GDMonoClass *class_Quaternion; - GDMonoClass *class_Transform3D; - GDMonoClass *class_AABB; - GDMonoClass *class_Color; - GDMonoClass *class_Plane; - GDMonoClass *class_StringName; - GDMonoClass *class_NodePath; - GDMonoClass *class_RID; - GDMonoClass *class_GodotObject; - GDMonoClass *class_GodotResource; - GDMonoClass *class_Node; - GDMonoClass *class_Control; - GDMonoClass *class_Node3D; - GDMonoClass *class_WeakRef; - GDMonoClass *class_Callable; - GDMonoClass *class_SignalInfo; - GDMonoClass *class_Array; - GDMonoClass *class_Dictionary; - GDMonoClass *class_MarshalUtils; - GDMonoClass *class_ISerializationListener; + GDMonoClass *class_Vector2 = nullptr; + GDMonoClass *class_Vector2i = nullptr; + GDMonoClass *class_Rect2 = nullptr; + GDMonoClass *class_Rect2i = nullptr; + GDMonoClass *class_Transform2D = nullptr; + GDMonoClass *class_Vector3 = nullptr; + GDMonoClass *class_Vector3i = nullptr; + GDMonoClass *class_Basis = nullptr; + GDMonoClass *class_Quaternion = nullptr; + GDMonoClass *class_Transform3D = nullptr; + GDMonoClass *class_AABB = nullptr; + GDMonoClass *class_Color = nullptr; + GDMonoClass *class_Plane = nullptr; + GDMonoClass *class_StringName = nullptr; + GDMonoClass *class_NodePath = nullptr; + GDMonoClass *class_RID = nullptr; + GDMonoClass *class_GodotObject = nullptr; + GDMonoClass *class_GodotResource = nullptr; + GDMonoClass *class_Node = nullptr; + GDMonoClass *class_Control = nullptr; + GDMonoClass *class_Node3D = nullptr; + GDMonoClass *class_WeakRef = nullptr; + GDMonoClass *class_Callable = nullptr; + GDMonoClass *class_SignalInfo = nullptr; + GDMonoClass *class_Array = nullptr; + GDMonoClass *class_Dictionary = nullptr; + GDMonoClass *class_MarshalUtils = nullptr; + GDMonoClass *class_ISerializationListener = nullptr; #ifdef DEBUG_ENABLED - GDMonoClass *class_DebuggingUtils; + GDMonoClass *class_DebuggingUtils = nullptr; GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo; #endif - GDMonoClass *class_ExportAttribute; - GDMonoField *field_ExportAttribute_hint; - GDMonoField *field_ExportAttribute_hintString; - GDMonoClass *class_SignalAttribute; - GDMonoClass *class_ToolAttribute; - GDMonoClass *class_AnyPeerAttribute; - GDMonoClass *class_AuthorityAttribute; - GDMonoClass *class_GodotMethodAttribute; - GDMonoField *field_GodotMethodAttribute_methodName; - GDMonoClass *class_ScriptPathAttribute; - GDMonoField *field_ScriptPathAttribute_path; - GDMonoClass *class_AssemblyHasScriptsAttribute; - GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup; - GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes; - - GDMonoField *field_GodotObject_ptr; - GDMonoField *field_StringName_ptr; - GDMonoField *field_NodePath_ptr; - GDMonoField *field_Image_ptr; - GDMonoField *field_RID_ptr; + GDMonoClass *class_ExportAttribute = nullptr; + GDMonoField *field_ExportAttribute_hint = nullptr; + GDMonoField *field_ExportAttribute_hintString = nullptr; + GDMonoClass *class_SignalAttribute = nullptr; + GDMonoClass *class_ToolAttribute = nullptr; + GDMonoClass *class_AnyPeerAttribute = nullptr; + GDMonoClass *class_AuthorityAttribute = nullptr; + GDMonoClass *class_GodotMethodAttribute = nullptr; + GDMonoField *field_GodotMethodAttribute_methodName = nullptr; + GDMonoClass *class_ScriptPathAttribute = nullptr; + GDMonoField *field_ScriptPathAttribute_path = nullptr; + GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr; + GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr; + GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr; + + GDMonoField *field_GodotObject_ptr = nullptr; + GDMonoField *field_StringName_ptr = nullptr; + GDMonoField *field_NodePath_ptr = nullptr; + GDMonoField *field_Image_ptr = nullptr; + GDMonoField *field_RID_ptr = nullptr; GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose; GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 520568071e..3fc0f16e05 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -194,7 +194,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base #ifdef DEBUG_ENABLED // For debug builds, we also fetched from native base classes as well before if this is not a native base class. - // This allows us to warn the user here if he is using snake_case by mistake. + // This allows us to warn the user here if they are using snake_case by mistake. if (p_native_base != this) { GDMonoClass *native_top = p_native_base; diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index daea75bae8..b32d561f61 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -70,11 +70,11 @@ class GDMonoClass { StringName namespace_name; StringName class_name; - MonoClass *mono_class; - GDMonoAssembly *assembly; + MonoClass *mono_class = nullptr; + GDMonoAssembly *assembly = nullptr; bool attrs_fetched; - MonoCustomAttrInfo *attributes; + MonoCustomAttrInfo *attributes = nullptr; // This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions. // Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming. diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 111eaa0bbf..333a06c94a 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h index ed5078c673..87ef245f3f 100644 --- a/modules/mono/mono_gd/gd_mono_field.h +++ b/modules/mono/mono_gd/gd_mono_field.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,14 +36,14 @@ #include "i_mono_class_member.h" class GDMonoField : public IMonoClassMember { - GDMonoClass *owner; - MonoClassField *mono_field; + GDMonoClass *owner = nullptr; + MonoClassField *mono_field = nullptr; StringName name; ManagedType type; bool attrs_fetched; - MonoCustomAttrInfo *attributes; + MonoCustomAttrInfo *attributes = nullptr; public: virtual GDMonoClass *get_enclosing_class() const final { return owner; } diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index 483030610f..bf21283080 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index cf76c23926..d206b0dfc3 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h index 26eb270eee..a8f9cfa3ca 100644 --- a/modules/mono/mono_gd/gd_mono_internals.h +++ b/modules/mono/mono_gd/gd_mono_internals.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index bcdcd6623b..6ea3c5539e 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -77,23 +77,20 @@ static String make_text(const char *log_domain, const char *log_level, const cha } void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) { - FileAccess *f = GDMonoLog::get_singleton()->log_file; - if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) { String text = make_text(log_domain, log_level, message); text += "\n"; - f->seek_end(); - f->store_string(text); + GDMonoLog::get_singleton()->log_file->seek_end(); + GDMonoLog::get_singleton()->log_file->store_string(text); } if (fatal) { String text = make_text(log_domain, log_level, message); ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'."); // Make sure to flush before aborting - f->flush(); - f->close(); - memdelete(f); + GDMonoLog::get_singleton()->log_file->flush(); + GDMonoLog::get_singleton()->log_file.unref(); abort(); } @@ -101,8 +98,8 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { if (!DirAccess::exists(p_logs_dir)) { - DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!diraccess, false); + Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(diraccess.is_null(), false); Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir); ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory."); } @@ -113,8 +110,8 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { static const uint64_t MAX_SECS = 5 * 86400; // 5 days - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND(!da); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND(da.is_null()); Error err = da->change_dir(p_logs_dir); ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'."); @@ -170,7 +167,7 @@ void GDMonoLog::initialize() { log_file_path = logs_dir.plus_file(log_file_name); log_file = FileAccess::open(log_file_path, FileAccess::WRITE); - if (!log_file) { + if (log_file.is_null()) { ERR_PRINT("Mono: Cannot create log file at: " + log_file_path); } } @@ -178,7 +175,7 @@ void GDMonoLog::initialize() { mono_trace_set_level_string(log_level.get_data()); log_level_id = get_log_level_id(log_level.get_data()); - if (log_file) { + if (log_file.is_valid()) { OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data()); mono_trace_set_log_handler(mono_log_callback, this); } else { @@ -192,11 +189,6 @@ GDMonoLog::GDMonoLog() { GDMonoLog::~GDMonoLog() { singleton = nullptr; - - if (log_file) { - log_file->close(); - memdelete(log_file); - } } #else diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index 9ddbd251ac..9fc35f8e31 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -48,7 +48,7 @@ class GDMonoLog { #ifdef GD_MONO_LOG_ENABLED int log_level_id = -1; - FileAccess *log_file = nullptr; + Ref<FileAccess> log_file; String log_file_path; bool _try_create_logs_dir(const String &p_logs_dir); diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 6b395303dd..957abca37b 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 2f4b619b61..778e52b6cb 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -196,14 +196,14 @@ PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array); #pragma pack(push, 1) struct M_Callable { - MonoObject *target; - MonoObject *method_string_name; - MonoDelegate *delegate; + MonoObject *target = nullptr; + MonoObject *method_string_name = nullptr; + MonoDelegate *delegate = nullptr; }; struct M_SignalInfo { - MonoObject *owner; - MonoObject *name_string_name; + MonoObject *owner = nullptr; + MonoObject *name_string_name = nullptr; }; #pragma pack(pop) @@ -367,9 +367,9 @@ struct M_Transform2D { static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) { M_Transform2D ret = { - M_Vector2::convert_from(p_from.elements[0]), - M_Vector2::convert_from(p_from.elements[1]), - M_Vector2::convert_from(p_from.elements[2]) + M_Vector2::convert_from(p_from.columns[0]), + M_Vector2::convert_from(p_from.columns[1]), + M_Vector2::convert_from(p_from.columns[2]) }; return ret; } @@ -412,9 +412,9 @@ struct M_Basis { static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) { M_Basis ret = { - M_Vector3::convert_from(p_from.elements[0]), - M_Vector3::convert_from(p_from.elements[1]), - M_Vector3::convert_from(p_from.elements[2]) + M_Vector3::convert_from(p_from.rows[0]), + M_Vector3::convert_from(p_from.rows[1]), + M_Vector3::convert_from(p_from.rows[2]) }; return ret; } diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 67aabcde10..6734b44783 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index c08ffe904b..be11ef5bfe 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -54,7 +54,7 @@ class GDMonoMethod : public IMonoClassMember { friend class GDMonoClass; - MonoMethod *mono_method; + MonoMethod *mono_method = nullptr; public: virtual GDMonoClass *get_enclosing_class() const final; diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h index 091d26df1d..bb163b89bc 100644 --- a/modules/mono/mono_gd/gd_mono_method_thunk.h +++ b/modules/mono/mono_gd/gd_mono_method_thunk.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index 5c7cf29e88..c9775ae9cb 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index 9bb1caa759..6fc681aeb5 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,14 +36,14 @@ #include "i_mono_class_member.h" class GDMonoProperty : public IMonoClassMember { - GDMonoClass *owner; - MonoProperty *mono_property; + GDMonoClass *owner = nullptr; + MonoProperty *mono_property = nullptr; StringName name; ManagedType type; bool attrs_fetched; - MonoCustomAttrInfo *attributes; + MonoCustomAttrInfo *attributes = nullptr; unsigned int param_buffer_size; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 505c637af9..a884bf4da0 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 3162ef198d..4c2c2c93c2 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp index a477c55456..dbfca2dc0c 100644 --- a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp +++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h index c49a62a632..83e2750e5a 100644 --- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h +++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -47,11 +47,11 @@ struct Mono_InterpMethodArguments { size_t ilen; void **iargs; size_t flen; - double *fargs; + double *fargs = nullptr; void **retval; size_t is_float_ret; //#ifdef TARGET_WASM - void *sig; + void *sig = nullptr; //#endif }; } // extern "C" diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h index 36e14ba27c..14e8ca82b9 100644 --- a/modules/mono/mono_gd/i_mono_class_member.h +++ b/modules/mono/mono_gd/i_mono_class_member.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp index 0acfafe841..5860d7db1e 100644 --- a/modules/mono/mono_gd/managed_type.cpp +++ b/modules/mono/mono_gd/managed_type.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h index 0456a9a864..603ff3aca1 100644 --- a/modules/mono/mono_gd/managed_type.h +++ b/modules/mono/mono_gd/managed_type.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp index c65353dfd1..4797d5dae1 100644 --- a/modules/mono/mono_gd/support/android_support.cpp +++ b/modules/mono/mono_gd/support/android_support.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -134,8 +134,9 @@ String determine_app_native_lib_dir() { } String get_app_native_lib_dir() { - if (app_native_lib_dir_cache.is_empty()) + if (app_native_lib_dir_cache.is_empty()) { app_native_lib_dir_cache = determine_app_native_lib_dir(); + } return app_native_lib_dir_cache; } @@ -144,10 +145,11 @@ int gd_mono_convert_dl_flags(int flags) { int lflags = flags & MONO_DL_LOCAL ? 0 : RTLD_GLOBAL; - if (flags & MONO_DL_LAZY) + if (flags & MONO_DL_LAZY) { lflags |= RTLD_LAZY; - else + } else { lflags |= RTLD_NOW; + } return lflags; } @@ -164,8 +166,9 @@ void *godot_dl_handle = nullptr; void *try_dlopen(const String &p_so_path, int p_flags) { if (!FileAccess::exists(p_so_path)) { - if (OS::get_singleton()->is_stdout_verbose()) + if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data()); + } return nullptr; } @@ -174,13 +177,15 @@ void *try_dlopen(const String &p_so_path, int p_flags) { void *handle = dlopen(p_so_path.utf8().get_data(), lflags); if (!handle) { - if (OS::get_singleton()->is_stdout_verbose()) + if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror()); + } return nullptr; } - if (OS::get_singleton()->is_stdout_verbose()) + if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data()); + } return handle; } @@ -217,20 +222,23 @@ void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, void *p_user_data) { void *sym_addr = dlsym(p_handle, p_name); - if (sym_addr) + if (sym_addr) { return sym_addr; + } if (p_handle == mono_dl_handle && godot_dl_handle) { // Looking up for '__Internal' P/Invoke. We want to search in both the Mono and Godot shared libraries. // This is needed to resolve the monodroid P/Invoke functions that are defined at the bottom of the file. sym_addr = dlsym(godot_dl_handle, p_name); - if (sym_addr) + if (sym_addr) { return sym_addr; + } } - if (r_err) + if (r_err) { *r_err = str_format_new("%s\n", dlerror()); + } return nullptr; } @@ -239,8 +247,9 @@ void *gd_mono_android_dlclose(void *p_handle, void *p_user_data) { dlclose(p_handle); // Not sure if this ever happens. Does Mono close the handle for the main module? - if (p_handle == mono_dl_handle) + if (p_handle == mono_dl_handle) { mono_dl_handle = nullptr; + } return nullptr; } @@ -292,13 +301,15 @@ MonoBoolean _gd_mono_init_cert_store() { ScopedLocalRef<jobject> certStoreLocal(env, env->CallStaticObjectMethod(keyStoreClass, getInstance, androidCAStoreString.get())); - if (jni_exception_check(env)) + if (jni_exception_check(env)) { return 0; + } env->CallVoidMethod(certStoreLocal, load, nullptr); - if (jni_exception_check(env)) + if (jni_exception_check(env)) { return 0; + } certStore = env->NewGlobalRef(certStoreLocal); @@ -309,8 +320,9 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { // The JNI code is the equivalent of: // // Certificate certificate = certStore.getCertificate(alias); - // if (certificate == null) + // if (certificate == null) { // return null; + // } // return certificate.getEncoded(); MonoError mono_error; @@ -340,8 +352,9 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { ScopedLocalRef<jobject> certificate(env, env->CallObjectMethod(certStore, getCertificate, js_alias.get())); - if (!certificate) + if (!certificate) { return nullptr; + } ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded)); jsize encodedLength = env->GetArrayLength(encoded); @@ -374,11 +387,13 @@ void initialize() { void cleanup() { // This is called after shutting down the Mono runtime - if (mono_dl_handle) + if (mono_dl_handle) { gd_mono_android_dlclose(mono_dl_handle, nullptr); + } - if (godot_dl_handle) + if (godot_dl_handle) { gd_mono_android_dlclose(godot_dl_handle, nullptr); + } JNIEnv *env = get_jni_env(); @@ -431,8 +446,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char // // NetworkInterface.getByName(p_ifname).isUp() - if (!r_is_up || !p_ifname || strlen(p_ifname) == 0) + if (!r_is_up || !p_ifname || strlen(p_ifname) == 0) { return 0; + } *r_is_up = 0; @@ -450,8 +466,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname)); ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get())); - if (!networkInterface) + if (!networkInterface) { return 0; + } *r_is_up = (mono_bool)env->CallBooleanMethod(networkInterface, isUp); @@ -463,8 +480,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast( // // NetworkInterface.getByName(p_ifname).supportsMulticast() - if (!r_supports_multicast || !p_ifname || strlen(p_ifname) == 0) + if (!r_supports_multicast || !p_ifname || strlen(p_ifname) == 0) { return 0; + } *r_supports_multicast = 0; @@ -482,8 +500,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast( ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname)); ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get())); - if (!networkInterface) + if (!networkInterface) { return 0; + } *r_supports_multicast = (mono_bool)env->CallBooleanMethod(networkInterface, supportsMulticast); @@ -528,8 +547,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn ScopedLocalRef<jobject> connectivityManager(env, env->CallObjectMethod(applicationContext, getSystemService, connectivityServiceString.get())); - if (!connectivityManager) + if (!connectivityManager) { return; + } ScopedLocalRef<jclass> connectivityManagerClass(env, env->FindClass("android/net/ConnectivityManager")); ERR_FAIL_NULL(connectivityManagerClass); @@ -539,8 +559,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn ScopedLocalRef<jobject> activeNetwork(env, env->CallObjectMethod(connectivityManager, getActiveNetwork)); - if (!activeNetwork) + if (!activeNetwork) { return; + } jmethodID getLinkProperties = env->GetMethodID(connectivityManagerClass, "getLinkProperties", "(Landroid/net/Network;)Landroid/net/LinkProperties;"); @@ -548,8 +569,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn ScopedLocalRef<jobject> linkProperties(env, env->CallObjectMethod(connectivityManager, getLinkProperties, activeNetwork.get())); - if (!linkProperties) + if (!linkProperties) { return; + } ScopedLocalRef<jclass> linkPropertiesClass(env, env->FindClass("android/net/LinkProperties")); ERR_FAIL_NULL(linkPropertiesClass); @@ -559,8 +581,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn ScopedLocalRef<jobject> dnsServers(env, env->CallObjectMethod(linkProperties, getDnsServers)); - if (!dnsServers) + if (!dnsServers) { return; + } ScopedLocalRef<jclass> listClass(env, env->FindClass("java/util/List")); ERR_FAIL_NULL(listClass); @@ -570,11 +593,13 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn int dnsServersCount = env->CallIntMethod(dnsServers, listSize); - if (dnsServersCount > dns_servers_len) + if (dnsServersCount > dns_servers_len) { dnsServersCount = dns_servers_len; + } - if (dnsServersCount <= 0) + if (dnsServersCount <= 0) { return; + } jmethodID listGet = env->GetMethodID(listClass, "get", "(I)Ljava/lang/Object;"); ERR_FAIL_NULL(listGet); @@ -587,8 +612,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn for (int i = 0; i < dnsServersCount; i++) { ScopedLocalRef<jobject> dnsServer(env, env->CallObjectMethod(dnsServers, listGet, (jint)i)); - if (!dnsServer) + if (!dnsServer) { continue; + } ScopedLocalRef<jstring> hostAddress(env, (jstring)env->CallObjectMethod(dnsServer, getHostAddress)); const char *host_address = env->GetStringUTFChars(hostAddress, 0); @@ -603,8 +629,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn } GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array) { - if (!r_dns_servers_array) + if (!r_dns_servers_array) { return -1; + } *r_dns_servers_array = nullptr; @@ -661,13 +688,15 @@ GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() { ScopedLocalRef<jobject> defaultTimeZone(env, env->CallStaticObjectMethod(timeZoneClass, getDefault)); - if (!defaultTimeZone) + if (!defaultTimeZone) { return nullptr; + } ScopedLocalRef<jstring> defaultTimeZoneID(env, (jstring)env->CallObjectMethod(defaultTimeZone, getID)); - if (!defaultTimeZoneID) + if (!defaultTimeZoneID) { return nullptr; + } const char *default_time_zone_id = env->GetStringUTFChars(defaultTimeZoneID, 0); diff --git a/modules/mono/mono_gd/support/android_support.h b/modules/mono/mono_gd/support/android_support.h index 0c5dd2764c..073cd31c65 100644 --- a/modules/mono/mono_gd/support/android_support.h +++ b/modules/mono/mono_gd/support/android_support.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h index 28a8806d0e..2f444d5089 100644 --- a/modules/mono/mono_gd/support/ios_support.h +++ b/modules/mono/mono_gd/support/ios_support.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm index 23424fbaf9..df97dfba49 100644 --- a/modules/mono/mono_gd/support/ios_support.mm +++ b/modules/mono/mono_gd/support/ios_support.mm @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -94,8 +94,9 @@ GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() { GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) { int length = 0; const uint16_t *ptr = p_unicode_message; - while (*ptr++) + while (*ptr++) { length += sizeof(uint16_t); + } NSString *msg = [[NSString alloc] initWithBytes:p_unicode_message length:length encoding:NSUTF16LittleEndianStringEncoding]; os_log_info(OS_LOG_DEFAULT, "%{public}@", msg); diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp index 98e83335e9..755e1f7a30 100644 --- a/modules/mono/register_types.cpp +++ b/modules/mono/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -40,7 +40,11 @@ Ref<ResourceFormatSaverCSharpScript> resource_saver_cs; mono_bind::GodotSharp *_godotsharp = nullptr; -void register_mono_types() { +void initialize_mono_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(CSharpScript); _godotsharp = memnew(mono_bind::GodotSharp); @@ -59,7 +63,11 @@ void register_mono_types() { ResourceSaver::add_resource_format_saver(resource_saver_cs); } -void unregister_mono_types() { +void uninitialize_mono_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + ScriptServer::unregister_language(script_language_cs); if (script_language_cs) { diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h index 1a2ff004b5..bc2690c277 100644 --- a/modules/mono/register_types.h +++ b/modules/mono/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef MONO_REGISTER_TYPES_H #define MONO_REGISTER_TYPES_H -void register_mono_types(); -void unregister_mono_types(); +#include "modules/register_module_types.h" + +void initialize_mono_module(ModuleInitializationLevel p_level); +void uninitialize_mono_module(ModuleInitializationLevel p_level); #endif // MONO_REGISTER_TYPES_H diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 3aaf726fc8..315a9c29f6 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h index e12ea45b3f..532aa3e327 100644 --- a/modules/mono/signal_awaiter_utils.h +++ b/modules/mono/signal_awaiter_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -68,7 +68,7 @@ public: }; class EventSignalCallable : public CallableCustom { - Object *owner; + Object *owner = nullptr; const CSharpScript::EventSignal *event_signal; public: diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h index 4a220d89c8..2ca1a4cbf1 100644 --- a/modules/mono/utils/macros.h +++ b/modules/mono/utils/macros.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index d0a27b27c1..8e37e6943c 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -60,8 +60,9 @@ REGSAM _get_bitness_sam() { LONG _RegOpenKey(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) { LONG res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, phkResult); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ | _get_bitness_sam(), phkResult); + } return res; } @@ -92,31 +93,37 @@ LONG _find_mono_in_reg(const String &p_subkey, MonoRegInfo &r_info, bool p_old_r HKEY hKey; LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } if (!p_old_reg) { res = _RegKeyQueryString(hKey, "Version", r_info.version); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } } res = _RegKeyQueryString(hKey, "SdkInstallRoot", r_info.install_root_dir); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } res = _RegKeyQueryString(hKey, "FrameworkAssemblyDirectory", r_info.assembly_dir); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } res = _RegKeyQueryString(hKey, "MonoConfigDir", r_info.config_dir); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } - if (r_info.install_root_dir.ends_with("\\")) + if (r_info.install_root_dir.ends_with("\\")) { r_info.bin_dir = r_info.install_root_dir + "bin"; - else + } else { r_info.bin_dir = r_info.install_root_dir + "\\bin"; + } cleanup: RegCloseKey(hKey); @@ -129,8 +136,9 @@ LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) { HKEY hKey; LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } res = _RegKeyQueryString(hKey, "DefaultCLR", default_clr); @@ -147,11 +155,13 @@ cleanup: MonoRegInfo find_mono() { MonoRegInfo info; - if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS) + if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS) { return info; + } - if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS) + if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS) { return info; + } return MonoRegInfo(); } @@ -212,13 +222,15 @@ String find_msbuild_tools_path() { HKEY hKey; LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\14.0", &hKey); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } res = _RegKeyQueryString(hKey, "MSBuildToolsPath", msbuild_tools_path); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS) { goto cleanup; + } cleanup: RegCloseKey(hKey); diff --git a/modules/mono/utils/mono_reg_utils.h b/modules/mono/utils/mono_reg_utils.h index 0e617761ea..5be60d4930 100644 --- a/modules/mono/utils/mono_reg_utils.h +++ b/modules/mono/utils/mono_reg_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp index f4216c8129..abb59420eb 100644 --- a/modules/mono/utils/osx_utils.cpp +++ b/modules/mono/utils/osx_utils.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,8 +34,8 @@ #include "core/string/print_string.h" -#include <CoreFoundation/CoreFoundation.h> -#include <CoreServices/CoreServices.h> +#import <CoreFoundation/CoreFoundation.h> +#import <CoreServices/CoreServices.h> bool osx_is_app_bundle_installed(const String &p_bundle_id) { CFStringRef bundle_id = CFStringCreateWithCString(nullptr, p_bundle_id.utf8(), kCFStringEncodingUTF8); diff --git a/modules/mono/utils/osx_utils.h b/modules/mono/utils/osx_utils.h index 6704f19077..2f6c6dad51 100644 --- a/modules/mono/utils/osx_utils.h +++ b/modules/mono/utils/osx_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index 64aec5d359..15a0b28181 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/modules/mono/utils/path_utils.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -57,8 +57,9 @@ String cwd() { Char16String buffer; buffer.resize((int)expected_size); - if (::GetCurrentDirectoryW(expected_size, (wchar_t *)buffer.ptrw()) == 0) + if (::GetCurrentDirectoryW(expected_size, (wchar_t *)buffer.ptrw()) == 0) { return "."; + } String result; if (result.parse_utf16(buffer.ptr())) { @@ -95,8 +96,9 @@ String realpath(const String &p_path) { FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile == INVALID_HANDLE_VALUE) + if (hFile == INVALID_HANDLE_VALUE) { return p_path; + } const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED); @@ -177,8 +179,9 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) { #ifdef WINDOWS_ENABLED String get_drive_letter(const String &p_norm_path) { int idx = p_norm_path.find(":/"); - if (idx != -1 && idx < p_norm_path.find("/")) + if (idx != -1 && idx < p_norm_path.find("/")) { return p_norm_path.substr(0, idx + 1); + } return String(); } #endif diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h index 82b8f95f49..a8cd8daf04 100644 --- a/modules/mono/utils/path_utils.h +++ b/modules/mono/utils/path_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index 74f5e6d18a..e6975611d2 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -167,15 +167,13 @@ String escape_csharp_keyword(const String &p_name) { Error read_all_file_utf8(const String &p_path, String &r_content) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h index 3290cb38b9..d79888716a 100644 --- a/modules/mono/utils/string_utils.h +++ b/modules/mono/utils/string_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/msdfgen/register_types.cpp b/modules/msdfgen/register_types.cpp index ad60a66d2d..2d3a2a0c69 100644 --- a/modules/msdfgen/register_types.cpp +++ b/modules/msdfgen/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,6 +30,14 @@ #include "register_types.h" -void register_msdfgen_types() {} +void initialize_msdfgen_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} -void unregister_msdfgen_types() {} +void uninitialize_msdfgen_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/msdfgen/register_types.h b/modules/msdfgen/register_types.h index fb776c14ed..749204f390 100644 --- a/modules/msdfgen/register_types.h +++ b/modules/msdfgen/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef MSDFGEN_REGISTER_TYPES_H #define MSDFGEN_REGISTER_TYPES_H -void register_msdfgen_types(); -void unregister_msdfgen_types(); +#include "modules/register_module_types.h" + +void initialize_msdfgen_module(ModuleInitializationLevel p_level); +void uninitialize_msdfgen_module(ModuleInitializationLevel p_level); #endif // MSDFGEN_REGISTER_TYPES_H diff --git a/modules/navigation/SCsub b/modules/navigation/SCsub index 22b5509b32..24a6b12639 100644 --- a/modules/navigation/SCsub +++ b/modules/navigation/SCsub @@ -57,6 +57,8 @@ env.modules_sources += thirdparty_obj module_obj = [] env_navigation.add_source_files(module_obj, "*.cpp") +if env["tools"]: + env_navigation.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/modules/navigation/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp index 587e56f593..c243e3e6e3 100644 --- a/modules/navigation/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,12 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef TOOLS_ENABLED #include "navigation_mesh_editor_plugin.h" +#ifdef TOOLS_ENABLED + +#include "../navigation_mesh_generator.h" #include "core/io/marshalls.h" #include "core/io/resource_saver.h" -#include "navigation_mesh_generator.h" +#include "editor/editor_node.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/gui/box_container.h" @@ -45,10 +47,12 @@ void NavigationMeshEditor::_node_removed(Node *p_node) { } } -void NavigationMeshEditor::_notification(int p_option) { - if (p_option == NOTIFICATION_ENTER_TREE) { - button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons"))); - button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); +void NavigationMeshEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons"))); + button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); + } break; } } @@ -139,10 +143,9 @@ void NavigationMeshEditorPlugin::make_visible(bool p_visible) { } } -NavigationMeshEditorPlugin::NavigationMeshEditorPlugin(EditorNode *p_node) { - editor = p_node; +NavigationMeshEditorPlugin::NavigationMeshEditorPlugin() { navigation_mesh_editor = memnew(NavigationMeshEditor); - editor->get_main_control()->add_child(navigation_mesh_editor); + EditorNode::get_singleton()->get_main_control()->add_child(navigation_mesh_editor); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, navigation_mesh_editor->bake_hbox); navigation_mesh_editor->hide(); navigation_mesh_editor->bake_hbox->hide(); @@ -151,4 +154,4 @@ NavigationMeshEditorPlugin::NavigationMeshEditorPlugin(EditorNode *p_node) { NavigationMeshEditorPlugin::~NavigationMeshEditorPlugin() { } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/navigation/navigation_mesh_editor_plugin.h b/modules/navigation/editor/navigation_mesh_editor_plugin.h index c39269865b..bc9e4185b7 100644 --- a/modules/navigation/navigation_mesh_editor_plugin.h +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,7 +33,6 @@ #ifdef TOOLS_ENABLED -#include "editor/editor_node.h" #include "editor/editor_plugin.h" class NavigationRegion3D; @@ -43,14 +42,14 @@ class NavigationMeshEditor : public Control { GDCLASS(NavigationMeshEditor, Control); - AcceptDialog *err_dialog; + AcceptDialog *err_dialog = nullptr; - HBoxContainer *bake_hbox; - Button *button_bake; - Button *button_reset; - Label *bake_info; + HBoxContainer *bake_hbox = nullptr; + Button *button_bake = nullptr; + Button *button_reset = nullptr; + Label *bake_info = nullptr; - NavigationRegion3D *node; + NavigationRegion3D *node = nullptr; void _bake_pressed(); void _clear_pressed(); @@ -58,7 +57,7 @@ class NavigationMeshEditor : public Control { protected: void _node_removed(Node *p_node); static void _bind_methods(); - void _notification(int p_option); + void _notification(int p_what); public: void edit(NavigationRegion3D *p_nav_region); @@ -69,8 +68,7 @@ public: class NavigationMeshEditorPlugin : public EditorPlugin { GDCLASS(NavigationMeshEditorPlugin, EditorPlugin); - NavigationMeshEditor *navigation_mesh_editor; - EditorNode *editor; + NavigationMeshEditor *navigation_mesh_editor = nullptr; public: virtual String get_name() const override { return "NavigationMesh"; } @@ -79,10 +77,10 @@ public: virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; - NavigationMeshEditorPlugin(EditorNode *p_node); + NavigationMeshEditorPlugin(); ~NavigationMeshEditorPlugin(); }; -#endif +#endif // TOOLS_ENABLED -#endif +#endif // NAVIGATION_MESH_EDITOR_PLUGIN_H diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index ac3422187f..d16d41b438 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,51 +36,47 @@ #include "navigation_mesh_generator.h" #endif -/** - @author AndreaCatania -*/ - /// Creates a struct for each function and a function that once called creates /// 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(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); \ - } \ +#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) override { \ + 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); \ - } \ +#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) override { \ + 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) \ @@ -99,7 +95,7 @@ d_1(p_d_1), \ d_2(p_d_2), \ d_3(p_d_3) {} \ - virtual void exec(GodotNavigationServer *server) { \ + virtual void exec(GodotNavigationServer *server) override { \ server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \ } \ }; \ @@ -113,9 +109,7 @@ } \ 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() { -} +GodotNavigationServer::GodotNavigationServer() {} GodotNavigationServer::~GodotNavigationServer() { flush_queries(); diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 65224493fd..7ad5e2d501 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -40,25 +40,21 @@ #include "nav_region.h" #include "rvo_agent.h" -/** - @author AndreaCatania -*/ - /// The commands are functions executed during the `sync` phase. #define MERGE_INTERNAL(A, B) A##B #define MERGE(A, B) MERGE_INTERNAL(A, B) -#define COMMAND_1(F_NAME, T_0, D_0) \ - virtual void F_NAME(T_0 D_0) const; \ +#define COMMAND_1(F_NAME, T_0, D_0) \ + virtual void F_NAME(T_0 D_0) const override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0) -#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ - virtual void F_NAME(T_0 D_0, T_1 D_1) const; \ +#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ + virtual void F_NAME(T_0 D_0, T_1 D_1) const override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) -#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \ - virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const; \ +#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \ + virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) class GodotNavigationServer; @@ -89,38 +85,38 @@ public: void add_command(SetCommand *command) const; - virtual RID map_create() const; + virtual RID map_create() const override; COMMAND_2(map_set_active, RID, p_map, bool, p_active); - virtual bool map_is_active(RID p_map) const; + virtual bool map_is_active(RID p_map) const override; COMMAND_2(map_set_up, RID, p_map, Vector3, p_up); - virtual Vector3 map_get_up(RID p_map) const; + virtual Vector3 map_get_up(RID p_map) const override; COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size); - virtual real_t map_get_cell_size(RID p_map) const; + virtual real_t map_get_cell_size(RID p_map) const override; COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin); - virtual real_t map_get_edge_connection_margin(RID p_map) const; + virtual real_t map_get_edge_connection_margin(RID p_map) const override; - virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const; + virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const override; - virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const; - virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const; - virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const; - virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const; + virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override; + virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const override; + virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override; + virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override; - virtual RID region_create() const; + virtual RID region_create() const override; 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; + virtual uint32_t region_get_layers(RID p_region) const override; 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; - virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const; - virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const; + virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override; + virtual int region_get_connections_count(RID p_region) const override; + virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; + virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; - virtual RID agent_create() const; + virtual RID agent_create() const override; COMMAND_2(agent_set_map, RID, p_agent, RID, p_map); COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist); COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count); @@ -131,15 +127,15 @@ public: COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity); COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position); COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore); - virtual bool agent_is_map_changed(RID p_agent) const; + virtual bool agent_is_map_changed(RID p_agent) const override; COMMAND_4_DEF(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, Variant()); COMMAND_1(free, RID, p_object); - virtual void set_active(bool p_active) const; + virtual void set_active(bool p_active) const override; void flush_queries(); - virtual void process(real_t p_delta_time); + virtual void process(real_t p_delta_time) override; }; #undef COMMAND_1 diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 0c8f0ed8c9..cbc0adc574 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,16 +30,11 @@ #include "nav_map.h" -#include "core/os/threaded_array_processor.h" #include "nav_region.h" #include "rvo_agent.h" #include <algorithm> -/** - @author AndreaCatania -*/ - #define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a))) void NavMap::set_up(Vector3 p_up) { @@ -87,12 +82,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p continue; } - // For each point cast a face and check the distance between the origin/destination - for (size_t point_id = 0; point_id < p.points.size(); point_id++) { - const Vector3 p1 = p.points[point_id].pos; - const Vector3 p2 = p.points[(point_id + 1) % p.points.size()].pos; - const Vector3 p3 = p.points[(point_id + 2) % p.points.size()].pos; - const Face3 face(p1, p2, p3); + // For each face check the distance between the origin/destination + for (size_t point_id = 2; point_id < p.points.size(); point_id++) { + const Face3 face(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos); Vector3 point = face.get_closest_point_to(p_origin); float distance_to_point = point.distance_to(p_origin); @@ -149,10 +141,10 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p bool is_reachable = true; while (true) { - gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id]; - // Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance. - for (size_t i = 0; i < least_cost_poly->poly->edges.size(); i++) { + for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) { + gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id]; + const gd::Edge &edge = least_cost_poly->poly->edges[i]; // Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon. @@ -218,7 +210,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p end_poly = reachable_end; end_d = 1e20; for (size_t point_id = 2; point_id < end_poly->points.size(); point_id++) { - Face3 f(end_poly->points[point_id - 2].pos, end_poly->points[point_id - 1].pos, end_poly->points[point_id].pos); + Face3 f(end_poly->points[0].pos, end_poly->points[point_id - 1].pos, end_poly->points[point_id].pos); Vector3 spoint = f.get_closest_point_to(p_destination); float dpoint = spoint.distance_to(p_destination); if (dpoint < end_d) { @@ -233,6 +225,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p navigation_polys.push_back(np); to_visit.clear(); to_visit.push_back(0); + least_cost_id = 0; reachable_end = nullptr; @@ -252,6 +245,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p } } + ERR_BREAK(least_cost_id == -1); + // Stores the further reachable end polygon, in case our goal is not reachable. if (is_reachable) { float d = navigation_polys[least_cost_id].entry.distance_to(p_destination); @@ -261,8 +256,6 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p } } - ERR_BREAK(least_cost_id == -1); - // Check if we reached the end if (navigation_polys[least_cost_id].poly == end_poly) { found_route = true; @@ -358,11 +351,15 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p // Add mid points int np_id = least_cost_id; - while (np_id != -1) { - path.push_back(navigation_polys[np_id].entry); + while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) { + int prev = navigation_polys[np_id].back_navigation_edge; + int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size(); + Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5; + path.push_back(point); np_id = navigation_polys[np_id].back_navigation_poly_id; } + path.push_back(begin_point); path.reverse(); } @@ -374,13 +371,12 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector Vector3 closest_point; real_t closest_point_d = 1e20; - // Find the initial poly and the end poly on this map. for (size_t i(0); i < polygons.size(); i++) { const gd::Polygon &p = polygons[i]; - // For each point cast a face and check the distance to the segment + // For each face check the distance to the segment for (size_t point_id = 2; point_id < p.points.size(); point_id += 1) { - const Face3 f(p.points[point_id - 2].pos, p.points[point_id - 1].pos, p.points[point_id].pos); + const Face3 f(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos); Vector3 inters; if (f.intersects_segment(p_from, p_to, &inters)) { const real_t d = closest_point_d = p_from.distance_to(inters); @@ -420,82 +416,42 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector } Vector3 NavMap::get_closest_point(const Vector3 &p_point) const { - // TODO this is really not optimal, please redesign the API to directly return all this data - - Vector3 closest_point; - real_t closest_point_d = 1e20; - - // Find the initial poly and the end poly on this map. - for (size_t i(0); i < polygons.size(); i++) { - const gd::Polygon &p = polygons[i]; - - // For each point cast a face and check the distance to the point - for (size_t point_id = 2; point_id < p.points.size(); point_id += 1) { - const Face3 f(p.points[point_id - 2].pos, p.points[point_id - 1].pos, p.points[point_id].pos); - const Vector3 inters = f.get_closest_point_to(p_point); - const real_t d = inters.distance_to(p_point); - if (d < closest_point_d) { - closest_point = inters; - closest_point_d = d; - } - } - } - - return closest_point; + gd::ClosestPointQueryResult cp = get_closest_point_info(p_point); + return cp.point; } Vector3 NavMap::get_closest_point_normal(const Vector3 &p_point) const { - // TODO this is really not optimal, please redesign the API to directly return all this data - - Vector3 closest_point; - Vector3 closest_point_normal; - real_t closest_point_d = 1e20; - - // Find the initial poly and the end poly on this map. - for (size_t i(0); i < polygons.size(); i++) { - const gd::Polygon &p = polygons[i]; - - // For each point cast a face and check the distance to the point - for (size_t point_id = 2; point_id < p.points.size(); point_id += 1) { - const Face3 f(p.points[point_id - 2].pos, p.points[point_id - 1].pos, p.points[point_id].pos); - const Vector3 inters = f.get_closest_point_to(p_point); - const real_t d = inters.distance_to(p_point); - if (d < closest_point_d) { - closest_point = inters; - closest_point_normal = f.get_plane().normal; - closest_point_d = d; - } - } - } - - return closest_point_normal; + gd::ClosestPointQueryResult cp = get_closest_point_info(p_point); + return cp.normal; } RID NavMap::get_closest_point_owner(const Vector3 &p_point) const { - // TODO this is really not optimal, please redesign the API to directly return all this data + gd::ClosestPointQueryResult cp = get_closest_point_info(p_point); + return cp.owner; +} - Vector3 closest_point; - RID closest_point_owner; - real_t closest_point_d = 1e20; +gd::ClosestPointQueryResult NavMap::get_closest_point_info(const Vector3 &p_point) const { + gd::ClosestPointQueryResult result; + real_t closest_point_ds = 1e20; - // Find the initial poly and the end poly on this map. for (size_t i(0); i < polygons.size(); i++) { const gd::Polygon &p = polygons[i]; - // For each point cast a face and check the distance to the point + // For each face check the distance to the point for (size_t point_id = 2; point_id < p.points.size(); point_id += 1) { - const Face3 f(p.points[point_id - 2].pos, p.points[point_id - 1].pos, p.points[point_id].pos); + const Face3 f(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos); const Vector3 inters = f.get_closest_point_to(p_point); - const real_t d = inters.distance_to(p_point); - if (d < closest_point_d) { - closest_point = inters; - closest_point_owner = p.owner->get_self(); - closest_point_d = d; + const real_t ds = inters.distance_squared_to(p_point); + if (ds < closest_point_ds) { + result.point = inters; + result.normal = f.get_plane().normal; + result.owner = p.owner->get_self(); + closest_point_ds = ds; } } } - return closest_point_owner; + return result; } void NavMap::add_region(NavRegion *p_region) { @@ -717,7 +673,10 @@ void NavMap::compute_single_step(uint32_t index, RvoAgent **agent) { void NavMap::step(real_t p_deltatime) { deltatime = p_deltatime; if (controlled_agents.size() > 0) { - thread_process_array( + if (step_work_pool.get_thread_count() == 0) { + step_work_pool.init(); + } + step_work_pool.do_work( controlled_agents.size(), this, &NavMap::compute_single_step, @@ -762,3 +721,10 @@ void NavMap::clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys } } } + +NavMap::NavMap() { +} + +NavMap::~NavMap() { + step_work_pool.finish(); +} diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index 8e013a72eb..5232e42bed 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,12 +35,10 @@ #include "core/math/math_defs.h" #include "core/templates/map.h" +#include "core/templates/thread_work_pool.h" #include "nav_utils.h" -#include <KdTree.h> -/** - @author AndreaCatania -*/ +#include <KdTree.h> class NavRegion; class RvoAgent; @@ -83,8 +81,12 @@ class NavMap : public NavRid { /// Change the id each time the map is updated. uint32_t map_update_id = 0; + /// Pooled threads for computing steps + ThreadWorkPool step_work_pool; + public: - NavMap() {} + NavMap(); + ~NavMap(); void set_up(Vector3 p_up); Vector3 get_up() const { @@ -107,6 +109,7 @@ public: Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const; Vector3 get_closest_point(const Vector3 &p_point) const; Vector3 get_closest_point_normal(const Vector3 &p_point) const; + gd::ClosestPointQueryResult get_closest_point_info(const Vector3 &p_point) const; RID get_closest_point_owner(const Vector3 &p_point) const; void add_region(NavRegion *p_region); diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp index 81b15a49f5..fea0ad519a 100644 --- a/modules/navigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,10 +32,6 @@ #include "nav_map.h" -/** - @author AndreaCatania -*/ - void NavRegion::set_map(NavMap *p_map) { map = p_map; polygons_dirty = true; diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index f8b067e638..7a6da281c0 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,11 +35,8 @@ #include "nav_rid.h" #include "nav_utils.h" -#include <vector> -/** - @author AndreaCatania -*/ +#include <vector> class NavMap; class NavRegion; diff --git a/modules/navigation/nav_rid.h b/modules/navigation/nav_rid.h index a0a60a3643..31e20440d2 100644 --- a/modules/navigation/nav_rid.h +++ b/modules/navigation/nav_rid.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,10 +33,6 @@ #include "core/templates/rid.h" -/** - @author AndreaCatania -*/ - class NavRid { RID self; diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index 35da391eea..5b6c695ca4 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,13 +32,10 @@ #define NAV_UTILS_H #include "core/math/vector3.h" +#include "core/templates/vector.h" #include <vector> -/** - @author AndreaCatania -*/ - class NavRegion; namespace gd { @@ -92,7 +89,7 @@ struct Edge { }; struct Polygon { - NavRegion *owner; + NavRegion *owner = nullptr; /// The points of this `Polygon` std::vector<Point> points; @@ -135,6 +132,12 @@ struct NavigationPoly { } }; +struct ClosestPointQueryResult { + Vector3 point; + Vector3 normal; + RID owner; +}; + } // namespace gd #endif // NAV_UTILS_H diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 0bce0fc9f0..2d6c78f704 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,7 +34,6 @@ #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" #include "scene/3d/multimesh_instance_3d.h" #include "scene/3d/physics_body_3d.h" @@ -50,7 +49,6 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" -#include "editor/editor_settings.h" #endif #include "modules/modules_enabled.gen.h" // For csg, gridmap. @@ -125,6 +123,28 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform } } +void NavigationMeshGenerator::_add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) { + Vector<Vector3> mesh_vertices = p_array[Mesh::ARRAY_VERTEX]; + const Vector3 *vr = mesh_vertices.ptr(); + + Vector<int> mesh_indices = p_array[Mesh::ARRAY_INDEX]; + const int *ir = mesh_indices.ptr(); + + const int face_count = mesh_indices.size() / 3; + const int current_vertex_count = p_vertices.size() / 3; + + for (int j = 0; j < mesh_vertices.size(); j++) { + _add_vertex(p_xform.xform(vr[j]), p_vertices); + } + + for (int j = 0; j < face_count; j++) { + // CCW + p_indices.push_back(current_vertex_count + (ir[j * 3 + 0])); + p_indices.push_back(current_vertex_count + (ir[j * 3 + 2])); + p_indices.push_back(current_vertex_count + (ir[j * 3 + 1])); + } +} + void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) { int face_count = p_faces.size() / 3; int current_vertex_count = p_vertices.size() / 3; @@ -140,12 +160,12 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons } } -void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { +void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType 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(); if (mesh.is_valid()) { - _add_mesh(mesh, p_accumulated_transform * mesh_instance->get_transform(), p_vertices, p_indices); + _add_mesh(mesh, p_navmesh_transform * mesh_instance->get_global_transform(), p_vertices, p_indices); } } @@ -159,7 +179,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor n = multimesh->get_instance_count(); } for (int i = 0; i < n; i++) { - _add_mesh(mesh, p_accumulated_transform * multimesh->get_instance_transform(i), p_vertices, p_indices); + _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices); } } } @@ -171,7 +191,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor if (!meshes.is_empty()) { Ref<Mesh> mesh = meshes[1]; if (mesh.is_valid()) { - _add_mesh(mesh, p_accumulated_transform * csg_shape->get_transform(), p_vertices, p_indices); + _add_mesh(mesh, p_navmesh_transform * csg_shape->get_global_transform(), p_vertices, p_indices); } } } @@ -181,50 +201,48 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor StaticBody3D *static_body = Object::cast_to<StaticBody3D>(p_node); if (static_body->get_collision_layer() & p_collision_mask) { - for (int i = 0; i < p_node->get_child_count(); ++i) { - Node *child = p_node->get_child(i); - if (Object::cast_to<CollisionShape3D>(child)) { - CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child); - - Transform3D transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform(); + List<uint32_t> shape_owners; + static_body->get_shape_owners(&shape_owners); + for (uint32_t shape_owner : shape_owners) { + const int shape_count = static_body->shape_owner_get_shape_count(shape_owner); + for (int i = 0; i < shape_count; i++) { + Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i); + if (s.is_null()) { + continue; + } - Ref<Mesh> mesh; - Ref<Shape3D> s = col_shape->get_shape(); + const Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * static_body->shape_owner_get_transform(shape_owner); BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { - Ref<BoxMesh> box_mesh; - box_mesh.instantiate(); - box_mesh->set_size(box->get_size()); - mesh = box_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + BoxMesh::create_mesh_array(arr, box->get_size()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); if (capsule) { - Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instantiate(); - capsule_mesh->set_radius(capsule->get_radius()); - capsule_mesh->set_height(capsule->get_height()); - mesh = capsule_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s); if (cylinder) { - Ref<CylinderMesh> cylinder_mesh; - 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()); - mesh = cylinder_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s); if (sphere) { - Ref<SphereMesh> sphere_mesh; - sphere_mesh.instantiate(); - sphere_mesh->set_radius(sphere->get_radius()); - sphere_mesh->set_height(sphere->get_radius() * 2.0); - mesh = sphere_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0); + _add_mesh_array(arr, transform, p_vertices, p_indices); } ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s); @@ -255,37 +273,105 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor _add_faces(faces, transform, p_vertices, p_indices); } } - - if (mesh.is_valid()) { - _add_mesh(mesh, transform, p_vertices, p_indices); - } } } } } #ifdef MODULE_GRIDMAP_ENABLED - 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(); - 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 * (Transform3D)meshes[i], p_vertices, p_indices); + GridMap *gridmap = Object::cast_to<GridMap>(p_node); + + if (gridmap) { + if (p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { + Array meshes = gridmap->get_meshes(); + Transform3D xform = gridmap->get_global_transform(); + for (int i = 0; i < meshes.size(); i += 2) { + Ref<Mesh> mesh = meshes[i + 1]; + if (mesh.is_valid()) { + _add_mesh(mesh, p_navmesh_transform * xform * (Transform3D)meshes[i], p_vertices, p_indices); + } } } - } -#endif - if (Object::cast_to<Node3D>(p_node)) { - Node3D *spatial = Object::cast_to<Node3D>(p_node); - p_accumulated_transform = p_accumulated_transform * spatial->get_transform(); + if (p_generate_from != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES && (gridmap->get_collision_layer() & p_collision_mask)) { + Array shapes = gridmap->get_collision_shapes(); + for (int i = 0; i < shapes.size(); i += 2) { + RID shape = shapes[i + 1]; + PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape); + Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape); + + switch (type) { + case PhysicsServer3D::SHAPE_SPHERE: { + real_t radius = data; + Array arr; + arr.resize(RS::ARRAY_MAX); + SphereMesh::create_mesh_array(arr, radius, radius * 2.0); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); + } break; + case PhysicsServer3D::SHAPE_BOX: { + Vector3 extents = data; + Array arr; + arr.resize(RS::ARRAY_MAX); + BoxMesh::create_mesh_array(arr, extents * 2.0); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); + } break; + case PhysicsServer3D::SHAPE_CAPSULE: { + Dictionary dict = data; + real_t radius = dict["radius"]; + real_t height = dict["height"]; + Array arr; + arr.resize(RS::ARRAY_MAX); + CapsuleMesh::create_mesh_array(arr, radius, height); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); + } break; + case PhysicsServer3D::SHAPE_CYLINDER: { + Dictionary dict = data; + real_t radius = dict["radius"]; + real_t height = dict["height"]; + Array arr; + arr.resize(RS::ARRAY_MAX); + CylinderMesh::create_mesh_array(arr, radius, radius, height); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); + } break; + case PhysicsServer3D::SHAPE_CONVEX_POLYGON: { + PackedVector3Array vertices = data; + Geometry3D::MeshData md; + + Error err = ConvexHullComputer::convex_hull(vertices, md); + + if (err == OK) { + PackedVector3Array faces; + + for (int j = 0; j < md.faces.size(); ++j) { + Geometry3D::MeshData::Face face = md.faces[j]; + + for (int k = 2; k < face.indices.size(); ++k) { + faces.push_back(md.vertices[face.indices[0]]); + faces.push_back(md.vertices[face.indices[k - 1]]); + faces.push_back(md.vertices[face.indices[k]]); + } + } + + _add_faces(faces, shapes[i], p_vertices, p_indices); + } + } break; + case PhysicsServer3D::SHAPE_CONCAVE_POLYGON: { + Dictionary dict = data; + PackedVector3Array faces = Variant(dict["faces"]); + _add_faces(faces, shapes[i], p_vertices, p_indices); + } break; + default: { + WARN_PRINT("Unsupported collision shape type."); + } break; + } + } + } } +#endif if (p_recurse_children) { for (int i = 0; i < p_node->get_child_count(); i++) { - _parse_geometry(p_accumulated_transform, p_node->get_child(i), p_vertices, p_indices, p_generate_from, p_collision_mask, p_recurse_children); + _parse_geometry(p_navmesh_transform, p_node->get_child(i), p_vertices, p_indices, p_generate_from, p_collision_mask, p_recurse_children); } } } @@ -530,7 +616,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); } - Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse(); + Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_global_transform().affine_inverse(); for (Node *E : parse_nodes) { NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type(); uint32_t collision_mask = p_nav_mesh->get_collision_mask(); diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h index dac844c68e..8cc1531b53 100644 --- a/modules/navigation/navigation_mesh_generator.h +++ b/modules/navigation/navigation_mesh_generator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -51,8 +51,9 @@ protected: static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_vertices); static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); + static void _add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); - static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); + static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType 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/navigation/register_types.cpp b/modules/navigation/register_types.cpp index 97c01d42ab..62ae2c7f02 100644 --- a/modules/navigation/register_types.cpp +++ b/modules/navigation/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -40,7 +40,7 @@ #endif #ifdef TOOLS_ENABLED -#include "navigation_mesh_editor_plugin.h" +#include "editor/navigation_mesh_editor_plugin.h" #endif #ifndef _3D_DISABLED @@ -51,21 +51,29 @@ NavigationServer3D *new_server() { return memnew(GodotNavigationServer); } -void register_navigation_types() { - NavigationServer3DManager::set_default_server(new_server); +void initialize_navigation_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + NavigationServer3DManager::set_default_server(new_server); #ifndef _3D_DISABLED - _nav_mesh_generator = memnew(NavigationMeshGenerator); - GDREGISTER_CLASS(NavigationMeshGenerator); - Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton())); + _nav_mesh_generator = memnew(NavigationMeshGenerator); + GDREGISTER_CLASS(NavigationMeshGenerator); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton())); #endif + } #ifdef TOOLS_ENABLED - EditorPlugins::add_by_type<NavigationMeshEditorPlugin>(); + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + EditorPlugins::add_by_type<NavigationMeshEditorPlugin>(); + } #endif } -void unregister_navigation_types() { +void uninitialize_navigation_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } + #ifndef _3D_DISABLED if (_nav_mesh_generator) { memdelete(_nav_mesh_generator); diff --git a/modules/navigation/register_types.h b/modules/navigation/register_types.h index 4737c818eb..c4dbd19ed3 100644 --- a/modules/navigation/register_types.h +++ b/modules/navigation/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef NAVIGATION_REGISTER_TYPES_H #define NAVIGATION_REGISTER_TYPES_H -void register_navigation_types(); -void unregister_navigation_types(); +#include "modules/register_module_types.h" + +void initialize_navigation_module(ModuleInitializationLevel p_level); +void uninitialize_navigation_module(ModuleInitializationLevel p_level); #endif // NAVIGATION_REGISTER_TYPES_H diff --git a/modules/navigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp index 21e43d08c1..a6a5660c0c 100644 --- a/modules/navigation/rvo_agent.cpp +++ b/modules/navigation/rvo_agent.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,10 +32,6 @@ #include "nav_map.h" -/** - @author AndreaCatania -*/ - RvoAgent::RvoAgent() { callback.id = ObjectID(); } @@ -79,5 +75,5 @@ void RvoAgent::dispatch_callback() { const Variant *vp[2] = { &callback.new_velocity, &callback.udata }; int argc = (callback.udata.get_type() == Variant::NIL) ? 1 : 2; - obj->call(callback.method, vp, argc, responseCallError); + obj->callp(callback.method, vp, argc, responseCallError); } diff --git a/modules/navigation/rvo_agent.h b/modules/navigation/rvo_agent.h index 369cb1f9a3..54baab404e 100644 --- a/modules/navigation/rvo_agent.h +++ b/modules/navigation/rvo_agent.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,10 +36,6 @@ #include <Agent.h> -/** - @author AndreaCatania -*/ - class NavMap; class RvoAgent : public NavRid { diff --git a/modules/opensimplex/SCsub b/modules/noise/SCsub index 86d77c3dfb..1430aa0c4e 100644 --- a/modules/opensimplex/SCsub +++ b/modules/noise/SCsub @@ -3,21 +3,21 @@ Import("env") Import("env_modules") -env_opensimplex = env_modules.Clone() +env_noise = env_modules.Clone() # Thirdparty source files thirdparty_obj = [] -thirdparty_dir = "#thirdparty/misc/" +thirdparty_dir = "#thirdparty/noise/" thirdparty_sources = [ - "open-simplex-noise.c", + # Add C++ source files for noise modules here ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env_opensimplex.Prepend(CPPPATH=[thirdparty_dir]) +env_noise.Prepend(CPPPATH=[thirdparty_dir]) -env_thirdparty = env_opensimplex.Clone() +env_thirdparty = env_noise.Clone() env_thirdparty.disable_warnings() env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) env.modules_sources += thirdparty_obj @@ -26,7 +26,8 @@ env.modules_sources += thirdparty_obj module_obj = [] -env_opensimplex.add_source_files(module_obj, "*.cpp") +env_noise.add_source_files(module_obj, "*.cpp") +env_noise.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/modules/opensimplex/config.py b/modules/noise/config.py index 90b85dbd70..74db20f2a4 100644 --- a/modules/opensimplex/config.py +++ b/modules/noise/config.py @@ -8,8 +8,9 @@ def configure(env): def get_doc_classes(): return [ + "FastNoiseLite", + "Noise", "NoiseTexture", - "OpenSimplexNoise", ] diff --git a/modules/noise/doc_classes/FastNoiseLite.xml b/modules/noise/doc_classes/FastNoiseLite.xml new file mode 100644 index 0000000000..6ca4ba2d46 --- /dev/null +++ b/modules/noise/doc_classes/FastNoiseLite.xml @@ -0,0 +1,163 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="FastNoiseLite" inherits="Noise" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Generates noise using the FastNoiseLite library. + </brief_description> + <description> + This class generates noise using the FastNoiseLite library, which is a collection of several noise algorithms including Cellular, Perlin, Value, and more. + Most generated noise values are in the range of [code][-1,1][/code], however not always. Some of the cellular noise algorithms return results above [code]1[/code]. + </description> + <tutorials> + </tutorials> + <members> + <member name="cellular_distance_function" type="int" setter="set_cellular_distance_function" getter="get_cellular_distance_function" enum="FastNoiseLite.CellularDistanceFunction" default="0"> + Determines how the distance to the nearest/second-nearest point is computed. See [enum CellularDistanceFunction] for options. + </member> + <member name="cellular_jitter" type="float" setter="set_cellular_jitter" getter="get_cellular_jitter" default="0.45"> + Maximum distance a point can move off of its grid position. Set to [code]0[/code] for an even grid. + </member> + <member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="1"> + Return type from cellular noise calculations. See [enum CellularReturnType]. + </member> + <member name="domain_warp_amplitude" type="float" setter="set_domain_warp_amplitude" getter="get_domain_warp_amplitude" default="30.0"> + Sets the maximum warp distance from the origin. + </member> + <member name="domain_warp_enabled" type="bool" setter="set_domain_warp_enabled" getter="is_domain_warp_enabled" default="false"> + If enabled, another FastNoiseLite instance is used to warp the space, resulting in a distortion of the noise. + </member> + <member name="domain_warp_fractal_gain" type="float" setter="set_domain_warp_fractal_gain" getter="get_domain_warp_fractal_gain" default="0.5"> + Determines the strength of each subsequent layer of the noise which is used to warp the space. + A low value places more emphasis on the lower frequency base layers, while a high value puts more emphasis on the higher frequency layers. + </member> + <member name="domain_warp_fractal_lacunarity" type="float" setter="set_domain_warp_fractal_lacunarity" getter="get_domain_warp_fractal_lacunarity" default="6.0"> + Octave lacunarity of the fractal noise which warps the space. Increasing this value results in higher octaves producing noise with finer details and a rougher appearance. + </member> + <member name="domain_warp_fractal_octaves" type="int" setter="set_domain_warp_fractal_octaves" getter="get_domain_warp_fractal_octaves" default="5"> + The number of noise layers that are sampled to get the final value for the fractal noise which warps the space. + </member> + <member name="domain_warp_fractal_type" type="int" setter="set_domain_warp_fractal_type" getter="get_domain_warp_fractal_type" enum="FastNoiseLite.DomainWarpFractalType" default="1"> + The method for combining octaves into a fractal which is used to warp the space. See [enum DomainWarpFractalType]. + </member> + <member name="domain_warp_frequency" type="float" setter="set_domain_warp_frequency" getter="get_domain_warp_frequency" default="0.05"> + Frequency of the noise which warps the space. Low frequency results in smooth noise while high frequency results in rougher, more granular noise. + </member> + <member name="domain_warp_type" type="int" setter="set_domain_warp_type" getter="get_domain_warp_type" enum="FastNoiseLite.DomainWarpType" default="0"> + Sets the warp algorithm. See [enum DomainWarpType]. + </member> + <member name="fractal_gain" type="float" setter="set_fractal_gain" getter="get_fractal_gain" default="0.5"> + Determines the strength of each subsequent layer of noise in fractal noise. + A low value places more emphasis on the lower frequency base layers, while a high value puts more emphasis on the higher frequency layers. + </member> + <member name="fractal_lacunarity" type="float" setter="set_fractal_lacunarity" getter="get_fractal_lacunarity" default="2.0"> + Frequency multiplier between subsequent octaves. Increasing this value results in higher octaves producing noise with finer details and a rougher appearance. + </member> + <member name="fractal_octaves" type="int" setter="set_fractal_octaves" getter="get_fractal_octaves" default="5"> + The number of noise layers that are sampled to get the final value for fractal noise types. + </member> + <member name="fractal_ping_pong_strength" type="float" setter="set_fractal_ping_pong_strength" getter="get_fractal_ping_pong_strength" default="2.0"> + Sets the strength of the fractal ping pong type. + </member> + <member name="fractal_type" type="int" setter="set_fractal_type" getter="get_fractal_type" enum="FastNoiseLite.FractalType" default="1"> + The method for combining octaves into a fractal. See [enum FractalType]. + </member> + <member name="fractal_weighted_strength" type="float" setter="set_fractal_weighted_strength" getter="get_fractal_weighted_strength" default="0.0"> + Higher weighting means higher octaves have less impact if lower octaves have a large impact. + </member> + <member name="frequency" type="float" setter="set_frequency" getter="get_frequency" default="0.01"> + The frequency for all noise types. Low frequency results in smooth noise while high frequency results in rougher, more granular noise. + </member> + <member name="noise_type" type="int" setter="set_noise_type" getter="get_noise_type" enum="FastNoiseLite.NoiseType" default="1"> + The noise algorithm used. See [enum NoiseType]. + </member> + <member name="offset" type="Vector3" setter="set_offset" getter="get_offset" default="Vector3(0, 0, 0)"> + Translate the noise input coordinates by the given [Vector3]. + </member> + <member name="seed" type="int" setter="set_seed" getter="get_seed" default="0"> + The random number seed for all noise types. + </member> + </members> + <constants> + <constant name="TYPE_VALUE" value="5" enum="NoiseType"> + A lattice of points are assigned random values then interpolated based on neighboring values. + </constant> + <constant name="TYPE_VALUE_CUBIC" value="4" enum="NoiseType"> + Similar to Value noise, but slower. Has more variance in peaks and valleys. + Cubic noise can be used to avoid certain artifacts when using value noise to create a bumpmap. In general, you should always use this mode if the value noise is being used for a heightmap or bumpmap. + </constant> + <constant name="TYPE_PERLIN" value="3" enum="NoiseType"> + A lattice of random gradients. Their dot products are interpolated to obtain values in between the lattices. + </constant> + <constant name="TYPE_CELLULAR" value="2" enum="NoiseType"> + Cellular includes both Worley noise and Voronoi diagrams which creates various regions of the same value. + </constant> + <constant name="TYPE_SIMPLEX" value="0" enum="NoiseType"> + As opposed to [constant TYPE_PERLIN], gradients exist in a simplex lattice rather than a grid lattice, avoiding directional artifacts. + </constant> + <constant name="TYPE_SIMPLEX_SMOOTH" value="1" enum="NoiseType"> + Modified, higher quality version of [constant TYPE_SIMPLEX], but slower. + </constant> + <constant name="FRACTAL_NONE" value="0" enum="FractalType"> + No fractal noise. + </constant> + <constant name="FRACTAL_FBM" value="1" enum="FractalType"> + Method using Fractional Brownian Motion to combine octaves into a fractal. + </constant> + <constant name="FRACTAL_RIDGED" value="2" enum="FractalType"> + Method of combining octaves into a fractal resulting in a "ridged" look. + </constant> + <constant name="FRACTAL_PING_PONG" value="3" enum="FractalType"> + Method of combining octaves into a fractal with a ping pong effect. + </constant> + <constant name="DISTANCE_EUCLIDEAN" value="0" enum="CellularDistanceFunction"> + Euclidean distance to the nearest point. + </constant> + <constant name="DISTANCE_EUCLIDEAN_SQUARED" value="1" enum="CellularDistanceFunction"> + Squared Euclidean distance to the nearest point. + </constant> + <constant name="DISTANCE_MANHATTAN" value="2" enum="CellularDistanceFunction"> + Manhattan distance (taxicab metric) to the nearest point. + </constant> + <constant name="DISTANCE_HYBRID" value="3" enum="CellularDistanceFunction"> + Blend of [constant DISTANCE_EUCLIDEAN] and [constant DISTANCE_MANHATTAN] to give curved cell boundaries + </constant> + <constant name="RETURN_CELL_VALUE" value="0" enum="CellularReturnType"> + The cellular distance function will return the same value for all points within a cell. + </constant> + <constant name="RETURN_DISTANCE" value="1" enum="CellularReturnType"> + The cellular distance function will return a value determined by the distance to the nearest point. + </constant> + <constant name="RETURN_DISTANCE2" value="2" enum="CellularReturnType"> + The cellular distance function returns the distance to the second-nearest point. + </constant> + <constant name="RETURN_DISTANCE2_ADD" value="3" enum="CellularReturnType"> + The distance to the nearest point is added to the distance to the second-nearest point. + </constant> + <constant name="RETURN_DISTANCE2_SUB" value="4" enum="CellularReturnType"> + The distance to the nearest point is subtracted from the distance to the second-nearest point. + </constant> + <constant name="RETURN_DISTANCE2_MUL" value="5" enum="CellularReturnType"> + The distance to the nearest point is multiplied with the distance to the second-nearest point. + </constant> + <constant name="RETURN_DISTANCE2_DIV" value="6" enum="CellularReturnType"> + The distance to the nearest point is divided by the distance to the second-nearest point. + </constant> + <constant name="DOMAIN_WARP_SIMPLEX" value="0" enum="DomainWarpType"> + The domain is warped using the simplex noise algorithm. + </constant> + <constant name="DOMAIN_WARP_SIMPLEX_REDUCED" value="1" enum="DomainWarpType"> + The domain is warped using a simplified version of the simplex noise algorithm. + </constant> + <constant name="DOMAIN_WARP_BASIC_GRID" value="2" enum="DomainWarpType"> + The domain is warped using a simple noise grid (not as smooth as the other methods, but more performant). + </constant> + <constant name="DOMAIN_WARP_FRACTAL_NONE" value="0" enum="DomainWarpFractalType"> + No fractal noise for warping the space. + </constant> + <constant name="DOMAIN_WARP_FRACTAL_PROGRESSIVE" value="1" enum="DomainWarpFractalType"> + Warping the space progressively, octave for octave, resulting in a more "liquified" distortion. + </constant> + <constant name="DOMAIN_WARP_FRACTAL_INDEPENDENT" value="2" enum="DomainWarpFractalType"> + Warping the space independently for each octave, resulting in a more chaotic distortion. + </constant> + </constants> +</class> diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml new file mode 100644 index 0000000000..5af204575c --- /dev/null +++ b/modules/noise/doc_classes/Noise.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="Noise" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Abstract base class for noise generators. + </brief_description> + <description> + This class defines the interface for noise generation libraries to inherit from. + A default get_seamless_noise() implementation is provided for libraries that do not provide seamless noise. This function requests a larger image from get_image(), reverses the quadrants of the image, then uses the strips of extra width to blend over the seams. + Inheriting noise classes can optionally override this function to provide a more optimal algorithm. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_image" qualifiers="const"> + <return type="Image" /> + <argument index="0" name="width" type="int" /> + <argument index="1" name="height" type="int" /> + <argument index="2" name="invert" type="bool" default="false" /> + <argument index="3" name="in_3d_space" type="bool" default="false" /> + <description> + Returns a 2D [Image] noise image. + </description> + </method> + <method name="get_noise_1d" qualifiers="const"> + <return type="float" /> + <argument index="0" name="x" type="float" /> + <description> + Returns the 1D noise value at the given (x) coordinate. + </description> + </method> + <method name="get_noise_2d" qualifiers="const"> + <return type="float" /> + <argument index="0" name="x" type="float" /> + <argument index="1" name="y" type="float" /> + <description> + Returns the 2D noise value at the given position. + </description> + </method> + <method name="get_noise_2dv" qualifiers="const"> + <return type="float" /> + <argument index="0" name="v" type="Vector2" /> + <description> + Returns the 2D noise value at the given position. + </description> + </method> + <method name="get_noise_3d" qualifiers="const"> + <return type="float" /> + <argument index="0" name="x" type="float" /> + <argument index="1" name="y" type="float" /> + <argument index="2" name="z" type="float" /> + <description> + Returns the 3D noise value at the given position. + </description> + </method> + <method name="get_noise_3dv" qualifiers="const"> + <return type="float" /> + <argument index="0" name="v" type="Vector3" /> + <description> + Returns the 3D noise value at the given position. + </description> + </method> + <method name="get_seamless_image" qualifiers="const"> + <return type="Image" /> + <argument index="0" name="width" type="int" /> + <argument index="1" name="height" type="int" /> + <argument index="2" name="invert" type="bool" default="false" /> + <argument index="3" name="in_3d_space" type="bool" default="false" /> + <argument index="4" name="skirt" type="float" default="0.1" /> + <description> + Returns a seamless 2D [Image] noise image. + </description> + </method> + </methods> +</class> diff --git a/modules/noise/doc_classes/NoiseTexture.xml b/modules/noise/doc_classes/NoiseTexture.xml new file mode 100644 index 0000000000..62a223b387 --- /dev/null +++ b/modules/noise/doc_classes/NoiseTexture.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="NoiseTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + A texture filled with noise generated by a [Noise] object. + </brief_description> + <description> + Uses [FastNoiseLite] or other libraries to fill the texture data of your desired size. + NoiseTexture can also generate normalmap textures. + 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 = NoiseTexture.new() + texture.noise = FastNoiseLite.new() + await texture.changed + var image = texture.get_image() + var data = image.get_data() + [/codeblock] + </description> + <tutorials> + </tutorials> + <members> + <member name="as_normal_map" type="bool" setter="set_as_normal_map" getter="is_normal_map" default="false"> + If [code]true[/code], the resulting texture contains a normal map created from the original noise interpreted as a bump map. + </member> + <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0"> + Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer. + </member> + <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> + A [Gradient] which is used to map the luminance of each pixel to a color value. + </member> + <member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="is_generating_mipmaps" default="true"> + Determines whether mipmaps are generated for this texture. + Enabling this results in less texture aliasing, but the noise texture generation may take longer. + Requires (anisotropic) mipmap filtering to be enabled for a material to have an effect. + </member> + <member name="height" type="int" setter="set_height" getter="get_height" default="512"> + Height of the generated texture. + </member> + <member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false"> + Determines whether the noise image is calculated in 3D space. May result in reduced contrast. + </member> + <member name="invert" type="bool" setter="set_invert" getter="get_invert" default="false"> + If [code]true[/code], inverts the noise texture. White becomes black, black becomes white. + </member> + <member name="noise" type="Noise" setter="set_noise" getter="get_noise"> + The instance of the [Noise] object. + </member> + <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false"> + If [code]true[/code], a seamless texture is requested from the [Noise] resource. + [b]Note:[/b] Seamless noise textures may take longer to generate and/or can have a lower contrast compared to non-seamless noise depending on the used [Noise] resource. This is because some implementations use higher dimensions for generating seamless noise. + </member> + <member name="seamless_blend_skirt" type="float" setter="set_seamless_blend_skirt" getter="get_seamless_blend_skirt" default="0.1"> + Used for the default/fallback implementation of the seamless texture generation. It determines the distance over which the seams are blended. High values may result in less details and contrast. See [Noise] for further details. + </member> + <member name="width" type="int" setter="set_width" getter="get_width" default="512"> + Width of the generated texture. + </member> + </members> +</class> diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp new file mode 100644 index 0000000000..32c3f0aad4 --- /dev/null +++ b/modules/noise/editor/noise_editor_plugin.cpp @@ -0,0 +1,149 @@ +/*************************************************************************/ +/* noise_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "noise_editor_plugin.h" + +#ifdef TOOLS_ENABLED + +#include "editor/editor_scale.h" + +#include "modules/noise/noise.h" +#include "modules/noise/noise_texture.h" + +class NoisePreview : public Control { + GDCLASS(NoisePreview, Control) + + static const int PREVIEW_HEIGHT = 150; + static const int PADDING_3D_SPACE_SWITCH = 2; + + Ref<Noise> _noise; + Size2i _preview_texture_size; + + TextureRect *_texture_rect = nullptr; + Button *_3d_space_switch = nullptr; + +public: + NoisePreview() { + set_custom_minimum_size(Size2(0, EDSCALE * PREVIEW_HEIGHT)); + + _texture_rect = memnew(TextureRect); + _texture_rect->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + _texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED); + add_child(_texture_rect); + + _3d_space_switch = memnew(Button); + _3d_space_switch->set_text(TTR("3D")); + _3d_space_switch->set_tooltip(TTR("Toggles whether the noise preview is computed in 3D space.")); + _3d_space_switch->set_toggle_mode(true); + _3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH); + _3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH); + _3d_space_switch->connect("pressed", callable_mp(this, &NoisePreview::_on_3d_button_pressed)); + add_child(_3d_space_switch); + } + + void set_noise(Ref<Noise> noise) { + if (_noise == noise) { + return; + } + _noise = noise; + if (_noise.is_valid()) { + if (_noise->has_meta("_preview_in_3d_space_")) { + _3d_space_switch->set_pressed(true); + } + + update_preview(); + } + } + +private: + void _on_3d_button_pressed() { + if (_3d_space_switch->is_pressed()) { + _noise->set_meta("_preview_in_3d_space_", true); + } else { + _noise->remove_meta("_preview_in_3d_space_"); + } + } + + void _notification(int p_what) { + switch (p_what) { + case NOTIFICATION_RESIZED: { + _preview_texture_size = get_size(); + update_preview(); + } break; + } + } + + void update_preview() { + if (MIN(_preview_texture_size.width, _preview_texture_size.height) > 0) { + Ref<NoiseTexture> tex; + tex.instantiate(); + tex->set_width(_preview_texture_size.width); + tex->set_height(_preview_texture_size.height); + tex->set_in_3d_space(_3d_space_switch->is_pressed()); + tex->set_noise(_noise); + _texture_rect->set_texture(tex); + } + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +class NoiseEditorInspectorPlugin : public EditorInspectorPlugin { + GDCLASS(NoiseEditorInspectorPlugin, EditorInspectorPlugin) +public: + bool can_handle(Object *p_object) override { + return Object::cast_to<Noise>(p_object) != nullptr; + } + + void parse_begin(Object *p_object) override { + Noise *noise_ptr = Object::cast_to<Noise>(p_object); + if (noise_ptr) { + Ref<Noise> noise(noise_ptr); + + NoisePreview *viewer = memnew(NoisePreview); + viewer->set_noise(noise); + add_custom_control(viewer); + } + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +String NoiseEditorPlugin::get_name() const { + return Noise::get_class_static(); +} + +NoiseEditorPlugin::NoiseEditorPlugin() { + Ref<NoiseEditorInspectorPlugin> plugin; + plugin.instantiate(); + add_inspector_plugin(plugin); +} + +#endif // TOOLS_ENABLED diff --git a/modules/bullet/joint_bullet.cpp b/modules/noise/editor/noise_editor_plugin.h index ac371658f5..55a01deb2d 100644 --- a/modules/bullet/joint_bullet.cpp +++ b/modules/noise/editor/noise_editor_plugin.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* joint_bullet.cpp */ +/* noise_editor_plugin.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,15 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "joint_bullet.h" +#ifndef NOISE_EDITOR_PLUGIN_H +#define NOISE_EDITOR_PLUGIN_H -#include "space_bullet.h" +#ifdef TOOLS_ENABLED -/** - @author AndreaCatania -*/ +#include "editor/editor_plugin.h" -JointBullet::JointBullet() : - ConstraintBullet() {} +class NoiseEditorPlugin : public EditorPlugin { + GDCLASS(NoiseEditorPlugin, EditorPlugin) -JointBullet::~JointBullet() {} +public: + String get_name() const override; + + NoiseEditorPlugin(); +}; + +#endif // TOOLS_ENABLED + +#endif // NOISE_EDITOR_PLUGIN_H diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp new file mode 100644 index 0000000000..a8d38dee62 --- /dev/null +++ b/modules/noise/fastnoise_lite.cpp @@ -0,0 +1,486 @@ +/*************************************************************************/ +/* fastnoise_lite.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "fastnoise_lite.h" + +FastNoiseLite::FastNoiseLite() { + _noise.SetNoiseType((_FastNoiseLite::NoiseType)noise_type); + _noise.SetSeed(seed); + _noise.SetFrequency(frequency); + + _noise.SetFractalType((_FastNoiseLite::FractalType)fractal_type); + _noise.SetFractalOctaves(fractal_octaves); + _noise.SetFractalLacunarity(fractal_lacunarity); + _noise.SetFractalGain(fractal_gain); + _noise.SetFractalWeightedStrength(fractal_weighted_strength); + _noise.SetFractalPingPongStrength(fractal_ping_pong_strength); + + _noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)cellular_distance_function); + _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)cellular_return_type); + _noise.SetCellularJitter(cellular_jitter); + + _domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)domain_warp_type); + _domain_warp_noise.SetSeed(seed); + _domain_warp_noise.SetDomainWarpAmp(domain_warp_amplitude); + _domain_warp_noise.SetFrequency(domain_warp_frequency); + _domain_warp_noise.SetFractalType(_FastNoiseLite::FractalType_None); + _domain_warp_noise.SetFractalOctaves(domain_warp_fractal_octaves); + _domain_warp_noise.SetFractalLacunarity(domain_warp_fractal_lacunarity); + _domain_warp_noise.SetFractalGain(domain_warp_fractal_gain); +} + +FastNoiseLite::~FastNoiseLite() { +} + +// General settings. + +void FastNoiseLite::set_noise_type(NoiseType p_noise_type) { + noise_type = p_noise_type; + _noise.SetNoiseType((_FastNoiseLite::NoiseType)p_noise_type); + emit_changed(); + notify_property_list_changed(); +} + +FastNoiseLite::NoiseType FastNoiseLite::get_noise_type() const { + return noise_type; +} + +void FastNoiseLite::set_seed(int p_seed) { + seed = p_seed; + _noise.SetSeed(p_seed); + _domain_warp_noise.SetSeed(p_seed); + emit_changed(); +} + +int FastNoiseLite::get_seed() const { + return seed; +} + +void FastNoiseLite::set_frequency(real_t p_freq) { + frequency = p_freq; + _noise.SetFrequency(p_freq); + emit_changed(); +} + +real_t FastNoiseLite::get_frequency() const { + return frequency; +} + +void FastNoiseLite::set_offset(Vector3 p_offset) { + offset = p_offset; + emit_changed(); +} + +Vector3 FastNoiseLite::get_offset() const { + return offset; +} + +// Fractal. + +void FastNoiseLite::set_fractal_type(FractalType p_type) { + fractal_type = p_type; + _noise.SetFractalType((_FastNoiseLite::FractalType)p_type); + emit_changed(); + notify_property_list_changed(); +} + +FastNoiseLite::FractalType FastNoiseLite::get_fractal_type() const { + return fractal_type; +} + +void FastNoiseLite::set_fractal_octaves(int p_octaves) { + fractal_octaves = p_octaves; + _noise.SetFractalOctaves(p_octaves); + emit_changed(); +} + +int FastNoiseLite::get_fractal_octaves() const { + return fractal_octaves; +} + +void FastNoiseLite::set_fractal_lacunarity(real_t p_lacunarity) { + fractal_lacunarity = p_lacunarity; + _noise.SetFractalLacunarity(p_lacunarity); + emit_changed(); +} + +real_t FastNoiseLite::get_fractal_lacunarity() const { + return fractal_lacunarity; +} + +void FastNoiseLite::set_fractal_gain(real_t p_gain) { + fractal_gain = p_gain; + _noise.SetFractalGain(p_gain); + emit_changed(); +} + +real_t FastNoiseLite::get_fractal_gain() const { + return fractal_gain; +} + +void FastNoiseLite::set_fractal_weighted_strength(real_t p_weighted_strength) { + fractal_weighted_strength = p_weighted_strength; + _noise.SetFractalWeightedStrength(p_weighted_strength); + emit_changed(); +} +real_t FastNoiseLite::get_fractal_weighted_strength() const { + return fractal_weighted_strength; +} + +void FastNoiseLite::set_fractal_ping_pong_strength(real_t p_ping_pong_strength) { + fractal_ping_pong_strength = p_ping_pong_strength; + _noise.SetFractalPingPongStrength(p_ping_pong_strength); + emit_changed(); +} +real_t FastNoiseLite::get_fractal_ping_pong_strength() const { + return fractal_ping_pong_strength; +} + +// Cellular. + +void FastNoiseLite::set_cellular_distance_function(CellularDistanceFunction p_func) { + cellular_distance_function = p_func; + _noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)p_func); + emit_changed(); +} + +FastNoiseLite::CellularDistanceFunction FastNoiseLite::get_cellular_distance_function() const { + return cellular_distance_function; +} + +void FastNoiseLite::set_cellular_jitter(real_t p_jitter) { + cellular_jitter = p_jitter; + _noise.SetCellularJitter(p_jitter); + emit_changed(); +} + +real_t FastNoiseLite::get_cellular_jitter() const { + return cellular_jitter; +} + +void FastNoiseLite::set_cellular_return_type(CellularReturnType p_ret) { + cellular_return_type = p_ret; + _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)p_ret); + emit_changed(); +} + +FastNoiseLite::CellularReturnType FastNoiseLite::get_cellular_return_type() const { + return cellular_return_type; +} + +// Domain warp specific. + +void FastNoiseLite::set_domain_warp_enabled(bool p_enabled) { + if (domain_warp_enabled != p_enabled) { + domain_warp_enabled = p_enabled; + emit_changed(); + notify_property_list_changed(); + } +} + +bool FastNoiseLite::is_domain_warp_enabled() const { + return domain_warp_enabled; +} + +void FastNoiseLite::set_domain_warp_type(DomainWarpType p_domain_warp_type) { + domain_warp_type = p_domain_warp_type; + _domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)p_domain_warp_type); + emit_changed(); +} + +FastNoiseLite::DomainWarpType FastNoiseLite::get_domain_warp_type() const { + return domain_warp_type; +} + +void FastNoiseLite::set_domain_warp_amplitude(real_t p_amplitude) { + domain_warp_amplitude = p_amplitude; + _domain_warp_noise.SetDomainWarpAmp(p_amplitude); + emit_changed(); +} +real_t FastNoiseLite::get_domain_warp_amplitude() const { + return domain_warp_amplitude; +} + +void FastNoiseLite::set_domain_warp_frequency(real_t p_frequency) { + domain_warp_frequency = p_frequency; + _domain_warp_noise.SetFrequency(p_frequency); + emit_changed(); +} + +real_t FastNoiseLite::get_domain_warp_frequency() const { + return domain_warp_frequency; +} + +void FastNoiseLite::set_domain_warp_fractal_type(DomainWarpFractalType p_domain_warp_fractal_type) { + domain_warp_fractal_type = p_domain_warp_fractal_type; + + // This needs manual conversion because Godots Inspector property API does not support discontiguous enum indices. + _FastNoiseLite::FractalType type; + switch (p_domain_warp_fractal_type) { + case DOMAIN_WARP_FRACTAL_NONE: + type = _FastNoiseLite::FractalType_None; + break; + case DOMAIN_WARP_FRACTAL_PROGRESSIVE: + type = _FastNoiseLite::FractalType_DomainWarpProgressive; + break; + case DOMAIN_WARP_FRACTAL_INDEPENDENT: + type = _FastNoiseLite::FractalType_DomainWarpIndependent; + break; + default: + type = _FastNoiseLite::FractalType_None; + } + + _domain_warp_noise.SetFractalType(type); + emit_changed(); +} + +FastNoiseLite::DomainWarpFractalType FastNoiseLite::get_domain_warp_fractal_type() const { + return domain_warp_fractal_type; +} + +void FastNoiseLite::set_domain_warp_fractal_octaves(int p_octaves) { + domain_warp_fractal_octaves = p_octaves; + _domain_warp_noise.SetFractalOctaves(p_octaves); + emit_changed(); +} + +int FastNoiseLite::get_domain_warp_fractal_octaves() const { + return domain_warp_fractal_octaves; +} + +void FastNoiseLite::set_domain_warp_fractal_lacunarity(real_t p_lacunarity) { + domain_warp_fractal_lacunarity = p_lacunarity; + _domain_warp_noise.SetFractalLacunarity(p_lacunarity); + emit_changed(); +} + +real_t FastNoiseLite::get_domain_warp_fractal_lacunarity() const { + return domain_warp_fractal_lacunarity; +} + +void FastNoiseLite::set_domain_warp_fractal_gain(real_t p_gain) { + domain_warp_fractal_gain = p_gain; + _domain_warp_noise.SetFractalGain(p_gain); + emit_changed(); +} + +real_t FastNoiseLite::get_domain_warp_fractal_gain() const { + return domain_warp_fractal_gain; +} + +// Noise interface functions. + +real_t FastNoiseLite::get_noise_1d(real_t p_x) const { + return get_noise_2d(p_x, 0.0); +} + +real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const { + return get_noise_2d(p_v.x, p_v.y); +} + +real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const { + if (domain_warp_enabled) { + _domain_warp_noise.DomainWarp(p_x, p_y); + } + return _noise.GetNoise(p_x + offset.x, p_y + offset.y); +} + +real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const { + return get_noise_3d(p_v.x, p_v.y, p_v.z); +} + +real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const { + if (domain_warp_enabled) { + _domain_warp_noise.DomainWarp(p_x, p_y, p_z); + } + return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z); +} + +void FastNoiseLite::_changed() { + emit_changed(); +} + +void FastNoiseLite::_bind_methods() { + // General settings. + + ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoiseLite::set_noise_type); + ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoiseLite::get_noise_type); + + ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLite::set_seed); + ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLite::get_seed); + + ClassDB::bind_method(D_METHOD("set_frequency", "freq"), &FastNoiseLite::set_frequency); + ClassDB::bind_method(D_METHOD("get_frequency"), &FastNoiseLite::get_frequency); + + ClassDB::bind_method(D_METHOD("set_offset", "offset"), &FastNoiseLite::set_offset); + ClassDB::bind_method(D_METHOD("get_offset"), &FastNoiseLite::get_offset); + + // Fractal. + + ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoiseLite::set_fractal_type); + ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoiseLite::get_fractal_type); + + ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octave_count"), &FastNoiseLite::set_fractal_octaves); + ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLite::get_fractal_octaves); + + ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"), &FastNoiseLite::set_fractal_lacunarity); + ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoiseLite::get_fractal_lacunarity); + + ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoiseLite::set_fractal_gain); + ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoiseLite::get_fractal_gain); + + ClassDB::bind_method(D_METHOD("set_fractal_weighted_strength", "weighted_strength"), &FastNoiseLite::set_fractal_weighted_strength); + ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoiseLite::get_fractal_weighted_strength); + + ClassDB::bind_method(D_METHOD("set_fractal_ping_pong_strength", "ping_pong_strength"), &FastNoiseLite::set_fractal_ping_pong_strength); + ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoiseLite::get_fractal_ping_pong_strength); + + // Cellular. + + ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "func"), &FastNoiseLite::set_cellular_distance_function); + ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoiseLite::get_cellular_distance_function); + + ClassDB::bind_method(D_METHOD("set_cellular_jitter", "jitter"), &FastNoiseLite::set_cellular_jitter); + ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoiseLite::get_cellular_jitter); + + ClassDB::bind_method(D_METHOD("set_cellular_return_type", "ret"), &FastNoiseLite::set_cellular_return_type); + ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoiseLite::get_cellular_return_type); + + // Domain warp. + + ClassDB::bind_method(D_METHOD("set_domain_warp_enabled", "domain_warp_enabled"), &FastNoiseLite::set_domain_warp_enabled); + ClassDB::bind_method(D_METHOD("is_domain_warp_enabled"), &FastNoiseLite::is_domain_warp_enabled); + + ClassDB::bind_method(D_METHOD("set_domain_warp_type", "domain_warp_type"), &FastNoiseLite::set_domain_warp_type); + ClassDB::bind_method(D_METHOD("get_domain_warp_type"), &FastNoiseLite::get_domain_warp_type); + + ClassDB::bind_method(D_METHOD("set_domain_warp_amplitude", "domain_warp_amplitude"), &FastNoiseLite::set_domain_warp_amplitude); + ClassDB::bind_method(D_METHOD("get_domain_warp_amplitude"), &FastNoiseLite::get_domain_warp_amplitude); + + ClassDB::bind_method(D_METHOD("set_domain_warp_frequency", "domain_warp_frequency"), &FastNoiseLite::set_domain_warp_frequency); + ClassDB::bind_method(D_METHOD("get_domain_warp_frequency"), &FastNoiseLite::get_domain_warp_frequency); + + ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_type", "domain_warp_fractal_type"), &FastNoiseLite::set_domain_warp_fractal_type); + ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_type"), &FastNoiseLite::get_domain_warp_fractal_type); + + ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_octaves", "domain_warp_octave_count"), &FastNoiseLite::set_domain_warp_fractal_octaves); + ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_octaves"), &FastNoiseLite::get_domain_warp_fractal_octaves); + + ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_lacunarity", "domain_warp_lacunarity"), &FastNoiseLite::set_domain_warp_fractal_lacunarity); + ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_lacunarity"), &FastNoiseLite::get_domain_warp_fractal_lacunarity); + + ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_gain", "domain_warp_gain"), &FastNoiseLite::set_domain_warp_fractal_gain); + ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_gain"), &FastNoiseLite::get_domain_warp_fractal_gain); + + ClassDB::bind_method(D_METHOD("_changed"), &FastNoiseLite::_changed); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset"); + + ADD_GROUP("Fractal", "fractal_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength"); + + ADD_GROUP("Cellular", "cellular_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type"); + + ADD_GROUP("Domain Warp", "domain_warp_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain"); + + BIND_ENUM_CONSTANT(TYPE_VALUE); + BIND_ENUM_CONSTANT(TYPE_VALUE_CUBIC); + BIND_ENUM_CONSTANT(TYPE_PERLIN); + BIND_ENUM_CONSTANT(TYPE_CELLULAR); + BIND_ENUM_CONSTANT(TYPE_SIMPLEX); + BIND_ENUM_CONSTANT(TYPE_SIMPLEX_SMOOTH); + + BIND_ENUM_CONSTANT(FRACTAL_NONE); + BIND_ENUM_CONSTANT(FRACTAL_FBM); + BIND_ENUM_CONSTANT(FRACTAL_RIDGED); + BIND_ENUM_CONSTANT(FRACTAL_PING_PONG); + + BIND_ENUM_CONSTANT(DISTANCE_EUCLIDEAN); + BIND_ENUM_CONSTANT(DISTANCE_EUCLIDEAN_SQUARED); + BIND_ENUM_CONSTANT(DISTANCE_MANHATTAN); + BIND_ENUM_CONSTANT(DISTANCE_HYBRID); + + BIND_ENUM_CONSTANT(RETURN_CELL_VALUE); + BIND_ENUM_CONSTANT(RETURN_DISTANCE); + BIND_ENUM_CONSTANT(RETURN_DISTANCE2); + BIND_ENUM_CONSTANT(RETURN_DISTANCE2_ADD); + BIND_ENUM_CONSTANT(RETURN_DISTANCE2_SUB); + BIND_ENUM_CONSTANT(RETURN_DISTANCE2_MUL); + BIND_ENUM_CONSTANT(RETURN_DISTANCE2_DIV); + + BIND_ENUM_CONSTANT(DOMAIN_WARP_SIMPLEX); + BIND_ENUM_CONSTANT(DOMAIN_WARP_SIMPLEX_REDUCED); + BIND_ENUM_CONSTANT(DOMAIN_WARP_BASIC_GRID); + + BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_NONE); + BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_PROGRESSIVE); + BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_INDEPENDENT); +} + +void FastNoiseLite::_validate_property(PropertyInfo &property) const { + if (property.name.begins_with("cellular") && get_noise_type() != TYPE_CELLULAR) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + return; + } + + if (property.name != "fractal_type" && property.name.begins_with("fractal") && get_fractal_type() == FRACTAL_NONE) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + return; + } + + if (property.name == "fractal_ping_pong_strength" && get_fractal_type() != FRACTAL_PING_PONG) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + return; + } + + if (property.name != "domain_warp_enabled" && property.name.begins_with("domain_warp") && !domain_warp_enabled) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + return; + } +} diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h new file mode 100644 index 0000000000..0a4251868b --- /dev/null +++ b/modules/noise/fastnoise_lite.h @@ -0,0 +1,224 @@ +/*************************************************************************/ +/* fastnoise_lite.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 FASTNOISE_LITE_H +#define FASTNOISE_LITE_H + +#include "core/io/image.h" +#include "core/object/ref_counted.h" +#include "noise.h" +#include "scene/resources/gradient.h" + +#include <thirdparty/noise/FastNoiseLite.h> + +typedef fastnoiselite::FastNoiseLite _FastNoiseLite; + +class FastNoiseLite : public Noise { + GDCLASS(FastNoiseLite, Noise); + OBJ_SAVE_TYPE(FastNoiseLite); + +public: + enum NoiseType { + TYPE_SIMPLEX = _FastNoiseLite::NoiseType_OpenSimplex2, + TYPE_SIMPLEX_SMOOTH = _FastNoiseLite::NoiseType_OpenSimplex2S, + TYPE_CELLULAR = _FastNoiseLite::NoiseType_Cellular, + TYPE_PERLIN = _FastNoiseLite::NoiseType_Perlin, + TYPE_VALUE_CUBIC = _FastNoiseLite::NoiseType_ValueCubic, + TYPE_VALUE = _FastNoiseLite::NoiseType_Value, + }; + + enum FractalType { + FRACTAL_NONE = _FastNoiseLite::FractalType_None, + FRACTAL_FBM = _FastNoiseLite::FractalType_FBm, + FRACTAL_RIDGED = _FastNoiseLite::FractalType_Ridged, + FRACTAL_PING_PONG = _FastNoiseLite::FractalType_PingPong, + }; + + enum CellularDistanceFunction { + DISTANCE_EUCLIDEAN = _FastNoiseLite::CellularDistanceFunction_Euclidean, + DISTANCE_EUCLIDEAN_SQUARED = _FastNoiseLite::CellularDistanceFunction_EuclideanSq, + DISTANCE_MANHATTAN = _FastNoiseLite::CellularDistanceFunction_Manhattan, + DISTANCE_HYBRID = _FastNoiseLite::CellularDistanceFunction_Hybrid + }; + + enum CellularReturnType { + RETURN_CELL_VALUE = _FastNoiseLite::CellularReturnType_CellValue, + RETURN_DISTANCE = _FastNoiseLite::CellularReturnType_Distance, + RETURN_DISTANCE2 = _FastNoiseLite::CellularReturnType_Distance2, + RETURN_DISTANCE2_ADD = _FastNoiseLite::CellularReturnType_Distance2Add, + RETURN_DISTANCE2_SUB = _FastNoiseLite::CellularReturnType_Distance2Sub, + RETURN_DISTANCE2_MUL = _FastNoiseLite::CellularReturnType_Distance2Mul, + RETURN_DISTANCE2_DIV = _FastNoiseLite::CellularReturnType_Distance2Div + }; + + enum DomainWarpType { + DOMAIN_WARP_SIMPLEX = _FastNoiseLite::DomainWarpType_OpenSimplex2, + DOMAIN_WARP_SIMPLEX_REDUCED = _FastNoiseLite::DomainWarpType_OpenSimplex2Reduced, + DOMAIN_WARP_BASIC_GRID = _FastNoiseLite::DomainWarpType_BasicGrid + }; + + enum DomainWarpFractalType { + DOMAIN_WARP_FRACTAL_NONE, + DOMAIN_WARP_FRACTAL_PROGRESSIVE, + DOMAIN_WARP_FRACTAL_INDEPENDENT + }; + +protected: + static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const override; + +private: + _FastNoiseLite _noise; + _FastNoiseLite _domain_warp_noise; + + Vector3 offset; + NoiseType noise_type = TYPE_SIMPLEX_SMOOTH; + + int seed = 0; + real_t frequency = 0.01; + + // Fractal specific. + FractalType fractal_type = FRACTAL_FBM; + int fractal_octaves = 5; + real_t fractal_lacunarity = 2; + real_t fractal_gain = 0.5; + real_t fractal_weighted_strength = 0; + real_t fractal_ping_pong_strength = 2; + + // Cellular specific. + CellularDistanceFunction cellular_distance_function = DISTANCE_EUCLIDEAN; + CellularReturnType cellular_return_type = RETURN_DISTANCE; + real_t cellular_jitter = 0.45; + + // Domain warp specific. + bool domain_warp_enabled = false; + DomainWarpType domain_warp_type = DOMAIN_WARP_SIMPLEX; + real_t domain_warp_amplitude = 30.0; + real_t domain_warp_frequency = 0.05; + DomainWarpFractalType domain_warp_fractal_type = DOMAIN_WARP_FRACTAL_PROGRESSIVE; + int domain_warp_fractal_octaves = 5; + real_t domain_warp_fractal_lacunarity = 6; + real_t domain_warp_fractal_gain = 0.5; + +public: + FastNoiseLite(); + ~FastNoiseLite(); + + // General noise settings. + + void set_noise_type(NoiseType p_noise_type); + NoiseType get_noise_type() const; + + void set_seed(int p_seed); + int get_seed() const; + + void set_frequency(real_t p_freq); + real_t get_frequency() const; + + void set_offset(Vector3 p_offset); + Vector3 get_offset() const; + + // Fractal specific. + + void set_fractal_type(FractalType p_type); + FractalType get_fractal_type() const; + + void set_fractal_octaves(int p_octaves); + int get_fractal_octaves() const; + + void set_fractal_lacunarity(real_t p_lacunarity); + real_t get_fractal_lacunarity() const; + + void set_fractal_gain(real_t p_gain); + real_t get_fractal_gain() const; + + void set_fractal_weighted_strength(real_t p_weighted_strength); + real_t get_fractal_weighted_strength() const; + + void set_fractal_ping_pong_strength(real_t p_ping_pong_strength); + real_t get_fractal_ping_pong_strength() const; + + // Cellular specific. + + void set_cellular_distance_function(CellularDistanceFunction p_func); + CellularDistanceFunction get_cellular_distance_function() const; + + void set_cellular_return_type(CellularReturnType p_ret); + CellularReturnType get_cellular_return_type() const; + + void set_cellular_jitter(real_t p_jitter); + real_t get_cellular_jitter() const; + + // Domain warp specific. + + void set_domain_warp_enabled(bool p_enabled); + bool is_domain_warp_enabled() const; + + void set_domain_warp_type(DomainWarpType p_domain_warp_type); + DomainWarpType get_domain_warp_type() const; + + void set_domain_warp_amplitude(real_t p_amplitude); + real_t get_domain_warp_amplitude() const; + + void set_domain_warp_frequency(real_t p_frequency); + real_t get_domain_warp_frequency() const; + + void set_domain_warp_fractal_type(DomainWarpFractalType p_domain_warp_fractal_type); + DomainWarpFractalType get_domain_warp_fractal_type() const; + + void set_domain_warp_fractal_octaves(int p_octaves); + int get_domain_warp_fractal_octaves() const; + + void set_domain_warp_fractal_lacunarity(real_t p_lacunarity); + real_t get_domain_warp_fractal_lacunarity() const; + + void set_domain_warp_fractal_gain(real_t p_gain); + real_t get_domain_warp_fractal_gain() const; + + // Interface methods. + real_t get_noise_1d(real_t p_x) const override; + + real_t get_noise_2dv(Vector2 p_v) const override; + real_t get_noise_2d(real_t p_x, real_t p_y) const override; + + real_t get_noise_3dv(Vector3 p_v) const override; + real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const override; + + void _changed(); +}; + +VARIANT_ENUM_CAST(FastNoiseLite::NoiseType); +VARIANT_ENUM_CAST(FastNoiseLite::FractalType); +VARIANT_ENUM_CAST(FastNoiseLite::CellularDistanceFunction); +VARIANT_ENUM_CAST(FastNoiseLite::CellularReturnType); +VARIANT_ENUM_CAST(FastNoiseLite::DomainWarpType); +VARIANT_ENUM_CAST(FastNoiseLite::DomainWarpFractalType); + +#endif // FASTNOISE_LITE_H diff --git a/modules/opensimplex/icons/NoiseTexture.svg b/modules/noise/icons/NoiseTexture.svg index 479684cde2..479684cde2 100644 --- a/modules/opensimplex/icons/NoiseTexture.svg +++ b/modules/noise/icons/NoiseTexture.svg diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp new file mode 100644 index 0000000000..d14b63f7c8 --- /dev/null +++ b/modules/noise/noise.cpp @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* noise.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "noise.h" + +Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt) const { + ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>()); + + int skirt_width = p_width * p_blend_skirt; + int skirt_height = p_height * p_blend_skirt; + int src_width = p_width + skirt_width; + int src_height = p_height + skirt_height; + + Ref<Image> src = get_image(src_width, src_height, p_invert, p_in_3d_space); + bool grayscale = (src->get_format() == Image::FORMAT_L8); + if (grayscale) { + return _generate_seamless_image<uint8_t>(src, p_width, p_height, p_invert, p_blend_skirt); + } else { + return _generate_seamless_image<uint32_t>(src, p_width, p_height, p_invert, p_blend_skirt); + } +} + +// Template specialization for faster grayscale blending. +template <> +uint8_t Noise::_alpha_blend<uint8_t>(uint8_t p_bg, uint8_t p_fg, int p_alpha) const { + uint16_t alpha = p_alpha + 1; + uint16_t inv_alpha = 256 - p_alpha; + + return (uint8_t)((alpha * p_fg + inv_alpha * p_bg) >> 8); +} + +Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space) const { + ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>()); + + Vector<uint8_t> data; + data.resize(p_width * p_height); + + uint8_t *wd8 = data.ptrw(); + + // Get all values and identify min/max values. + Vector<real_t> values; + values.resize(p_width * p_height); + real_t min_val = 1000; + real_t max_val = -1000; + + for (int y = 0, i = 0; y < p_height; y++) { + for (int x = 0; x < p_width; x++, i++) { + values.set(i, p_in_3d_space ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y)); + if (values[i] > max_val) { + max_val = values[i]; + } + if (values[i] < min_val) { + min_val = values[i]; + } + } + } + + // Normalize values and write to texture. + uint8_t value; + for (int i = 0, x = 0; i < p_height; i++) { + for (int j = 0; j < p_width; j++, x++) { + if (max_val == min_val) { + value = 0; + } else { + value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255)); + } + if (p_invert) { + value = 255 - value; + } + + wd8[x] = value; + } + } + + return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data)); +} + +void Noise::_bind_methods() { + // Noise functions. + ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &Noise::get_noise_1d); + ClassDB::bind_method(D_METHOD("get_noise_2d", "x", "y"), &Noise::get_noise_2d); + ClassDB::bind_method(D_METHOD("get_noise_2dv", "v"), &Noise::get_noise_2dv); + ClassDB::bind_method(D_METHOD("get_noise_3d", "x", "y", "z"), &Noise::get_noise_3d); + ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv); + + // Textures. + ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert", "in_3d_space"), &Noise::get_image, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "in_3d_space", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1)); +} diff --git a/modules/noise/noise.h b/modules/noise/noise.h new file mode 100644 index 0000000000..8083334388 --- /dev/null +++ b/modules/noise/noise.h @@ -0,0 +1,240 @@ +/*************************************************************************/ +/* noise.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 NOISE_H +#define NOISE_H + +#include "core/io/image.h" + +class Noise : public Resource { + GDCLASS(Noise, Resource); + + // Helper struct for get_seamless_image(). See comments in .cpp for usage. + template <typename T> + struct img_buff { + T *img = nullptr; + int width; // Array dimensions & default modulo for image. + int height; + int offset_x; // Offset index location on image (wrapped by specified modulo). + int offset_y; + int alt_width; // Alternate module for image. + int alt_height; + + enum ALT_MODULO { + DEFAULT = 0, + ALT_X, + ALT_Y, + ALT_XY + }; + + // Multi-dimensional array indexer (e.g. img[x][y]) that supports multiple modulos. + T &operator()(int x, int y, ALT_MODULO mode = DEFAULT) { + switch (mode) { + case ALT_XY: + return img[(x + offset_x) % alt_width + ((y + offset_y) % alt_height) * width]; + case ALT_X: + return img[(x + offset_x) % alt_width + ((y + offset_y) % height) * width]; + case ALT_Y: + return img[(x + offset_x) % width + ((y + offset_y) % alt_height) * width]; + default: + return img[(x + offset_x) % width + ((y + offset_y) % height) * width]; + } + } + }; + + union l2c { + uint32_t l; + uint8_t c[4]; + struct { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + }; + + template <typename T> + Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) const { + /* + To make a seamless image, we swap the quadrants so the edges are perfect matches. + We initially get a 10% larger image so we have an overlap we can use to blend over the seams. + + Noise::img_buff::operator() acts as a multi-dimensional array indexer. + It does the array math, translates between the flipped and non-flipped quadrants, and manages offsets and modulos. + + Here is how the larger source image and final output image map to each other: + + Output size = p_width*p_height Source w/ extra 10% skirt `s` size = src_width*src_height + Q1 Q2 Q4 Q3 s1 + Q3 Q4 Q2 Q1 s2 + s5 s4 s3 + + All of the loops use output coordinates, so Output:Q1 == Source:Q1 + Ex: Output(half_width, half_height) [the midpoint, corner of Q1/Q4] => + on Source it's translated to + corner of Q1/s3 unless the ALT_XY modulo moves it to Q4 + */ + ERR_FAIL_COND_V(p_blend_skirt < 0, Ref<Image>()); + + int skirt_width = MAX(1, p_width * p_blend_skirt); + int skirt_height = MAX(1, p_height * p_blend_skirt); + int src_width = p_width + skirt_width; + int src_height = p_height + skirt_height; + int half_width = p_width * .5; + int half_height = p_height * .5; + int skirt_edge_x = half_width + skirt_width; + int skirt_edge_y = half_height + skirt_height; + + Vector<uint8_t> dest; + dest.resize(p_width * p_height * Image::get_format_pixel_size(p_src->get_format())); + + img_buff<T> rd_src = { + (T *)p_src->get_data().ptr(), + src_width, src_height, + half_width, half_height, + p_width, p_height + }; + + // `wr` is setup for straight x/y coordinate array access. + img_buff<T> wr = { + (T *)dest.ptrw(), + p_width, p_height, + 0, 0, 0, 0 + }; + // `rd_dest` is a readable pointer to `wr`, i.e. what has already been written to the output buffer. + img_buff<T> rd_dest = { + (T *)dest.ptr(), + p_width, p_height, + 0, 0, 0, 0 + }; + + // Swap the quadrants to make edges seamless. + for (int y = 0; y < p_height; y++) { + for (int x = 0; x < p_width; x++) { + // rd_src has a half offset and the shorter modulo ignores the skirt. + // It reads and writes in Q1-4 order (see map above), skipping the skirt. + wr(x, y) = rd_src(x, y, img_buff<T>::ALT_XY); + } + } + + // Blend the vertical skirt over the middle seam. + for (int x = half_width; x < skirt_edge_x; x++) { + int alpha = 255 * (1 - Math::smoothstep(.1f, .9f, float(x - half_width) / float(skirt_width))); + for (int y = 0; y < p_height; y++) { + // Skip the center square + if (y == half_height) { + y = skirt_edge_y - 1; + } else { + // Starts reading at s2, ALT_Y skips s3, and continues with s1. + wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_Y), alpha); + } + } + } + + // Blend the horizontal skirt over the middle seam. + for (int y = half_height; y < skirt_edge_y; y++) { + int alpha = 255 * (1 - Math::smoothstep(.1f, .9f, float(y - half_height) / float(skirt_height))); + for (int x = 0; x < p_width; x++) { + // Skip the center square + if (x == half_width) { + x = skirt_edge_x - 1; + } else { + // Starts reading at s4, skips s3, continues with s5. + wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_X), alpha); + } + } + } + + // Fill in the center square. Wr starts at the top left of Q4, which is the equivalent of the top left of s3, unless a modulo is used. + for (int y = half_height; y < skirt_edge_y; y++) { + for (int x = half_width; x < skirt_edge_x; x++) { + int xpos = 255 * (1 - Math::smoothstep(.1f, .9f, float(x - half_width) / float(skirt_width))); + int ypos = 255 * (1 - Math::smoothstep(.1f, .9f, float(y - half_height) / float(skirt_height))); + + // Blend s3(Q1) onto s5(Q2) for the top half. + T top_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_X), rd_src(x, y, img_buff<T>::DEFAULT), xpos); + // Blend s1(Q3) onto Q4 for the bottom half. + T bottom_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_XY), rd_src(x, y, img_buff<T>::ALT_Y), xpos); + // Blend the top half onto the bottom half. + wr(x, y) = _alpha_blend<T>(bottom_blend, top_blend, ypos); + } + } + Ref<Image> image = memnew(Image(p_width, p_height, false, p_src->get_format(), dest)); + p_src.unref(); + return image; + } + + template <typename T> + T _alpha_blend(T p_bg, T p_fg, int p_alpha) const { + l2c fg, bg, out; + + fg.l = p_fg; + bg.l = p_bg; + + uint16_t alpha; + uint16_t inv_alpha; + + // If no alpha argument specified, use the alpha channel in the color + if (p_alpha == -1) { + alpha = fg.c[3] + 1; + inv_alpha = 256 - fg.c[3]; + } else { + alpha = p_alpha + 1; + inv_alpha = 256 - p_alpha; + } + + out.c[0] = (uint8_t)((alpha * fg.c[0] + inv_alpha * bg.c[0]) >> 8); + out.c[1] = (uint8_t)((alpha * fg.c[1] + inv_alpha * bg.c[1]) >> 8); + out.c[2] = (uint8_t)((alpha * fg.c[2] + inv_alpha * bg.c[2]) >> 8); + out.c[3] = 0xFF; + + return out.l; + } + +protected: + static void _bind_methods(); + +public: + // Virtual destructor so we can delete any Noise derived object when referenced as a Noise*. + virtual ~Noise() {} + + virtual real_t get_noise_1d(real_t p_x) const = 0; + + virtual real_t get_noise_2dv(Vector2 p_v) const = 0; + virtual real_t get_noise_2d(real_t p_x, real_t p_y) const = 0; + + virtual real_t get_noise_3dv(Vector3 p_v) const = 0; + virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const = 0; + + virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false) const; + virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1) const; +}; + +#endif // NOISE_H diff --git a/modules/opensimplex/noise_texture.cpp b/modules/noise/noise_texture.cpp index e36dcfcea5..e9d16e548c 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/noise/noise_texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,9 +31,10 @@ #include "noise_texture.h" #include "core/core_string_names.h" +#include "noise.h" NoiseTexture::NoiseTexture() { - noise = Ref<OpenSimplexNoise>(); + noise = Ref<Noise>(); _queue_update(); } @@ -46,35 +47,51 @@ NoiseTexture::~NoiseTexture() { } void NoiseTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture); + ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture); + ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done); + ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture::set_width); ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture::set_height); - 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_invert", "invert"), &NoiseTexture::set_invert); + ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture::get_invert); - 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_in_3d_space", "enable"), &NoiseTexture::set_in_3d_space); + ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture::is_in_3d_space); + + ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture::set_generate_mipmaps); + ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture::is_generating_mipmaps); ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless); ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless); + ClassDB::bind_method(D_METHOD("set_seamless_blend_skirt", "seamless_blend_skirt"), &NoiseTexture::set_seamless_blend_skirt); + ClassDB::bind_method(D_METHOD("get_seamless_blend_skirt"), &NoiseTexture::get_seamless_blend_skirt); + ClassDB::bind_method(D_METHOD("set_as_normal_map", "as_normal_map"), &NoiseTexture::set_as_normal_map); ClassDB::bind_method(D_METHOD("is_normal_map"), &NoiseTexture::is_normal_map); ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength); ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength); - ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture); - ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture); - ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done); + ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture::set_color_ramp); + ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture::get_color_ramp); + + ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise); + ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise); ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert"), "set_invert", "get_invert"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "is_generating_mipmaps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "seamless"), "set_seamless", "get_seamless"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "seamless_blend_skirt", PROPERTY_HINT_RANGE, "0.05,1,0.001"), "set_seamless_blend_skirt", "get_seamless_blend_skirt"); 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"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise"); } void NoiseTexture::_validate_property(PropertyInfo &property) const { @@ -83,6 +100,12 @@ void NoiseTexture::_validate_property(PropertyInfo &property) const { property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } + + if (property.name == "seamless_blend_skirt") { + if (!seamless) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } } void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) { @@ -108,7 +131,7 @@ void NoiseTexture::_thread_done(const Ref<Image> &p_image) { } void NoiseTexture::_thread_function(void *p_ud) { - NoiseTexture *tex = (NoiseTexture *)p_ud; + NoiseTexture *tex = static_cast<NoiseTexture *>(p_ud); tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture()); } @@ -123,7 +146,7 @@ void NoiseTexture::_queue_update() { Ref<Image> NoiseTexture::_generate_texture() { // Prevent memdelete due to unref() on other thread. - Ref<OpenSimplexNoise> ref_noise = noise; + Ref<Noise> ref_noise = noise; if (ref_noise.is_null()) { return Ref<Image>(); @@ -132,18 +155,42 @@ Ref<Image> NoiseTexture::_generate_texture() { Ref<Image> image; if (seamless) { - image = ref_noise->get_seamless_image(size.x); + image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt); } else { - image = ref_noise->get_image(size.x, size.y, noise_offset); + image = ref_noise->get_image(size.x, size.y, invert, in_3d_space); + } + if (color_ramp.is_valid()) { + image = _modulate_with_gradient(image, color_ramp); } - if (as_normal_map) { image->bump_map_to_normal_map(bump_strength); } + if (generate_mipmaps) { + image->generate_mipmaps(); + } return image; } +Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) { + int width = p_image->get_width(); + int height = p_image->get_height(); + + Ref<Image> new_image; + new_image.instantiate(); + new_image->create(width, height, false, Image::FORMAT_RGBA8); + + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + Color pixel_color = p_image->get_pixel(col, row); + Color ramp_color = color_ramp->get_color_at_offset(pixel_color.get_luminance()); + new_image->set_pixel(col, row, ramp_color); + } + } + + return new_image; +} + void NoiseTexture::_update_texture() { bool use_thread = true; if (first_time) { @@ -168,7 +215,7 @@ void NoiseTexture::_update_texture() { update_queued = false; } -void NoiseTexture::set_noise(Ref<OpenSimplexNoise> p_noise) { +void NoiseTexture::set_noise(Ref<Noise> p_noise) { if (p_noise == noise) { return; } @@ -182,7 +229,7 @@ void NoiseTexture::set_noise(Ref<OpenSimplexNoise> p_noise) { _queue_update(); } -Ref<OpenSimplexNoise> NoiseTexture::get_noise() { +Ref<Noise> NoiseTexture::get_noise() { return noise; } @@ -204,26 +251,67 @@ void NoiseTexture::set_height(int p_height) { _queue_update(); } -void NoiseTexture::set_noise_offset(Vector2 p_noise_offset) { - if (noise_offset == p_noise_offset) { +void NoiseTexture::set_invert(bool p_invert) { + if (p_invert == invert) { return; } - noise_offset = p_noise_offset; + invert = p_invert; _queue_update(); } +bool NoiseTexture::get_invert() const { + return invert; +} + +void NoiseTexture::set_in_3d_space(bool p_enable) { + if (p_enable == in_3d_space) { + return; + } + in_3d_space = p_enable; + _queue_update(); +} +bool NoiseTexture::is_in_3d_space() const { + return in_3d_space; +} + +void NoiseTexture::set_generate_mipmaps(bool p_enable) { + if (p_enable == generate_mipmaps) { + return; + } + generate_mipmaps = p_enable; + _queue_update(); +} + +bool NoiseTexture::is_generating_mipmaps() const { + return generate_mipmaps; +} + void NoiseTexture::set_seamless(bool p_seamless) { if (p_seamless == seamless) { return; } seamless = p_seamless; _queue_update(); + notify_property_list_changed(); } bool NoiseTexture::get_seamless() { return seamless; } +void NoiseTexture::set_seamless_blend_skirt(real_t p_blend_skirt) { + ERR_FAIL_COND(p_blend_skirt < 0.05 || p_blend_skirt > 1); + + if (p_blend_skirt == seamless_blend_skirt) { + return; + } + seamless_blend_skirt = p_blend_skirt; + _queue_update(); +} +real_t NoiseTexture::get_seamless_blend_skirt() { + return seamless_blend_skirt; +} + void NoiseTexture::set_as_normal_map(bool p_as_normal_map) { if (p_as_normal_map == as_normal_map) { return; @@ -251,6 +339,24 @@ float NoiseTexture::get_bump_strength() { return bump_strength; } +void NoiseTexture::set_color_ramp(const Ref<Gradient> &p_gradient) { + if (p_gradient == color_ramp) { + return; + } + if (color_ramp.is_valid()) { + color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update)); + } + color_ramp = p_gradient; + if (color_ramp.is_valid()) { + color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update)); + } + _queue_update(); +} + +Ref<Gradient> NoiseTexture::get_color_ramp() const { + return color_ramp; +} + int NoiseTexture::get_width() const { return size.x; } @@ -259,10 +365,6 @@ 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(); diff --git a/modules/opensimplex/noise_texture.h b/modules/noise/noise_texture.h index a0b2a86c41..6c088562a1 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/noise/noise_texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,10 +31,10 @@ #ifndef NOISE_TEXTURE_H #define NOISE_TEXTURE_H -#include "open_simplex_noise.h" +#include "noise.h" -#include "core/io/image.h" #include "core/object/ref_counted.h" +#include "scene/resources/texture.h" class NoiseTexture : public Texture2D { GDCLASS(NoiseTexture, Texture2D); @@ -51,13 +51,18 @@ private: mutable RID texture; uint32_t flags = 0; - Ref<OpenSimplexNoise> noise; - Vector2i size = Vector2i(512, 512); - Vector2 noise_offset; + Size2i size = Size2i(512, 512); + bool invert = false; + bool in_3d_space = false; + bool generate_mipmaps = true; bool seamless = false; + real_t seamless_blend_skirt = 0.1; bool as_normal_map = false; float bump_strength = 8.0; + Ref<Gradient> color_ramp; + Ref<Noise> noise; + void _thread_done(const Ref<Image> &p_image); static void _thread_function(void *p_ud); @@ -66,29 +71,43 @@ private: void _update_texture(); void _set_texture_image(const Ref<Image> &p_image); + Ref<Image> _modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient); + protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; public: - void set_noise(Ref<OpenSimplexNoise> p_noise); - Ref<OpenSimplexNoise> get_noise(); + void set_noise(Ref<Noise> p_noise); + Ref<Noise> get_noise(); 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_invert(bool p_invert); + bool get_invert() const; + + void set_in_3d_space(bool p_enable); + bool is_in_3d_space() const; + + void set_generate_mipmaps(bool p_enable); + bool is_generating_mipmaps() const; void set_seamless(bool p_seamless); bool get_seamless(); + void set_seamless_blend_skirt(real_t p_blend_skirt); + real_t get_seamless_blend_skirt(); + void set_as_normal_map(bool p_as_normal_map); bool is_normal_map(); void set_bump_strength(float p_bump_strength); float get_bump_strength(); + void set_color_ramp(const Ref<Gradient> &p_gradient); + Ref<Gradient> get_color_ramp() const; + int get_width() const override; int get_height() const override; diff --git a/modules/fbx/register_types.cpp b/modules/noise/register_types.cpp index d5e520a060..d0cfc4e944 100644 --- a/modules/fbx/register_types.cpp +++ b/modules/noise/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,29 +30,31 @@ #include "register_types.h" -#include "editor/editor_node.h" -#include "editor_scene_importer_fbx.h" +#include "fastnoise_lite.h" +#include "noise.h" +#include "noise_texture.h" #ifdef TOOLS_ENABLED -static void _editor_init() { - Ref<EditorSceneFormatImporterFBX> import_fbx; - import_fbx.instantiate(); - ResourceImporterScene::get_singleton()->add_importer(import_fbx); -} +#include "editor/editor_plugin.h" +#include "editor/noise_editor_plugin.h" #endif -void register_fbx_types() { -#ifdef TOOLS_ENABLED - ClassDB::APIType prev_api = ClassDB::get_current_api(); - ClassDB::set_current_api(ClassDB::API_EDITOR); - - GDREGISTER_CLASS(EditorSceneFormatImporterFBX); +void initialize_noise_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { + GDREGISTER_CLASS(NoiseTexture); + GDREGISTER_ABSTRACT_CLASS(Noise); + GDREGISTER_CLASS(FastNoiseLite); + } - ClassDB::set_current_api(prev_api); - - EditorNode::add_init_callback(_editor_init); +#ifdef TOOLS_ENABLED + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + EditorPlugins::add_by_type<NoiseEditorPlugin>(); + } #endif } -void unregister_fbx_types() { +void uninitialize_noise_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/fbx/register_types.h b/modules/noise/register_types.h index e5741afd72..dfe5a480de 100644 --- a/modules/fbx/register_types.h +++ b/modules/noise/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,10 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef FBX_REGISTER_TYPES_H -#define FBX_REGISTER_TYPES_H +#ifndef NOISE_REGISTER_TYPES_H +#define NOISE_REGISTER_TYPES_H -void register_fbx_types(); -void unregister_fbx_types(); +#include "modules/register_module_types.h" -#endif // FBX_REGISTER_TYPES_H +void initialize_noise_module(ModuleInitializationLevel p_level); +void uninitialize_noise_module(ModuleInitializationLevel p_level); + +#endif // NOISE_REGISTER_TYPES_H diff --git a/modules/ogg/doc_classes/OGGPacketSequence.xml b/modules/ogg/doc_classes/OGGPacketSequence.xml index deac5b67e2..bff3691ce0 100644 --- a/modules/ogg/doc_classes/OGGPacketSequence.xml +++ b/modules/ogg/doc_classes/OGGPacketSequence.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="OGGPacketSequence" inherits="Resource" version="4.0"> +<class name="OGGPacketSequence" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A sequence of OGG packets. </brief_description> diff --git a/modules/ogg/doc_classes/OGGPacketSequencePlayback.xml b/modules/ogg/doc_classes/OGGPacketSequencePlayback.xml index 86dee15567..11fc1f4cb6 100644 --- a/modules/ogg/doc_classes/OGGPacketSequencePlayback.xml +++ b/modules/ogg/doc_classes/OGGPacketSequencePlayback.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="OGGPacketSequencePlayback" inherits="RefCounted" version="4.0"> +<class name="OGGPacketSequencePlayback" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp index abb2b67ab0..da52ecfdd5 100644 --- a/modules/ogg/ogg_packet_sequence.cpp +++ b/modules/ogg/ogg_packet_sequence.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -162,6 +162,7 @@ bool OGGPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const { } uint32_t OGGPacketSequencePlayback::seek_page_internal(int64_t granule, uint32_t after_page_inclusive, uint32_t before_page_inclusive) { + // FIXME: This function needs better corner case handling. if (before_page_inclusive == after_page_inclusive) { return before_page_inclusive; } @@ -169,7 +170,8 @@ uint32_t OGGPacketSequencePlayback::seek_page_internal(int64_t granule, uint32_t // Complicating the bisection search algorithm, the middle page might not have a packet that ends on it, // which means it might not have a correct granule position. Find a nearby page that does have a packet ending on it. uint32_t bisection_page = -1; - for (uint32_t test_page = actual_middle_page; test_page <= before_page_inclusive; test_page++) { + // Don't include before_page_inclusive because that always succeeds and will cause infinite recursion later. + for (uint32_t test_page = actual_middle_page; test_page < before_page_inclusive; test_page++) { if (ogg_packet_sequence->page_data[test_page].size() > 0) { bisection_page = test_page; break; diff --git a/modules/ogg/ogg_packet_sequence.h b/modules/ogg/ogg_packet_sequence.h index b00ada06c1..73e3cb4fff 100644 --- a/modules/ogg/ogg_packet_sequence.h +++ b/modules/ogg/ogg_packet_sequence.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -104,7 +104,7 @@ class OGGPacketSequencePlayback : public RefCounted { mutable ogg_packet *packet; - uint64_t data_version; + uint64_t data_version = 0; mutable int64_t packetno = 0; diff --git a/modules/ogg/register_types.cpp b/modules/ogg/register_types.cpp index 3448e7063a..01f04aa3d5 100644 --- a/modules/ogg/register_types.cpp +++ b/modules/ogg/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,9 +32,17 @@ #include "ogg_packet_sequence.h" -void register_ogg_types() { +void initialize_ogg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(OGGPacketSequence); GDREGISTER_CLASS(OGGPacketSequencePlayback); } -void unregister_ogg_types() {} +void uninitialize_ogg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/ogg/register_types.h b/modules/ogg/register_types.h index 49d5ed9c80..9065d26d07 100644 --- a/modules/ogg/register_types.h +++ b/modules/ogg/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef OGG_REGISTER_TYPES_H #define OGG_REGISTER_TYPES_H -void register_ogg_types(); -void unregister_ogg_types(); +#include "modules/register_module_types.h" + +void initialize_ogg_module(ModuleInitializationLevel p_level); +void uninitialize_ogg_module(ModuleInitializationLevel p_level); #endif // OGG_REGISTER_TYPES_H diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml deleted file mode 100644 index 16fea228b1..0000000000 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="NoiseTexture" inherits="Texture2D" version="4.0"> - <brief_description> - [OpenSimplexNoise] filled texture. - </brief_description> - <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_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 = NoiseTexture.new() - texture.noise = OpenSimplexNoise.new() - await texture.changed - var image = texture.get_image() - var data = image.get_data() - [/codeblock] - </description> - <tutorials> - </tutorials> - <members> - <member name="as_normal_map" type="bool" setter="set_as_normal_map" getter="is_normal_map" default="false"> - If [code]true[/code], the resulting texture contains a normal map created from the original noise interpreted as a bump map. - </member> - <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0"> - Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer. - </member> - <member name="height" type="int" setter="set_height" getter="get_height" default="512"> - Height of the generated texture. - </member> - <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. - </member> - <member name="width" type="int" setter="set_width" getter="get_width" default="512"> - Width of the generated texture. - </member> - </members> -</class> diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml deleted file mode 100644 index 604b07b645..0000000000 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ /dev/null @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="OpenSimplexNoise" inherits="Resource" version="4.0"> - <brief_description> - Noise generator based on Open Simplex. - </brief_description> - <description> - This resource allows you to configure and sample a fractal noise space. Here is a brief usage example that configures an OpenSimplexNoise and gets samples at various positions and dimensions: - [codeblock] - var noise = OpenSimplexNoise.new() - - # Configure - noise.seed = randi() - noise.octaves = 4 - noise.period = 20.0 - noise.persistence = 0.8 - - # Sample - print("Values:") - print(noise.get_noise_2d(1.0, 1.0)) - print(noise.get_noise_3d(0.5, 3.0, 15.0)) - print(noise.get_noise_4d(0.5, 1.9, 4.7, 0.0)) - [/codeblock] - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_image" qualifiers="const"> - <return type="Image" /> - <argument index="0" name="width" type="int" /> - <argument index="1" name="height" type="int" /> - <argument index="2" name="noise_offset" type="Vector2" default="Vector2(0, 0)" /> - <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. 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"> - <return type="float" /> - <argument index="0" name="x" type="float" /> - <description> - Returns the 1D noise value [code][-1,1][/code] at the given x-coordinate. - [b]Note:[/b] This method actually returns the 2D noise value [code][-1,1][/code] with fixed y-coordinate value 0.0. - </description> - </method> - <method name="get_noise_2d" qualifiers="const"> - <return type="float" /> - <argument index="0" name="x" type="float" /> - <argument index="1" name="y" type="float" /> - <description> - Returns the 2D noise value [code][-1,1][/code] at the given position. - </description> - </method> - <method name="get_noise_2dv" qualifiers="const"> - <return type="float" /> - <argument index="0" name="pos" type="Vector2" /> - <description> - Returns the 2D noise value [code][-1,1][/code] at the given position. - </description> - </method> - <method name="get_noise_3d" qualifiers="const"> - <return type="float" /> - <argument index="0" name="x" type="float" /> - <argument index="1" name="y" type="float" /> - <argument index="2" name="z" type="float" /> - <description> - Returns the 3D noise value [code][-1,1][/code] at the given position. - </description> - </method> - <method name="get_noise_3dv" qualifiers="const"> - <return type="float" /> - <argument index="0" name="pos" type="Vector3" /> - <description> - Returns the 3D noise value [code][-1,1][/code] at the given position. - </description> - </method> - <method name="get_noise_4d" qualifiers="const"> - <return type="float" /> - <argument index="0" name="x" type="float" /> - <argument index="1" name="y" type="float" /> - <argument index="2" name="z" type="float" /> - <argument index="3" name="w" type="float" /> - <description> - Returns the 4D noise value [code][-1,1][/code] at the given position. - </description> - </method> - <method name="get_seamless_image" qualifiers="const"> - <return type="Image" /> - <argument index="0" name="size" type="int" /> - <description> - Generate a tileable noise image in [constant Image.FORMAT_L8] format, based on the current noise parameters. Generated seamless images are always square ([code]size[/code] × [code]size[/code]). - [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. - </description> - </method> - </methods> - <members> - <member name="lacunarity" type="float" setter="set_lacunarity" getter="get_lacunarity" default="2.0"> - Difference in period between [member octaves]. - </member> - <member name="octaves" type="int" setter="set_octaves" getter="get_octaves" default="3"> - Number of OpenSimplex noise layers that are sampled to get the fractal noise. Higher values result in more detailed noise but take more time to generate. - [b]Note:[/b] The maximum allowed value is 9. - </member> - <member name="period" type="float" setter="set_period" getter="get_period" default="64.0"> - Period of the base octave. A lower period results in a higher-frequency noise (more value changes across the same distance). - </member> - <member name="persistence" type="float" setter="set_persistence" getter="get_persistence" default="0.5"> - Contribution factor of the different octaves. A [code]persistence[/code] value of 1 means all the octaves have the same contribution, a value of 0.5 means each octave contributes half as much as the previous one. - </member> - <member name="seed" type="int" setter="set_seed" getter="get_seed" default="0"> - Seed used to generate random values, different seeds will generate different noise maps. - </member> - </members> -</class> diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp deleted file mode 100644 index f0a8867284..0000000000 --- a/modules/opensimplex/open_simplex_noise.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/*************************************************************************/ -/* open_simplex_noise.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 "open_simplex_noise.h" - -#include "core/core_string_names.h" - -OpenSimplexNoise::OpenSimplexNoise() { - _init_seeds(); -} - -OpenSimplexNoise::~OpenSimplexNoise() { -} - -void OpenSimplexNoise::_init_seeds() { - for (int i = 0; i < MAX_OCTAVES; ++i) { - open_simplex_noise(seed + i * 2, &(contexts[i])); - } -} - -void OpenSimplexNoise::set_seed(int p_seed) { - if (seed == p_seed) { - return; - } - - seed = p_seed; - - _init_seeds(); - - emit_changed(); -} - -int OpenSimplexNoise::get_seed() const { - return seed; -} - -void OpenSimplexNoise::set_octaves(int p_octaves) { - if (p_octaves == octaves) { - return; - } - - ERR_FAIL_COND_MSG(p_octaves > MAX_OCTAVES, vformat("The number of OpenSimplexNoise octaves is limited to %d; ignoring the new value.", MAX_OCTAVES)); - - octaves = CLAMP(p_octaves, 1, MAX_OCTAVES); - emit_changed(); -} - -void OpenSimplexNoise::set_period(float p_period) { - if (p_period == period) { - return; - } - period = p_period; - emit_changed(); -} - -void OpenSimplexNoise::set_persistence(float p_persistence) { - if (p_persistence == persistence) { - return; - } - persistence = p_persistence; - emit_changed(); -} - -void OpenSimplexNoise::set_lacunarity(float p_lacunarity) { - if (p_lacunarity == lacunarity) { - return; - } - lacunarity = p_lacunarity; - emit_changed(); -} - -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); - - uint8_t *wd8 = data.ptrw(); - - for (int i = 0; i < p_height; i++) { - for (int j = 0; j < p_width; j++) { - 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)); - } - } - - Ref<Image> image = memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data)); - return image; -} - -Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) const { - Vector<uint8_t> data; - data.resize(p_size * p_size); - - uint8_t *wd8 = data.ptrw(); - - for (int i = 0; i < p_size; i++) { - for (int j = 0; j < p_size; j++) { - float ii = (float)i / (float)p_size; - float jj = (float)j / (float)p_size; - - ii *= Math_TAU; - jj *= Math_TAU; - - float radius = p_size / Math_TAU; - - float x = radius * Math::sin(jj); - float y = radius * Math::cos(jj); - float z = radius * Math::sin(ii); - float w = radius * Math::cos(ii); - float v = get_noise_4d(x, y, z, w); - - v = v * 0.5 + 0.5; // Normalize [0..1] - wd8[(i * p_size + j)] = uint8_t(CLAMP(v * 255.0, 0, 255)); - } - } - - Ref<Image> image = memnew(Image(p_size, p_size, false, Image::FORMAT_L8, data)); - return image; -} - -void OpenSimplexNoise::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_seed"), &OpenSimplexNoise::get_seed); - ClassDB::bind_method(D_METHOD("set_seed", "seed"), &OpenSimplexNoise::set_seed); - - ClassDB::bind_method(D_METHOD("set_octaves", "octave_count"), &OpenSimplexNoise::set_octaves); - ClassDB::bind_method(D_METHOD("get_octaves"), &OpenSimplexNoise::get_octaves); - - ClassDB::bind_method(D_METHOD("set_period", "period"), &OpenSimplexNoise::set_period); - ClassDB::bind_method(D_METHOD("get_period"), &OpenSimplexNoise::get_period); - - ClassDB::bind_method(D_METHOD("set_persistence", "persistence"), &OpenSimplexNoise::set_persistence); - ClassDB::bind_method(D_METHOD("get_persistence"), &OpenSimplexNoise::get_persistence); - - 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", "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); - ClassDB::bind_method(D_METHOD("get_noise_2d", "x", "y"), &OpenSimplexNoise::get_noise_2d); - ClassDB::bind_method(D_METHOD("get_noise_3d", "x", "y", "z"), &OpenSimplexNoise::get_noise_3d); - ClassDB::bind_method(D_METHOD("get_noise_4d", "x", "y", "z", "w"), &OpenSimplexNoise::get_noise_4d); - - ClassDB::bind_method(D_METHOD("get_noise_2dv", "pos"), &OpenSimplexNoise::get_noise_2dv); - ClassDB::bind_method(D_METHOD("get_noise_3dv", "pos"), &OpenSimplexNoise::get_noise_3dv); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "octaves", PROPERTY_HINT_RANGE, vformat("1,%d,1", MAX_OCTAVES)), "set_octaves", "get_octaves"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "period", PROPERTY_HINT_RANGE, "0.1,256.0,0.1"), "set_period", "get_period"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "persistence", PROPERTY_HINT_RANGE, "0.0,1.0,0.001"), "set_persistence", "get_persistence"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lacunarity", PROPERTY_HINT_RANGE, "0.1,4.0,0.01"), "set_lacunarity", "get_lacunarity"); -} - -float OpenSimplexNoise::get_noise_1d(float x) const { - return get_noise_2d(x, 1.0); -} - -float OpenSimplexNoise::get_noise_2d(float x, float y) const { - x /= period; - y /= period; - - float amp = 1.0; - float max = 1.0; - float sum = _get_octave_noise_2d(0, x, y); - - int i = 0; - while (++i < octaves) { - x *= lacunarity; - y *= lacunarity; - amp *= persistence; - max += amp; - sum += _get_octave_noise_2d(i, x, y) * amp; - } - - return sum / max; -} - -float OpenSimplexNoise::get_noise_3d(float x, float y, float z) const { - x /= period; - y /= period; - z /= period; - - float amp = 1.0; - float max = 1.0; - float sum = _get_octave_noise_3d(0, x, y, z); - - int i = 0; - while (++i < octaves) { - x *= lacunarity; - y *= lacunarity; - z *= lacunarity; - amp *= persistence; - max += amp; - sum += _get_octave_noise_3d(i, x, y, z) * amp; - } - - return sum / max; -} - -float OpenSimplexNoise::get_noise_4d(float x, float y, float z, float w) const { - x /= period; - y /= period; - z /= period; - w /= period; - - float amp = 1.0; - float max = 1.0; - float sum = _get_octave_noise_4d(0, x, y, z, w); - - int i = 0; - while (++i < octaves) { - x *= lacunarity; - y *= lacunarity; - z *= lacunarity; - w *= lacunarity; - amp *= persistence; - max += amp; - sum += _get_octave_noise_4d(i, x, y, z, w) * amp; - } - - return sum / max; -} diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h deleted file mode 100644 index dcf922a8bf..0000000000 --- a/modules/opensimplex/open_simplex_noise.h +++ /dev/null @@ -1,99 +0,0 @@ -/*************************************************************************/ -/* open_simplex_noise.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 OPEN_SIMPLEX_NOISE_H -#define OPEN_SIMPLEX_NOISE_H - -#include "core/io/image.h" -#include "core/object/ref_counted.h" -#include "scene/resources/texture.h" - -#include "thirdparty/misc/open-simplex-noise.h" - -class OpenSimplexNoise : public Resource { - GDCLASS(OpenSimplexNoise, Resource); - OBJ_SAVE_TYPE(OpenSimplexNoise); - - // The maximum number of octaves allowed. Note that these are statically allocated. - // Higher values become exponentially slower, so this shouldn't be set too high - // to avoid freezing the editor for long periods of time. - static const int MAX_OCTAVES = 9; - - osn_context contexts[MAX_OCTAVES]; - - int seed = 0; - float persistence = 0.5; // Controls details, value in [0,1]. Higher increases grain, lower increases smoothness. - int octaves = 3; // Number of noise layers - float period = 64.0; // Distance above which we start to see similarities. The higher, the longer "hills" will be on a terrain. - float lacunarity = 2.0; // Controls period change across octaves. 2 is usually a good value to address all detail levels. - -public: - OpenSimplexNoise(); - ~OpenSimplexNoise(); - - void _init_seeds(); - - void set_seed(int seed); - int get_seed() const; - - void set_octaves(int p_octaves); - int get_octaves() const { return octaves; } - - void set_period(float p_period); - float get_period() const { return period; } - - void set_persistence(float p_persistence); - float get_persistence() const { return persistence; } - - void set_lacunarity(float p_lacunarity); - float get_lacunarity() const { return lacunarity; } - - 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; - float get_noise_2d(float x, float y) const; - float get_noise_3d(float x, float y, float z) const; - float get_noise_4d(float x, float y, float z, float w) const; - - _FORCE_INLINE_ float _get_octave_noise_2d(int octave, float x, float y) const { return open_simplex_noise2(&(contexts[octave]), x, y); } - _FORCE_INLINE_ float _get_octave_noise_3d(int octave, float x, float y, float z) const { return open_simplex_noise3(&(contexts[octave]), x, y, z); } - _FORCE_INLINE_ float _get_octave_noise_4d(int octave, float x, float y, float z, float w) const { return open_simplex_noise4(&(contexts[octave]), x, y, z, w); } - - // Convenience - - _FORCE_INLINE_ float get_noise_2dv(const Vector2 &v) const { return get_noise_2d(v.x, v.y); } - _FORCE_INLINE_ float get_noise_3dv(const Vector3 &v) const { return get_noise_3d(v.x, v.y, v.z); } - -protected: - static void _bind_methods(); -}; - -#endif // OPEN_SIMPLEX_NOISE_H diff --git a/modules/opensimplex/register_types.cpp b/modules/opensimplex/register_types.cpp deleted file mode 100644 index d6f9f3436d..0000000000 --- a/modules/opensimplex/register_types.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" -#include "noise_texture.h" -#include "open_simplex_noise.h" - -void register_opensimplex_types() { - GDREGISTER_CLASS(OpenSimplexNoise); - GDREGISTER_CLASS(NoiseTexture); -} - -void unregister_opensimplex_types() { -} diff --git a/modules/opensimplex/register_types.h b/modules/opensimplex/register_types.h deleted file mode 100644 index d72e37e3a3..0000000000 --- a/modules/opensimplex/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef OPENSIMPLEX_REGISTER_TYPES_H -#define OPENSIMPLEX_REGISTER_TYPES_H - -void register_opensimplex_types(); -void unregister_opensimplex_types(); - -#endif // OPENSIMPLEX_REGISTER_TYPES_H diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub new file mode 100644 index 0000000000..ff320236a7 --- /dev/null +++ b/modules/openxr/SCsub @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_openxr = env_modules.Clone() + +################################################# +# Add in our Khronos OpenXR loader + +thirdparty_obj = [] +thirdparty_dir = "#thirdparty/openxr" + +env_openxr.Prepend( + CPPPATH=[ + thirdparty_dir, + thirdparty_dir + "/include", + thirdparty_dir + "/src", + thirdparty_dir + "/src/common", + thirdparty_dir + "/src/external/jsoncpp/include", + thirdparty_dir + "/src/loader", + ] +) + +# may need to check and set: +# - XR_USE_TIMESPEC + +env_thirdparty = env_openxr.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"]) + +if env["platform"] == "android": + # may need to set OPENXR_ANDROID_VERSION_SUFFIX + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"]) + + # may need to include java parts of the openxr loader +elif env["platform"] == "linuxbsd": + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX", "XR_USE_PLATFORM_XLIB"]) + # FIXME: Review what needs to be set for Android and macOS. + env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) +elif env["platform"] == "windows": + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"]) + +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") + +# add in common files (hope these don't clash with us) +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/object_info.cpp") + +# add in external jsoncpp dependency +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_value.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp") + +# add in load +if env["platform"] == "android": + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/android_utilities.cpp") + +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_core.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_instance.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp") + +env.modules_sources += thirdparty_obj + +################################################# +# And include our module source + +module_obj = [] + +env_openxr.add_source_files(module_obj, "*.cpp") +env_openxr.add_source_files(module_obj, "action_map/*.cpp") + +# We're a little more targeted with our extensions +if env["platform"] == "android": + env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp") +if env["vulkan"]: + env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp") + +env.modules_sources += module_obj + +if env["tools"]: + SConscript("editor/SCsub") + +# Needed to force rebuilding the module files when the thirdparty library is updated. +env.Depends(module_obj, thirdparty_obj) diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp new file mode 100644 index 0000000000..359975a480 --- /dev/null +++ b/modules/openxr/action_map/openxr_action.cpp @@ -0,0 +1,114 @@ +/*************************************************************************/ +/* openxr_action.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_action.h" +#include "openxr_action_set.h" + +void OpenXRAction::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name); + ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRAction::get_localized_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name"); + + ClassDB::bind_method(D_METHOD("set_action_type", "action_type"), &OpenXRAction::set_action_type); + ClassDB::bind_method(D_METHOD("get_action_type"), &OpenXRAction::get_action_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "action_type", PROPERTY_HINT_ENUM, "bool,float,vector2,pose"), "set_action_type", "get_action_type"); + + ClassDB::bind_method(D_METHOD("set_toplevel_paths", "toplevel_paths"), &OpenXRAction::set_toplevel_paths); + ClassDB::bind_method(D_METHOD("get_toplevel_paths"), &OpenXRAction::get_toplevel_paths); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "toplevel_paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_toplevel_paths", "get_toplevel_paths"); + + BIND_ENUM_CONSTANT(OPENXR_ACTION_BOOL); + BIND_ENUM_CONSTANT(OPENXR_ACTION_FLOAT); + BIND_ENUM_CONSTANT(OPENXR_ACTION_VECTOR2); + BIND_ENUM_CONSTANT(OPENXR_ACTION_POSE); +} + +Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRAction> action; + action.instantiate(); + action->set_name(String(p_name)); + action->set_localized_name(String(p_localized_name)); + action->set_action_type(p_action_type); + action->parse_toplevel_paths(String(p_toplevel_paths)); + + return action; +} + +String OpenXRAction::get_name_with_set() const { + String name = get_name(); + + if (action_set != nullptr) { + name = action_set->get_name() + "/" + name; + } + + return name; +} + +void OpenXRAction::set_localized_name(const String p_localized_name) { + localized_name = p_localized_name; +} + +String OpenXRAction::get_localized_name() const { + return localized_name; +} + +void OpenXRAction::set_action_type(const OpenXRAction::ActionType p_action_type) { + action_type = p_action_type; +} + +OpenXRAction::ActionType OpenXRAction::get_action_type() const { + return action_type; +} + +void OpenXRAction::set_toplevel_paths(const PackedStringArray p_toplevel_paths) { + toplevel_paths = p_toplevel_paths; +} + +PackedStringArray OpenXRAction::get_toplevel_paths() const { + return toplevel_paths; +} + +void OpenXRAction::add_toplevel_path(const String p_toplevel_path) { + if (!toplevel_paths.has(p_toplevel_path)) { + toplevel_paths.push_back(p_toplevel_path); + } +} + +void OpenXRAction::rem_toplevel_path(const String p_toplevel_path) { + if (toplevel_paths.has(p_toplevel_path)) { + toplevel_paths.erase(p_toplevel_path); + } +} + +void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) { + toplevel_paths = p_toplevel_paths.split(",", false); +} diff --git a/modules/openxr/action_map/openxr_action.h b/modules/openxr/action_map/openxr_action.h new file mode 100644 index 0000000000..5e57f89133 --- /dev/null +++ b/modules/openxr/action_map/openxr_action.h @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* openxr_action.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_ACTION_H +#define OPENXR_ACTION_H + +#include "core/io/resource.h" + +class OpenXRActionSet; + +class OpenXRAction : public Resource { + GDCLASS(OpenXRAction, Resource); + +public: + enum ActionType { + OPENXR_ACTION_BOOL, + OPENXR_ACTION_FLOAT, + OPENXR_ACTION_VECTOR2, + OPENXR_ACTION_POSE, + OPENXR_ACTION_HAPTIC, + OPENXR_ACTION_MAX + }; + +private: + String localized_name; + ActionType action_type = OPENXR_ACTION_FLOAT; + + PackedStringArray toplevel_paths; + +protected: + friend class OpenXRActionSet; + + OpenXRActionSet *action_set = nullptr; // action belongs to this action set. + + static void _bind_methods(); + +public: + static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); // Helper function to add and configure an action + OpenXRActionSet *get_action_set() const { return action_set; } // Get the action set this action belongs to + + String get_name_with_set() const; // Retrieve the name of this action as <action_set>/<action> + + void set_localized_name(const String p_localized_name); // Set the localized name of this action + String get_localized_name() const; // Get the localized name of this action + + void set_action_type(const ActionType p_action_type); // Set the type of this action + ActionType get_action_type() const; // Get the type of this action + + void set_toplevel_paths(const PackedStringArray p_toplevel_paths); // Set the toplevel paths of this action + PackedStringArray get_toplevel_paths() const; // Get the toplevel paths of this action + + void add_toplevel_path(const String p_toplevel_path); // Add a top level path to this action + void rem_toplevel_path(const String p_toplevel_path); // Remove a toplevel path from this action + + void parse_toplevel_paths(const String p_toplevel_paths); // Parse and set the top level paths from a comma separated string +}; + +VARIANT_ENUM_CAST(OpenXRAction::ActionType); + +#endif // !OPENXR_ACTION_H diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp new file mode 100644 index 0000000000..366e131369 --- /dev/null +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -0,0 +1,475 @@ +/*************************************************************************/ +/* openxr_action_map.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_action_map.h" + +void OpenXRActionMap::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_action_sets", "action_sets"), &OpenXRActionMap::set_action_sets); + ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets"); + + ClassDB::bind_method(D_METHOD("get_action_set_count"), &OpenXRActionMap::get_action_set_count); + ClassDB::bind_method(D_METHOD("find_action_set", "name"), &OpenXRActionMap::find_action_set); + ClassDB::bind_method(D_METHOD("get_action_set", "idx"), &OpenXRActionMap::get_action_set); + ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set); + ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set); + + ClassDB::bind_method(D_METHOD("set_interaction_profiles", "interaction_profiles"), &OpenXRActionMap::set_interaction_profiles); + ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles"); + + ClassDB::bind_method(D_METHOD("get_interaction_profile_count"), &OpenXRActionMap::get_interaction_profile_count); + ClassDB::bind_method(D_METHOD("find_interaction_profile", "name"), &OpenXRActionMap::find_interaction_profile); + ClassDB::bind_method(D_METHOD("get_interaction_profile", "idx"), &OpenXRActionMap::get_interaction_profile); + ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile); + ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile); + + ClassDB::bind_method(D_METHOD("create_default_action_sets"), &OpenXRActionMap::create_default_action_sets); +} + +void OpenXRActionMap::set_action_sets(Array p_action_sets) { + action_sets.clear(); + + for (int i = 0; i < p_action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = p_action_sets[i]; + if (action_set.is_valid() && action_sets.find(action_set) == -1) { + action_sets.push_back(action_set); + } + } +} + +Array OpenXRActionMap::get_action_sets() const { + return action_sets; +} + +int OpenXRActionMap::get_action_set_count() const { + return action_sets.size(); +} + +Ref<OpenXRActionSet> OpenXRActionMap::find_action_set(String p_name) const { + for (int i = 0; i < action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = action_sets[i]; + if (action_set->get_name() == p_name) { + return action_set; + } + } + + return Ref<OpenXRActionSet>(); +} + +Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, action_sets.size(), Ref<OpenXRActionSet>()); + + return action_sets[p_idx]; +} + +void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) { + ERR_FAIL_COND(p_action_set.is_null()); + + if (action_sets.find(p_action_set) == -1) { + action_sets.push_back(p_action_set); + } +} + +void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) { + int idx = action_sets.find(p_action_set); + if (idx != -1) { + action_sets.remove_at(idx); + } +} + +void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) { + interaction_profiles.clear(); + + for (int i = 0; i < p_interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profiles[i]; + if (interaction_profile.is_valid() && interaction_profiles.find(interaction_profile) == -1) { + interaction_profiles.push_back(interaction_profile); + } + } +} + +Array OpenXRActionMap::get_interaction_profiles() const { + return interaction_profiles; +} + +int OpenXRActionMap::get_interaction_profile_count() const { + return interaction_profiles.size(); +} + +Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const { + for (int i = 0; i < interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i]; + if (interaction_profile->get_interaction_profile_path() == p_path) { + return interaction_profile; + } + } + + return Ref<OpenXRInteractionProfile>(); +} + +Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, interaction_profiles.size(), Ref<OpenXRInteractionProfile>()); + + return interaction_profiles[p_idx]; +} + +void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) { + ERR_FAIL_COND(p_interaction_profile.is_null()); + + if (interaction_profiles.find(p_interaction_profile) == -1) { + interaction_profiles.push_back(p_interaction_profile); + } +} + +void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) { + int idx = interaction_profiles.find(p_interaction_profile); + if (idx != -1) { + interaction_profiles.remove_at(idx); + } +} + +void OpenXRActionMap::create_default_action_sets() { + // Note, if you make changes here make sure to delete your default_action_map.tres file of it will load an old version. + + // Create our Godot action set + Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set"); + add_action_set(action_set); + + // Create our actions + Ref<OpenXRAction> trigger = action_set->add_new_action("trigger", "Trigger", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> trigger_click = action_set->add_new_action("trigger_click", "Trigger click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip_touch = action_set->add_new_action("grip_touch", "Grip touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> primary_touch = action_set->add_new_action("primary_touch", "Primary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> secondary = action_set->add_new_action("secondary", "Secondary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> secondary_click = action_set->add_new_action("secondary_click", "Secondary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> secondary_touch = action_set->add_new_action("secondary_touch", "Secondary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> menu_button = action_set->add_new_action("menu_button", "Menu button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> select_button = action_set->add_new_action("select_button", "Select button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> ax_button = action_set->add_new_action("ax_button", "A/X button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> ax_touch = action_set->add_new_action("ax_touch", "A/X touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> by_button = action_set->add_new_action("by_button", "B/Y button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> by_touch = action_set->add_new_action("by_touch", "B/Y touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> default_pose = action_set->add_new_action("default_pose", "Default pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> aim_pose = action_set->add_new_action("aim_pose", "Aim pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> grip_pose = action_set->add_new_action("grip_pose", "Grip pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC, "/user/hand/left,/user/hand/right"); + + // Create our interaction profiles + Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click"); + // generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); + // wmr controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our vive controller is our trackpad + profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + // vive controllers have no secondary input + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our WMR controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // wmr controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // wmr controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will convert float to bool + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our wmr controller is our thumbstick, no touch + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // secondary on our wmr controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Meta touch controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // touch controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch"); + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our touch controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // touch controller has no secondary input + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Valve index controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // index controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); + profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers + profile->add_new_binding(ax_touch, "/user/hand/left/input/a/touch,/user/hand/right/input/a/touch"); + profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers + profile->add_new_binding(by_touch, "/user/hand/left/input/b/touch,/user/hand/right/input/b/touch"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion + // primary on our index controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // secondary on our index controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/force,/user/hand/right/input/trackpad/force"); // not sure if this will work but doesn't seem to support click... + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Note, the following profiles are all part of extensions. + // We include these regardless of whether the extension is active. + // We want our action map to be as complete as possible so our game is as portable as possible. + // It is very possible these will in due time become core. + + // Create our HP MR controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // hpmr controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // hpmr controllers only register click, not touch, on our a/b/x/y buttons + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our hpmr controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // No secondary on our hpmr controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Samsung Odyssey controller profile, + // Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller. + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // Odyssey controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // Odyssey controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Odyssey controller is our thumbstick, no touch + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // secondary on our Odyssey controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive Cosmos controller + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Cosmos controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // No secondary on our cosmos controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive Focus 3 controller + // Note, Vive Focus 3 currently is not yet supported as a stand alone device + // however HTC currently has a beta OpenXR runtime in testing we may support in the near future + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Focus 3 controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // We only have a thumb rest + profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Huawei controller + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + // primary on our Huawei controller is our trackpad + profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); +} + +void OpenXRActionMap::create_editor_action_sets() { + // TODO implement +} + +Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const { + PackedStringArray paths = p_path.split("/", false); + ERR_FAIL_COND_V(paths.size() != 2, Ref<OpenXRAction>()); + + Ref<OpenXRActionSet> action_set = find_action_set(paths[0]); + if (action_set.is_valid()) { + return action_set->get_action(paths[1]); + } + + return Ref<OpenXRAction>(); +} + +void OpenXRActionMap::remove_action(const String p_path) { + Ref<OpenXRAction> action = get_action(p_path); + if (action.is_valid()) { + OpenXRActionSet *action_set = action->get_action_set(); + if (action_set != nullptr) { + // Remove the action from this action set + action_set->remove_action(action); + } + + for (int i = 0; i < interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i]; + + // Remove any bindings for this action + interaction_profile->remove_binding_for_action(action); + } + } +} + +PackedStringArray OpenXRActionMap::get_top_level_paths(Ref<OpenXRAction> p_action) { + PackedStringArray arr; + + for (int i = 0; i < interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> ip = interaction_profiles[i]; + const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(ip->get_interaction_profile_path()); + + if (profile != nullptr) { + for (int j = 0; j < ip->get_binding_count(); j++) { + Ref<OpenXRIPBinding> binding = ip->get_binding(j); + if (binding->get_action() == p_action) { + PackedStringArray paths = binding->get_paths(); + + for (int k = 0; k < paths.size(); k++) { + const OpenXRDefs::IOPath *io_path = profile->get_io_path(paths[k]); + if (io_path != nullptr) { + String top_path = String(io_path->top_level_path->openxr_path); + + if (!arr.has(top_path)) { + arr.push_back(top_path); + } + } + } + } + } + } + } + + print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr); + + return arr; +} + +OpenXRActionMap::~OpenXRActionMap() { + action_sets.clear(); + interaction_profiles.clear(); +} diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h new file mode 100644 index 0000000000..dcd8fc71aa --- /dev/null +++ b/modules/openxr/action_map/openxr_action_map.h @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* openxr_action_map.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_ACTION_SETS_H +#define OPENXR_ACTION_SETS_H + +#include "core/io/resource.h" + +#include "openxr_action.h" +#include "openxr_action_set.h" +#include "openxr_interaction_profile.h" + +class OpenXRActionMap : public Resource { + GDCLASS(OpenXRActionMap, Resource); + +private: + Array action_sets; + Array interaction_profiles; + +protected: + static void _bind_methods(); + +public: + void set_action_sets(Array p_action_sets); // Set our actions sets by providing an array with action sets (for loading from resource) + Array get_action_sets() const; // Get our action sets as an array (for saving to resource) + + int get_action_set_count() const; // Retrieve the number of action sets we have + Ref<OpenXRActionSet> find_action_set(String p_name) const; // Find an action set by name + Ref<OpenXRActionSet> get_action_set(int p_idx) const; // Retrieve an action set by index + void add_action_set(Ref<OpenXRActionSet> p_action_set); // Add an action set to our action map + void remove_action_set(Ref<OpenXRActionSet> p_action_set); // Remove an action set from our action map + + void set_interaction_profiles(Array p_interaction_profiles); // Set our interaction profiles by providing an array (for loading from resource) + Array get_interaction_profiles() const; // Get our interaction profiles as an array (for saving to resource) + + int get_interaction_profile_count() const; // Retrieve the number of interaction profiles we have + Ref<OpenXRInteractionProfile> find_interaction_profile(String p_path) const; // Find an interaction profile by path + Ref<OpenXRInteractionProfile> get_interaction_profile(int p_idx) const; // Retrieve an interaction profile by index + void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // Add an interaction profile to our action map + void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // remove an interaction profile from our action map + + void create_default_action_sets(); // Create our default action set for runtime + void create_editor_action_sets(); // Create our action set for the editor + + // Helper functions for editor + Ref<OpenXRAction> get_action(const String p_path) const; // Retrieve an action using <action name>/<action> as our parameter + void remove_action(const String p_path); // Remove action from action set, also removes it from interaction profiles + PackedStringArray get_top_level_paths(Ref<OpenXRAction> p_action); // Determines the top level paths based on where an action is bound in interaction profiles + + // TODO add validation to display in the interface that checks if we have action sets with the same name or if we have interaction profiles for the same path + + ~OpenXRActionMap(); +}; + +#endif // !OPENXR_ACTION_SETS_H diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp new file mode 100644 index 0000000000..be45218300 --- /dev/null +++ b/modules/openxr/action_map/openxr_action_set.cpp @@ -0,0 +1,151 @@ +/*************************************************************************/ +/* openxr_action_set.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_action_set.h" + +void OpenXRActionSet::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRActionSet::set_localized_name); + ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRActionSet::get_localized_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name"); + + ClassDB::bind_method(D_METHOD("set_priority", "priority"), &OpenXRActionSet::set_priority); + ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority); + ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority"); + + ClassDB::bind_method(D_METHOD("get_action_count"), &OpenXRActionSet::get_action_count); + ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions); + ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions"); + + ClassDB::bind_method(D_METHOD("add_action", "action"), &OpenXRActionSet::add_action); + ClassDB::bind_method(D_METHOD("remove_action", "action"), &OpenXRActionSet::remove_action); +} + +Ref<OpenXRActionSet> OpenXRActionSet::new_action_set(const char *p_name, const char *p_localized_name, const int p_priority) { + // This is a helper function to help build our default action sets + + Ref<OpenXRActionSet> action_set; + action_set.instantiate(); + action_set->set_name(String(p_name)); + action_set->set_localized_name(p_localized_name); + action_set->set_priority(p_priority); + + return action_set; +} + +void OpenXRActionSet::set_localized_name(const String p_localized_name) { + localized_name = p_localized_name; +} + +String OpenXRActionSet::get_localized_name() const { + return localized_name; +} + +void OpenXRActionSet::set_priority(const int p_priority) { + priority = p_priority; +} + +int OpenXRActionSet::get_priority() const { + return priority; +} + +int OpenXRActionSet::get_action_count() const { + return actions.size(); +} + +void OpenXRActionSet::clear_actions() { + // Actions held within our action set should be released and destroyed but just in case they are still used some where else + for (int i = 0; i < actions.size(); i++) { + Ref<OpenXRAction> action = actions[i]; + action->action_set = nullptr; + } + actions.clear(); +} + +void OpenXRActionSet::set_actions(Array p_actions) { + // Any actions not retained in p_actions should be freed automatically, those held within our Array will have be relinked to our action set. + clear_actions(); + + for (int i = 0; i < p_actions.size(); i++) { + // add them anew so we verify our action_set pointer + add_action(p_actions[i]); + } +} + +Array OpenXRActionSet::get_actions() const { + return actions; +} + +Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const { + for (int i = 0; i < actions.size(); i++) { + Ref<OpenXRAction> action = actions[i]; + if (action->get_name() == p_name) { + return action; + } + } + + return Ref<OpenXRAction>(); +} + +void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) { + ERR_FAIL_COND(p_action.is_null()); + + if (actions.find(p_action) == -1) { + if (p_action->action_set && p_action->action_set != this) { + // action should only relate to our action set + p_action->action_set->remove_action(p_action); + } + + p_action->action_set = this; + actions.push_back(p_action); + } +} + +void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) { + int idx = actions.find(p_action); + if (idx != -1) { + actions.remove_at(idx); + + ERR_FAIL_COND_MSG(p_action->action_set != this, "Removing action that belongs to this action set but had incorrect action set pointer."); // this should never happen! + p_action->action_set = nullptr; + } +} + +Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRAction> new_action = OpenXRAction::new_action(p_name, p_localized_name, p_action_type, p_toplevel_paths); + add_action(new_action); + return new_action; +} + +OpenXRActionSet::~OpenXRActionSet() { + clear_actions(); +} diff --git a/modules/openxr/action_map/openxr_action_set.h b/modules/openxr/action_map/openxr_action_set.h new file mode 100644 index 0000000000..b1d7168894 --- /dev/null +++ b/modules/openxr/action_map/openxr_action_set.h @@ -0,0 +1,75 @@ +/*************************************************************************/ +/* openxr_action_set.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_ACTION_SET_H +#define OPENXR_ACTION_SET_H + +#include "core/io/resource.h" + +#include "openxr_action.h" + +class OpenXRActionSet : public Resource { + GDCLASS(OpenXRActionSet, Resource); + +private: + String localized_name; + int priority = 0; + + Array actions; + void clear_actions(); + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); // Helper function for adding and setting up an action set + + void set_localized_name(const String p_localized_name); // Set the localized name of this action set + String get_localized_name() const; // Get the localized name of this action set + + void set_priority(const int p_priority); // Set the priority of this action set + int get_priority() const; // Get the priority of this action set + + int get_action_count() const; // Retrieve the number of actions in our action set + void set_actions(Array p_actions); // Set our actions using an array of actions (for loading a resource) + Array get_actions() const; // Get our actions as an array (for saving a resource) + + Ref<OpenXRAction> get_action(const String p_name) const; // Retrieve an action by name + void add_action(Ref<OpenXRAction> p_action); // Add a new action to our action set + void remove_action(Ref<OpenXRAction> p_action); // remove a action from our action set + + Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); // Helper function for adding and setting up an action + + // TODO add validation to display in the interface that checks if we have duplicate action names within our action set + + ~OpenXRActionSet(); +}; + +#endif // !OPENXR_ACTION_SET_H diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp new file mode 100644 index 0000000000..e10326449c --- /dev/null +++ b/modules/openxr/action_map/openxr_defs.cpp @@ -0,0 +1,493 @@ +/*************************************************************************/ +/* openxr_defs.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_defs.h" + +// Our top level paths to which devices can be bound +OpenXRDefs::TopLevelPath OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_TOP_LEVEL_PATH_MAX] = { + { "Left hand controller", "/user/hand/left" }, + { "Right hand controller", "/user/hand/right" }, +}; + +// Fallback Khronos simple controller +OpenXRDefs::IOPath OpenXRDefs::simple_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Original HTC Vive wands +OpenXRDefs::IOPath OpenXRDefs::vive_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Microsoft motion controller (original WMR controllers) +OpenXRDefs::IOPath OpenXRDefs::motion_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// HP MR controller (newer G2 controllers) +OpenXRDefs::IOPath OpenXRDefs::hpmr_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers) +OpenXRDefs::IOPath OpenXRDefs::touch_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "X touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Valve index controller +OpenXRDefs::IOPath OpenXRDefs::index_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Samsung odyssey controller +OpenXRDefs::IOPath OpenXRDefs::odyssey_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Vive Cosmos controller +OpenXRDefs::IOPath OpenXRDefs::vive_cosmos_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Vive Focus 3 controller +OpenXRDefs::IOPath OpenXRDefs::vive_focus3_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch ", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbrest touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbrest/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Huawei controller +OpenXRDefs::IOPath OpenXRDefs::huawei_controller_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +OpenXRDefs::InteractionProfile OpenXRDefs::available_interaction_profiles[] = { + { + "Simple controller", // display_name + "/interaction_profiles/khr/simple_controller", // openxr_path + simple_io_paths, // io_paths + sizeof(simple_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "HTC Vive wand", // display_name + "/interaction_profiles/htc/vive_controller", // openxr_path + vive_io_paths, // io_paths + sizeof(vive_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "MS Motion controller", // display_name + "/interaction_profiles/microsoft/motion_controller", // openxr_path + motion_io_paths, // io_paths + sizeof(motion_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "HPMR controller", // display_name + "/interaction_profiles/hp/mixed_reality_controller", // openxr_path + hpmr_io_paths, // io_paths + sizeof(hpmr_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Touch controller", // display_name + "/interaction_profiles/oculus/touch_controller", // openxr_path + touch_io_paths, // io_paths + sizeof(touch_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Index controller", // display_name + "/interaction_profiles/valve/index_controller", // openxr_path + index_io_paths, // io_paths + sizeof(index_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Samsung Odyssey controller", // display_name + "/interaction_profiles/samsung/odyssey_controller", // openxr_path + odyssey_io_paths, // io_paths + sizeof(odyssey_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Vive Cosmos controller", // display_name + "/interaction_profiles/htc/vive_cosmos_controller", // openxr_path + vive_cosmos_paths, // io_paths + sizeof(vive_cosmos_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Vive Focus 3 controller", // display_name + "/interaction_profiles/htc/vive_focus3_controller", // openxr_path + vive_focus3_paths, // io_paths + sizeof(vive_focus3_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Huawei controller", // display_name + "/interaction_profiles/huawei/controller", // openxr_path + huawei_controller_paths, // io_paths + sizeof(huawei_controller_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, +}; + +int OpenXRDefs::available_interaction_profile_count = sizeof(OpenXRDefs::available_interaction_profiles) / sizeof(OpenXRDefs::InteractionProfile); + +const OpenXRDefs::TopLevelPath *OpenXRDefs::get_top_level_path(const String p_top_level_path) { + for (int i = 0; i < OPENXR_TOP_LEVEL_PATH_MAX; i++) { + if (available_top_level_paths[i].openxr_path == p_top_level_path) { + return &OpenXRDefs::available_top_level_paths[i]; + } + } + + return nullptr; +} + +const OpenXRDefs::InteractionProfile *OpenXRDefs::get_profile(const String p_interaction_profile_path) { + for (int i = 0; i < available_interaction_profile_count; i++) { + if (available_interaction_profiles[i].openxr_path == p_interaction_profile_path) { + return &available_interaction_profiles[i]; + } + } + + return nullptr; +} + +const OpenXRDefs::IOPath *OpenXRDefs::InteractionProfile::get_io_path(const String p_io_path) const { + for (int i = 0; i < available_interaction_profiles[i].io_path_count; i++) { + if (io_paths[i].openxr_path == p_io_path) { + return &io_paths[i]; + } + } + + return nullptr; +} + +const OpenXRDefs::IOPath *OpenXRDefs::get_io_path(const String p_interaction_profile_path, const String p_io_path) { + const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(p_interaction_profile_path); + if (profile != nullptr) { + return profile->get_io_path(p_io_path); + } + + return nullptr; +} + +PackedStringArray OpenXRDefs::get_interaction_profile_paths() { + PackedStringArray arr; + + for (int i = 0; i < available_interaction_profile_count; i++) { + arr.push_back(available_interaction_profiles[i].openxr_path); + } + + return arr; +} diff --git a/modules/openxr/action_map/openxr_defs.h b/modules/openxr/action_map/openxr_defs.h new file mode 100644 index 0000000000..dbda4757f1 --- /dev/null +++ b/modules/openxr/action_map/openxr_defs.h @@ -0,0 +1,103 @@ +/*************************************************************************/ +/* openxr_defs.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_DEFS_H +#define OPENXR_DEFS_H + +#include "openxr_action.h" + +/////////////////////////////////////////////////////////////////////////// +// Stores available interaction profiles +// +// OpenXR defines and hardcodes all the supported input devices and their +// paths as part of the OpenXR spec. When support for new devices is +// introduced this often starts life as extensions that need to be enabled +// until they are adopted into the core. As there is no interface to +// enumerate the possibly paths, and that any OpenXR runtime would likely +// limit such enumeration to those input devices supported by that runtime +// there is no other option than to hardcode this. +// +// Note on action type that automatic conversions between boolean and float +// are supported but otherwise action types should match between action and +// input/output paths. + +class OpenXRDefs { +public: + enum TOP_LEVEL_PATH { + OPENXR_LEFT_HAND, + OPENXR_RIGHT_HAND, + OPENXR_TOP_LEVEL_PATH_MAX + }; + + struct TopLevelPath { + const char *display_name; // User friendly display name (i.e. Left controller) + const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left) + }; + + struct IOPath { + const char *display_name; // User friendly display name (i.e. Grip pose (left controller)) + const TopLevelPath *top_level_path; // Top level path identifying the usage of the device in relation to this input/output + const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left/input/grip/pose) + const OpenXRAction::ActionType action_type; // Type of input/output + }; + + struct InteractionProfile { + const char *display_name; // User friendly display name (i.e. Simple controller) + const char *openxr_path; // Path in OpenXR (i.e. /interaction_profiles/khr/simple_controller) + const IOPath *io_paths; // Inputs and outputs for this device + const int io_path_count; // Number of inputs and outputs for this device + + const IOPath *get_io_path(const String p_io_path) const; + }; + +private: + static TopLevelPath available_top_level_paths[OPENXR_TOP_LEVEL_PATH_MAX]; + static IOPath simple_io_paths[]; + static IOPath vive_io_paths[]; + static IOPath motion_io_paths[]; + static IOPath hpmr_io_paths[]; + static IOPath touch_io_paths[]; + static IOPath index_io_paths[]; + static IOPath odyssey_io_paths[]; + static IOPath vive_cosmos_paths[]; + static IOPath vive_focus3_paths[]; + static IOPath huawei_controller_paths[]; + static InteractionProfile available_interaction_profiles[]; + static int available_interaction_profile_count; + +public: + static const TopLevelPath *get_top_level_path(const String p_top_level_path); + static const InteractionProfile *get_profile(const String p_interaction_profile_path); + static const IOPath *get_io_path(const String p_interaction_profile_path, const String p_io_path); + + static PackedStringArray get_interaction_profile_paths(); +}; + +#endif // !OPENXR_DEFS_H diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp new file mode 100644 index 0000000000..342c36cdff --- /dev/null +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -0,0 +1,197 @@ +/*************************************************************************/ +/* openxr_interaction_profile.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_interaction_profile.h" + +void OpenXRIPBinding::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_action", "action"), &OpenXRIPBinding::set_action); + ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action"); + + ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count); + ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); + ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths"); + + ClassDB::bind_method(D_METHOD("has_path"), &OpenXRIPBinding::has_path); + ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path); + ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path); +} + +Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRIPBinding> binding; + binding.instantiate(); + binding->set_action(p_action); + binding->parse_paths(String(p_paths)); + + return binding; +} + +void OpenXRIPBinding::set_action(const Ref<OpenXRAction> p_action) { + action = p_action; +} + +Ref<OpenXRAction> OpenXRIPBinding::get_action() const { + return action; +} + +int OpenXRIPBinding::get_path_count() const { + return paths.size(); +} + +void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { + paths = p_paths; +} + +PackedStringArray OpenXRIPBinding::get_paths() const { + return paths; +} + +void OpenXRIPBinding::parse_paths(const String p_paths) { + paths = p_paths.split(",", false); +} + +bool OpenXRIPBinding::has_path(const String p_path) const { + return paths.has(p_path); +} + +void OpenXRIPBinding::add_path(const String p_path) { + if (!paths.has(p_path)) { + paths.push_back(p_path); + } +} + +void OpenXRIPBinding::remove_path(const String p_path) { + if (paths.has(p_path)) { + paths.erase(p_path); + } +} + +OpenXRIPBinding::~OpenXRIPBinding() { + action.unref(); +} + +void OpenXRInteractionProfile::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_interaction_profile_path", "interaction_profile_path"), &OpenXRInteractionProfile::set_interaction_profile_path); + ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path"); + + ClassDB::bind_method(D_METHOD("get_binding_count"), &OpenXRInteractionProfile::get_binding_count); + ClassDB::bind_method(D_METHOD("get_binding", "index"), &OpenXRInteractionProfile::get_binding); + ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings); + ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings"); +} + +Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) { + Ref<OpenXRInteractionProfile> profile; + profile.instantiate(); + profile->set_interaction_profile_path(String(p_input_profile_path)); + + return profile; +} + +void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) { + interaction_profile_path = p_input_profile_path; +} + +String OpenXRInteractionProfile::get_interaction_profile_path() const { + return interaction_profile_path; +} + +int OpenXRInteractionProfile::get_binding_count() const { + return bindings.size(); +} + +Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const { + ERR_FAIL_INDEX_V(p_index, bindings.size(), Ref<OpenXRIPBinding>()); + + return bindings[p_index]; +} + +void OpenXRInteractionProfile::set_bindings(Array p_bindings) { + bindings = p_bindings; + + // TODO add check here that our bindings don't contain duplicate actions +} + +Array OpenXRInteractionProfile::get_bindings() const { + return bindings; +} + +Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const { + for (int i = 0; i < bindings.size(); i++) { + Ref<OpenXRIPBinding> binding = bindings[i]; + if (binding->get_action() == p_action) { + return binding; + } + } + + return Ref<OpenXRIPBinding>(); +} + +void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) { + ERR_FAIL_COND(p_binding.is_null()); + + if (bindings.find(p_binding) == -1) { + ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile"); + + bindings.push_back(p_binding); + } +} + +void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) { + int idx = bindings.find(p_binding); + if (idx != -1) { + bindings.remove_at(idx); + } +} + +void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) { + // This is a helper function to help build our default action sets + + Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, p_paths); + add_binding(binding); +} + +void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> p_action) { + for (int i = bindings.size() - 1; i >= 0; i--) { + Ref<OpenXRIPBinding> binding = bindings[i]; + if (binding->get_action() == p_action) { + remove_binding(binding); + } + } +} + +OpenXRInteractionProfile::~OpenXRInteractionProfile() { + bindings.clear(); +} diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h new file mode 100644 index 0000000000..46b1bda50f --- /dev/null +++ b/modules/openxr/action_map/openxr_interaction_profile.h @@ -0,0 +1,101 @@ +/*************************************************************************/ +/* openxr_interaction_profile.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_INTERACTION_PROFILE_H +#define OPENXR_INTERACTION_PROFILE_H + +#include "core/io/resource.h" + +#include "openxr_action.h" +#include "openxr_defs.h" + +class OpenXRIPBinding : public Resource { + GDCLASS(OpenXRIPBinding, Resource); + +private: + Ref<OpenXRAction> action; + PackedStringArray paths; + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Helper function for adding a new binding + + void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding + Ref<OpenXRAction> get_action() const; // Get the action for this binding + + int get_path_count() const; // Get the number of io paths + void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource) + PackedStringArray get_paths() const; // Get our paths (for saving to resource) + + void parse_paths(const String p_paths); // Parse a comma separated string of io paths. + + bool has_path(const String p_path) const; // Has this io path + void add_path(const String p_path); // Add an io path + void remove_path(const String p_path); // Remove an io path + + // TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path + + ~OpenXRIPBinding(); +}; + +class OpenXRInteractionProfile : public Resource { + GDCLASS(OpenXRInteractionProfile, Resource); + +private: + String interaction_profile_path; + Array bindings; + +protected: + static void _bind_methods(); + +public: + static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); // Helper function to create a new interaction profile + + void set_interaction_profile_path(const String p_input_profile_path); // Set our input profile path + String get_interaction_profile_path() const; // get our input profile path + + int get_binding_count() const; // Retrieve the number of bindings in this profile path + Ref<OpenXRIPBinding> get_binding(int p_index) const; + void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource) + Array get_bindings() const; // Get the bindings (for saving to a resource) + + Ref<OpenXRIPBinding> get_binding_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action + void add_binding(Ref<OpenXRIPBinding> p_binding); // Add a binding object + void remove_binding(Ref<OpenXRIPBinding> p_binding); // Remove a binding object + + void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Create a new binding for this profile + void remove_binding_for_action(const Ref<OpenXRAction> p_action); // Remove all bindings for this action + + ~OpenXRInteractionProfile(); +}; + +#endif // !OPENXR_INTERACTION_PROFILE_H diff --git a/modules/openxr/config.py b/modules/openxr/config.py new file mode 100644 index 0000000000..f91cb1359f --- /dev/null +++ b/modules/openxr/config.py @@ -0,0 +1,27 @@ +def can_build(env, platform): + if ( + platform == "linuxbsd" or platform == "windows" + ): # or platform == "android" -- temporarily disabled android support + return env["openxr"] + else: + # not supported on these platforms + return False + + +def configure(env): + pass + + +def get_doc_classes(): + return [ + "OpenXRInterface", + "OpenXRAction", + "OpenXRActionSet", + "OpenXRActionMap", + "OpenXRInteractionProfile", + "OpenXRIPBinding", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml new file mode 100644 index 0000000000..6ff8c1ad26 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRAction.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRAction" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + An OpenXR action. + </brief_description> + <description> + This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics). + OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/core] if the trigger is depressed and [code]true[/code] if pressed fully. + Actions are not directly bound to specific devices, instead OpenXR recognises a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths. + Note that the name of the resource is used to register the action with. + </description> + <tutorials> + </tutorials> + <members> + <member name="action_type" type="int" setter="set_action_type" getter="get_action_type" enum="OpenXRAction.ActionType" default="1"> + The type of action. + </member> + <member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default=""""> + The localised description of this action. + </member> + <member name="toplevel_paths" type="PackedStringArray" setter="set_toplevel_paths" getter="get_toplevel_paths" default="PackedStringArray()"> + A collections of toplevel paths to which this action can be bound. + </member> + </members> + <constants> + <constant name="OPENXR_ACTION_BOOL" value="0" enum="ActionType"> + This action provides a boolean value. + </constant> + <constant name="OPENXR_ACTION_FLOAT" value="1" enum="ActionType"> + This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analogue input such as triggers. + </constant> + <constant name="OPENXR_ACTION_VECTOR2" value="2" enum="ActionType"> + This action provides a vector2 value and can be bound to embedded trackpads and joysticks + </constant> + <constant name="OPENXR_ACTION_POSE" value="3" enum="ActionType"> + </constant> + </constants> +</class> diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml new file mode 100644 index 0000000000..a29d10be41 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRActionMap.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRActionMap" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Collection of [OpenXRActionSet] and [OpenXRInteractionProfile] resources for the OpenXR module. + </brief_description> + <description> + OpenXR uses an action system similar to Godots Input map system to bind inputs and outputs on various types of XR controllers to named actions. OpenXR specifies more detail on these inputs and outputs than Godot supports. + Another important distinction is that OpenXR offers no control over these bindings. The bindings we register are suggestions, it is up to the XR runtime to offer users the ability to change these bindings. This allows the XR runtime to fill in the gaps if new hardware becomes available. + The action map therefore needs to be loaded at startup and can't be changed afterwards. This resource is a container for the entire action map. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_action_set"> + <return type="void" /> + <argument index="0" name="action_set" type="OpenXRActionSet" /> + <description> + Add an action set. + </description> + </method> + <method name="add_interaction_profile"> + <return type="void" /> + <argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" /> + <description> + Add an interaction profile. + </description> + </method> + <method name="create_default_action_sets"> + <return type="void" /> + <description> + Setup this action set with our default actions. + </description> + </method> + <method name="find_action_set" qualifiers="const"> + <return type="OpenXRActionSet" /> + <argument index="0" name="name" type="String" /> + <description> + Retrieve an action set by name. + </description> + </method> + <method name="find_interaction_profile" qualifiers="const"> + <return type="OpenXRInteractionProfile" /> + <argument index="0" name="name" type="String" /> + <description> + Find an interaction profile by its name (path). + </description> + </method> + <method name="get_action_set" qualifiers="const"> + <return type="OpenXRActionSet" /> + <argument index="0" name="idx" type="int" /> + <description> + Retrieve the action set at this index. + </description> + </method> + <method name="get_action_set_count" qualifiers="const"> + <return type="int" /> + <description> + Retrieve the number of actions sets in our action map. + </description> + </method> + <method name="get_interaction_profile" qualifiers="const"> + <return type="OpenXRInteractionProfile" /> + <argument index="0" name="idx" type="int" /> + <description> + Get the interaction profile at this index. + </description> + </method> + <method name="get_interaction_profile_count" qualifiers="const"> + <return type="int" /> + <description> + Retrieve the number of interaction profiles in our action map. + </description> + </method> + <method name="remove_action_set"> + <return type="void" /> + <argument index="0" name="action_set" type="OpenXRActionSet" /> + <description> + Remove an action set. + </description> + </method> + <method name="remove_interaction_profile"> + <return type="void" /> + <argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" /> + <description> + Remove an interaction profile. + </description> + </method> + </methods> + <members> + <member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]"> + Collection of [OpenXRActionSet]s that are part of this action map. + </member> + <member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]"> + Collection of [OpenXRInteractionProfile]s that are part of this action map. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml new file mode 100644 index 0000000000..55cc0aaad4 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRActionSet.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRActionSet" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Collection of [OpenXRAction] resources that make up an action set. + </brief_description> + <description> + Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle. + Action sets can contain the same action with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_action"> + <return type="void" /> + <argument index="0" name="action" type="OpenXRAction" /> + <description> + Add an action to this action set. + </description> + </method> + <method name="get_action_count" qualifiers="const"> + <return type="int" /> + <description> + Retrieve the number of actions in our action set. + </description> + </method> + <method name="remove_action"> + <return type="void" /> + <argument index="0" name="action" type="OpenXRAction" /> + <description> + Remove an action from this action set. + </description> + </method> + </methods> + <members> + <member name="actions" type="Array" setter="set_actions" getter="get_actions" default="[]"> + Collection of actions for this action set. + </member> + <member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default=""""> + The localised name of this action set. + </member> + <member name="priority" type="int" setter="set_priority" getter="get_priority" default="0"> + The priority for this action set. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml new file mode 100644 index 0000000000..9e1176874a --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRIPBinding" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Defines a binding between an [OpenXRAction] and an XR input or output. + </brief_description> + <description> + This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_path"> + <return type="void" /> + <argument index="0" name="path" type="String" /> + <description> + Add an input/output path to this binding. + </description> + </method> + <method name="get_path_count" qualifiers="const"> + <return type="int" /> + <description> + Get the number of input/output paths in this binding. + </description> + </method> + <method name="has_path" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="arg0" type="String" /> + <description> + Returns [code]true[/code] if this input/output path is part of this binding. + </description> + </method> + <method name="remove_path"> + <return type="void" /> + <argument index="0" name="path" type="String" /> + <description> + Removes this input/output path from this binding. + </description> + </method> + </methods> + <members> + <member name="action" type="OpenXRAction" setter="set_action" getter="get_action"> + [OpenXRAction] that is bound to these paths. + </member> + <member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()"> + Paths that define the inputs or outputs bound on the device. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml new file mode 100644 index 0000000000..71c0db44ed --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRInteractionProfile" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Suggested bindings object for OpenXR. + </brief_description> + <description> + This object stores suggested bindings for an interaction profile. Interaction profiles define the meta data for a tracked XR device such as an XR controller. + For more information see the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-interaction-profiles]interaction profiles info in the OpenXR specification[/url]. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_binding" qualifiers="const"> + <return type="OpenXRIPBinding" /> + <argument index="0" name="index" type="int" /> + <description> + Retrieve the binding at this index. + </description> + </method> + <method name="get_binding_count" qualifiers="const"> + <return type="int" /> + <description> + Get the number of bindings in this interaction profile. + </description> + </method> + </methods> + <members> + <member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]"> + Action bindings for this interaction profile. + </member> + <member name="interaction_profile_path" type="String" setter="set_interaction_profile_path" getter="get_interaction_profile_path" default=""""> + The interaction profile path identifying the XR device. + </member> + </members> +</class> diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml new file mode 100644 index 0000000000..74f708bc95 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRInterface" inherits="XRInterface" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Our OpenXR interface. + </brief_description> + <description> + The OpenXR interface allows Godot to interact with OpenXR runtimes and make it possible to create XR experiences and games. + Due to the needs of OpenXR this interface works slightly different then other plugin based XR interfaces. It needs to be initialised when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset. + </description> + <tutorials> + <link title="OpenXR documentation">$DOCS_URL/tutorials/vr/openxr/index.html</link> + </tutorials> + <signals> + <signal name="pose_recentered"> + <description> + Informs the user queued a recenter of the player position. + </description> + </signal> + <signal name="session_begun"> + <description> + Informs our OpenXR session has been started. + </description> + </signal> + <signal name="session_focussed"> + <description> + Informs our OpenXR session now has focus. + </description> + </signal> + <signal name="session_stopping"> + <description> + Informs our OpenXR session is stopping. + </description> + </signal> + <signal name="session_visible"> + <description> + Informs our OpenXR session is now visible (output is being sent to the HMD). + </description> + </signal> + </signals> +</class> diff --git a/modules/openxr/editor/SCsub b/modules/openxr/editor/SCsub new file mode 100644 index 0000000000..ccf67a80d0 --- /dev/null +++ b/modules/openxr/editor/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp new file mode 100644 index 0000000000..e2a4f67f16 --- /dev/null +++ b/modules/openxr/editor/openxr_action_editor.cpp @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* openxr_action_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_action_editor.h" + +void OpenXRActionEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor"))); +} + +void OpenXRActionEditor::_theme_changed() { + rem_action->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); +} + +void OpenXRActionEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + _theme_changed(); + } break; + } +} + +void OpenXRActionEditor::_on_action_name_changed(const String p_new_text) { + // TODO validate if entry is allowed + + // If our localized name matches our action name, set this too + if (action->get_name() == action->get_localized_name()) { + action->set_localized_name(p_new_text); + action_localized_name->set_text(p_new_text); + } + action->set_name(p_new_text); +} + +void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_text) { + action->set_localized_name(p_new_text); +} + +void OpenXRActionEditor::_on_item_selected(int p_idx) { + ERR_FAIL_COND(p_idx < 0); + ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX); + + action->set_action_type(OpenXRAction::ActionType(p_idx)); +} + +void OpenXRActionEditor::_on_remove_action() { + emit_signal("remove", this); +} + +OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) { + action = p_action; + + set_h_size_flags(Control::SIZE_EXPAND_FILL); + + action_name = memnew(LineEdit); + action_name->set_text(action->get_name()); + action_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_name_changed)); + add_child(action_name); + + action_localized_name = memnew(LineEdit); + action_localized_name->set_text(action->get_localized_name()); + action_localized_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); + action_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_localized_name_changed)); + add_child(action_localized_name); + + action_type = memnew(OptionButton); + action_type->add_item("Bool", OpenXRAction::OPENXR_ACTION_BOOL); + action_type->add_item("Float", OpenXRAction::OPENXR_ACTION_FLOAT); + action_type->add_item("Vector2", OpenXRAction::OPENXR_ACTION_VECTOR2); + action_type->add_item("Pose", OpenXRAction::OPENXR_ACTION_POSE); + action_type->add_item("Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC); + action_type->select(int(action->get_action_type())); + action_type->set_custom_minimum_size(Size2(100.0, 0.0)); + action_type->connect("item_selected", callable_mp(this, &OpenXRActionEditor::_on_item_selected)); + add_child(action_type); + + // maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings? + + rem_action = memnew(Button); + rem_action->set_tooltip(TTR("Remove action")); + rem_action->connect("pressed", callable_mp(this, &OpenXRActionEditor::_on_remove_action)); + rem_action->set_flat(true); + add_child(rem_action); +} diff --git a/modules/basis_universal/texture_basisu.h b/modules/openxr/editor/openxr_action_editor.h index 3316035404..6e1b7ab779 100644 --- a/modules/basis_universal/texture_basisu.h +++ b/modules/openxr/editor/openxr_action_editor.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* texture_basisu.h */ +/* openxr_action_editor.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,53 +28,40 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BASIS_UNIVERSAL_TEXTURE_BASISU_H -#define BASIS_UNIVERSAL_TEXTURE_BASISU_H +#ifndef OPENXR_ACTION_EDITOR_H +#define OPENXR_ACTION_EDITOR_H -#include "scene/resources/texture.h" +#include "../action_map/openxr_action.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/option_button.h" +#include "scene/gui/text_edit.h" -#ifdef TOOLS_ENABLED -#include <encoder/basisu_comp.h> -#endif +class OpenXRActionEditor : public HBoxContainer { + GDCLASS(OpenXRActionEditor, HBoxContainer); -#include <transcoder/basisu_transcoder.h> +private: + Ref<OpenXRAction> action; -#if 0 -class TextureBasisU : public Texture { - GDCLASS(TextureBasisU, Texture); - RES_BASE_EXTENSION("butex"); + LineEdit *action_name = nullptr; + LineEdit *action_localized_name = nullptr; + OptionButton *action_type = nullptr; + Button *rem_action = nullptr; - RID texture; - Size2 tex_size; - - uint32_t flags = FLAGS_DEFAULT; - - Vector<uint8_t> data; + void _theme_changed(); + void _on_action_name_changed(const String p_new_text); + void _on_action_localized_name_changed(const String p_new_text); + void _on_item_selected(int p_idx); + void _on_remove_action(); +protected: static void _bind_methods(); + void _notification(int p_what); public: - - virtual int get_width() const; - virtual int get_height() const; - virtual RID get_rid() const; - virtual bool has_alpha() const; - - virtual void set_flags(uint32_t p_flags); - virtual uint32_t get_flags() const; - - - Error import(const Ref<Image> &p_img); - - void set_basisu_data(const Vector<uint8_t>& p_data); - - Vector<uint8_t> get_basisu_data() const; - String get_img_path() const; - - TextureBasisU(); - ~TextureBasisU(); + Ref<OpenXRAction> get_action() { return action; }; + OpenXRActionEditor(Ref<OpenXRAction> p_action); }; -#endif - -#endif // BASIS_UNIVERSAL_TEXTURE_BASISU_H +#endif // !OPENXR_ACTION_EDITOR_H diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp new file mode 100644 index 0000000000..6e9a2e1b61 --- /dev/null +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -0,0 +1,370 @@ +/*************************************************************************/ +/* openxr_action_map_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_action_map_editor.h" + +#include "core/config/project_settings.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" + +// TODO implement redo/undo system + +void OpenXRActionMapEditor::_bind_methods() { + ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor); + ClassDB::bind_method("_update_action_sets", &OpenXRActionMapEditor::_update_action_sets); + + ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor); + ClassDB::bind_method("_update_interaction_profiles", &OpenXRActionMapEditor::_update_interaction_profiles); + + ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set); + ClassDB::bind_method(D_METHOD("_set_focus_on_action_set", "action_set"), &OpenXRActionMapEditor::_set_focus_on_action_set); + ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set); +} + +void OpenXRActionMapEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + for (int i = 0; i < tabs->get_child_count(); i++) { + Control *tab = static_cast<Control *>(tabs->get_child(i)); + if (tab) { + tab->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + } + } + } break; + + case NOTIFICATION_READY: { + _update_action_sets(); + _update_interaction_profiles(); + } break; + } +} + +OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(Ref<OpenXRActionSet> p_action_set) { + ERR_FAIL_COND_V(p_action_set.is_null(), nullptr); + + OpenXRActionSetEditor *action_set_editor = memnew(OpenXRActionSetEditor(action_map, p_action_set)); + action_set_editor->connect("remove", callable_mp(this, &OpenXRActionMapEditor::_on_remove_action_set)); + action_set_editor->connect("action_removed", callable_mp(this, &OpenXRActionMapEditor::_on_action_removed)); + actionsets_vb->add_child(action_set_editor); + + return action_set_editor; +} + +void OpenXRActionMapEditor::_update_action_sets() { + // out with the old... + while (actionsets_vb->get_child_count() > 0) { + memdelete(actionsets_vb->get_child(0)); + } + + // in with the new... + if (action_map.is_valid()) { + Array action_sets = action_map->get_action_sets(); + for (int i = 0; i < action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = action_sets[i]; + _add_action_set_editor(action_set); + } + } +} + +OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile) { + ERR_FAIL_COND_V(p_interaction_profile.is_null(), nullptr); + + String profile_path = p_interaction_profile->get_interaction_profile_path(); + + // need to instance the correct editor for our profile + OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr; + if (profile_path == "placeholder_text") { + // instance specific editor for this type + } else { + // instance generic editor + new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile)); + } + + // now add it in.. + ERR_FAIL_NULL_V(new_profile_editor, nullptr); + tabs->add_child(new_profile_editor); + new_profile_editor->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar"))); + + interaction_profiles.push_back(new_profile_editor); + + return new_profile_editor; +} + +void OpenXRActionMapEditor::_update_interaction_profiles() { + // out with the old... + while (interaction_profiles.size() > 0) { + Node *interaction_profile = interaction_profiles[0]; + interaction_profiles.remove_at(0); + + tabs->remove_child(interaction_profile); + interaction_profile->queue_delete(); + } + + // in with the new... + if (action_map.is_valid()) { + Array new_interaction_profiles = action_map->get_interaction_profiles(); + for (int i = 0; i < new_interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> interaction_profile = new_interaction_profiles[i]; + _add_interaction_profile_editor(interaction_profile); + } + } +} + +OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(String p_name) { + ERR_FAIL_COND_V(action_map.is_null(), nullptr); + Ref<OpenXRActionSet> new_action_set; + + // add our new action set + new_action_set.instantiate(); + new_action_set->set_name(p_name); + new_action_set->set_localized_name(p_name); + action_map->add_action_set(new_action_set); + + // update our editor right away + return _add_action_set_editor(new_action_set); +} + +void OpenXRActionMapEditor::_remove_action_set(String p_name) { + ERR_FAIL_COND(action_map.is_null()); + Ref<OpenXRActionSet> action_set = action_map->find_action_set(p_name); + ERR_FAIL_COND(action_set.is_null()); + + if (action_set->get_action_count() > 0) { + // we should remove these and add to our redo/undo step before calling _remove_action_set + WARN_PRINT("Action set still has associated actions before being removed!"); + } + + // now we remove it + action_map->remove_action_set(action_set); +} + +void OpenXRActionMapEditor::_on_add_action_set() { + ERR_FAIL_COND(action_map.is_null()); + String new_name = "New"; + int count = 0; + + while (action_map->find_action_set(new_name).is_valid()) { + new_name = "New_" + itos(count++); + } + + OpenXRActionSetEditor *new_action_set_editor = _add_action_set(new_name); + + // Make sure our action set is the current tab + tabs->set_current_tab(0); + + call_deferred("_set_focus_on_action_set", new_action_set_editor); +} + +void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) { + // Scroll down to our new entry + actionsets_scroll->ensure_control_visible(p_action_set_editor); + + // Set focus on this entry + p_action_set_editor->set_focus_on_entry(); +} + +void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) { + ERR_FAIL_COND(action_map.is_null()); + + OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(p_action_set_editor); + ERR_FAIL_NULL(action_set_editor); + ERR_FAIL_COND(action_set_editor->get_parent() != actionsets_vb); + Ref<OpenXRActionSet> action_set = action_set_editor->get_action_set(); + ERR_FAIL_COND(action_set.is_null()); + + action_map->remove_action_set(action_set); + actionsets_vb->remove_child(action_set_editor); + action_set_editor->queue_delete(); +} + +void OpenXRActionMapEditor::_on_action_removed() { + // make sure our interaction profiles are updated + _update_interaction_profiles(); +} + +void OpenXRActionMapEditor::_on_add_interaction_profile() { + ERR_FAIL_COND(action_map.is_null()); + + PackedStringArray already_selected; + + for (int i = 0; i < action_map->get_interaction_profile_count(); i++) { + already_selected.push_back(action_map->get_interaction_profile(i)->get_interaction_profile_path()); + } + + select_interaction_profile_dialog->open(already_selected); +} + +void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path) { + ERR_FAIL_COND(action_map.is_null()); + + Ref<OpenXRInteractionProfile> new_profile; + new_profile.instantiate(); + new_profile->set_interaction_profile_path(p_path); + action_map->add_interaction_profile(new_profile); + + _add_interaction_profile_editor(new_profile); + + tabs->set_current_tab(tabs->get_tab_count() - 1); +} + +void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) { + action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE); + if (action_map.is_null()) { + if (p_create_new_if_missing) { + action_map.instantiate(); + action_map->create_default_action_sets(); + } else { + EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an OpenXR action map.")); + + edited_path = ""; + header_label->set_text(""); + return; + } + } + + edited_path = p_path; + header_label->set_text(TTR("OpenXR Action map:") + " " + p_path.get_file()); +} + +void OpenXRActionMapEditor::_on_save_action_map() { + Error err = ResourceSaver::save(edited_path, action_map); + if (err != OK) { + EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), edited_path)); + return; + } + + _update_action_sets(); + _update_interaction_profiles(); +} + +void OpenXRActionMapEditor::_on_reset_to_default_layout() { + // create a new one + action_map.unref(); + action_map.instantiate(); + action_map->create_default_action_sets(); + + _update_action_sets(); + _update_interaction_profiles(); +} + +void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) { +} + +void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) { + OpenXRInteractionProfileEditorBase *profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(p_tab)); + ERR_FAIL_NULL(profile_editor); + + Ref<OpenXRInteractionProfile> interaction_profile = profile_editor->get_interaction_profile(); + ERR_FAIL_COND(interaction_profile.is_null()); + + action_map->remove_interaction_profile(interaction_profile); + tabs->remove_child(profile_editor); + profile_editor->queue_delete(); +} + +void OpenXRActionMapEditor::open_action_map(String p_path) { + EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + + _load_action_map(p_path); + + _update_action_sets(); + _update_interaction_profiles(); +} + +OpenXRActionMapEditor::OpenXRActionMapEditor() { + set_custom_minimum_size(Size2(0.0, 300.0)); + + top_hb = memnew(HBoxContainer); + add_child(top_hb); + + header_label = memnew(Label); + header_label->set_text(String(TTR("Action Map"))); + header_label->set_clip_text(true); + header_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + top_hb->add_child(header_label); + + add_action_set = memnew(Button); + add_action_set->set_text(TTR("Add Action Set")); + add_action_set->set_tooltip(TTR("Add an action set.")); + add_action_set->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set)); + top_hb->add_child(add_action_set); + + add_interaction_profile = memnew(Button); + add_interaction_profile->set_text(TTR("Add profile")); + add_interaction_profile->set_tooltip(TTR("Add an interaction profile.")); + add_interaction_profile->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile)); + top_hb->add_child(add_interaction_profile); + + VSeparator *vseparator = memnew(VSeparator); + top_hb->add_child(vseparator); + + save_as = memnew(Button); + save_as->set_text(TTR("Save")); + save_as->set_tooltip(TTR("Save this OpenXR action map.")); + save_as->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map)); + top_hb->add_child(save_as); + + _default = memnew(Button); + _default->set_text(TTR("Reset to Default")); + _default->set_tooltip(TTR("Reset to default OpenXR action map.")); + _default->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout)); + top_hb->add_child(_default); + + tabs = memnew(TabContainer); + tabs->set_h_size_flags(SIZE_EXPAND_FILL); + tabs->set_v_size_flags(SIZE_EXPAND_FILL); + tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed)); + tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed)); + add_child(tabs); + + actionsets_scroll = memnew(ScrollContainer); + actionsets_scroll->set_h_size_flags(SIZE_EXPAND_FILL); + actionsets_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + actionsets_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + tabs->add_child(actionsets_scroll); + actionsets_scroll->set_name(TTR("Action Sets")); + + actionsets_vb = memnew(VBoxContainer); + actionsets_vb->set_h_size_flags(SIZE_EXPAND_FILL); + actionsets_scroll->add_child(actionsets_vb); + + select_interaction_profile_dialog = memnew(OpenXRSelectInteractionProfileDialog); + select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected)); + add_child(select_interaction_profile_dialog); + + _load_action_map(ProjectSettings::get_singleton()->get("xr/openxr/default_action_map")); +} + +OpenXRActionMapEditor::~OpenXRActionMapEditor() { +} diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h new file mode 100644 index 0000000000..dfc941b500 --- /dev/null +++ b/modules/openxr/editor/openxr_action_map_editor.h @@ -0,0 +1,100 @@ +/*************************************************************************/ +/* openxr_action_map_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_ACTION_MAP_EDITOR_H +#define OPENXR_ACTION_MAP_EDITOR_H + +#include "../action_map/openxr_action_map.h" +#include "../editor/openxr_action_set_editor.h" +#include "../editor/openxr_interaction_profile_editor.h" +#include "../editor/openxr_select_interaction_profile_dialog.h" + +#include "editor/editor_plugin.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/tab_container.h" + +class OpenXRActionMapEditor : public VBoxContainer { + GDCLASS(OpenXRActionMapEditor, VBoxContainer); + +private: + String edited_path; + Ref<OpenXRActionMap> action_map; + Vector<Node *> interaction_profiles; + + HBoxContainer *top_hb = nullptr; + Label *header_label = nullptr; + Button *add_action_set = nullptr; + Button *add_interaction_profile = nullptr; + Button *load = nullptr; + Button *save_as = nullptr; + Button *_default = nullptr; + TabContainer *tabs = nullptr; + ScrollContainer *actionsets_scroll = nullptr; + VBoxContainer *actionsets_vb = nullptr; + OpenXRSelectInteractionProfileDialog *select_interaction_profile_dialog = nullptr; + + OpenXRActionSetEditor *_add_action_set_editor(Ref<OpenXRActionSet> p_action_set); + void _update_action_sets(); + OpenXRInteractionProfileEditorBase *_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile); + void _update_interaction_profiles(); + + OpenXRActionSetEditor *_add_action_set(String p_name); + void _remove_action_set(String p_name); + + void _on_add_action_set(); + void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor); + void _on_remove_action_set(Object *p_action_set_editor); + void _on_action_removed(); + + void _on_add_interaction_profile(); + void _on_interaction_profile_selected(const String p_path); + + void _load_action_map(const String p_path, bool p_create_new_if_missing = false); + void _on_save_action_map(); + void _on_reset_to_default_layout(); + + void _on_tabs_tab_changed(int p_tab); + void _on_tab_button_pressed(int p_tab); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + void open_action_map(String p_path); + + OpenXRActionMapEditor(); + ~OpenXRActionMapEditor(); +}; + +#endif // !OPENXR_ACTION_MAP_EDITOR_H diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp new file mode 100644 index 0000000000..7bf8557c5b --- /dev/null +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -0,0 +1,218 @@ +/*************************************************************************/ +/* openxr_action_set_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_action_set_editor.h" +#include "openxr_action_editor.h" + +void OpenXRActionSetEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_set_editor"))); + ADD_SIGNAL(MethodInfo("action_removed")); +} + +void OpenXRActionSetEditor::_set_fold_icon() { + if (is_expanded) { + fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons"))); + } else { + fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons"))); + } +} + +void OpenXRActionSetEditor::_theme_changed() { + _set_fold_icon(); + add_action->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); +} + +void OpenXRActionSetEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + _theme_changed(); + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + } break; + } +} + +OpenXRActionEditor *OpenXRActionSetEditor::_add_action_editor(Ref<OpenXRAction> p_action) { + OpenXRActionEditor *action_editor = memnew(OpenXRActionEditor(p_action)); + action_editor->connect("remove", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action)); + actions_vb->add_child(action_editor); + + return action_editor; +} + +void OpenXRActionSetEditor::_update_actions() { + // out with the old... + while (actions_vb->get_child_count() > 0) { + memdelete(actions_vb->get_child(0)); + } + + // in with the new... + Array actions = action_set->get_actions(); + for (int i = 0; i < actions.size(); i++) { + Ref<OpenXRAction> action = actions[i]; + _add_action_editor(action); + } +} + +void OpenXRActionSetEditor::_on_toggle_expand() { + is_expanded = !is_expanded; + actions_vb->set_visible(is_expanded); + _set_fold_icon(); +} + +void OpenXRActionSetEditor::_on_action_set_name_changed(const String p_new_text) { + // TODO validate if entry is allowed + + // If our localized name matches our action set name, set this too + if (action_set->get_name() == action_set->get_localized_name()) { + action_set->set_localized_name(p_new_text); + action_set_localized_name->set_text(p_new_text); + } + action_set->set_name(p_new_text); +} + +void OpenXRActionSetEditor::_on_action_set_localized_name_changed(const String p_new_text) { + action_set->set_localized_name(p_new_text); +} + +void OpenXRActionSetEditor::_on_action_set_priority_changed(const String p_new_text) { + int64_t value = p_new_text.to_int(); + + action_set->set_priority(value); +} + +void OpenXRActionSetEditor::_on_add_action() { + Ref<OpenXRAction> new_action; + + new_action.instantiate(); + new_action->set_name("New"); + new_action->set_localized_name("New"); + action_set->add_action(new_action); + + _add_action_editor(new_action); + + // TODO handle focus +} + +void OpenXRActionSetEditor::_on_remove_action_set() { + emit_signal("remove", this); +} + +void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) { + OpenXRActionEditor *action_editor = Object::cast_to<OpenXRActionEditor>(p_action_editor); + ERR_FAIL_NULL(action_editor); + ERR_FAIL_COND(action_editor->get_parent() != actions_vb); + Ref<OpenXRAction> action = action_editor->get_action(); + ERR_FAIL_COND(action.is_null()); + + // TODO add undo/redo action + + // TODO find where this action is used by our interaction profiles and remove it there + + // And remove it.... + action_map->remove_action(action->get_name_with_set()); // remove it from the set and any interaction profile it relates to + actions_vb->remove_child(action_editor); + action_editor->queue_delete(); + + // Let action map editor know so we can update our interaction profiles + emit_signal("action_removed"); +} + +void OpenXRActionSetEditor::set_focus_on_entry() { + ERR_FAIL_NULL(action_set_name); + action_set_name->grab_focus(); +} + +OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) { + action_map = p_action_map; + action_set = p_action_set; + + set_h_size_flags(Control::SIZE_EXPAND_FILL); + + panel = memnew(PanelContainer); + panel->set_h_size_flags(Control::SIZE_EXPAND_FILL); + add_child(panel); + + HBoxContainer *panel_hb = memnew(HBoxContainer); + panel_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + panel->add_child(panel_hb); + + fold_btn = memnew(Button); + fold_btn->set_v_size_flags(Control::SIZE_SHRINK_BEGIN); + fold_btn->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand)); + fold_btn->set_flat(true); + panel_hb->add_child(fold_btn); + + main_vb = memnew(VBoxContainer); + main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + panel_hb->add_child(main_vb); + + action_set_hb = memnew(HBoxContainer); + action_set_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(action_set_hb); + + action_set_name = memnew(LineEdit); + action_set_name->set_text(action_set->get_name()); + action_set_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_set_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_name_changed)); + action_set_hb->add_child(action_set_name); + + action_set_localized_name = memnew(LineEdit); + action_set_localized_name->set_text(action_set->get_localized_name()); + action_set_localized_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_set_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); + action_set_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_localized_name_changed)); + action_set_hb->add_child(action_set_localized_name); + + action_set_priority = memnew(TextEdit); + action_set_priority->set_text(itos(action_set->get_priority())); + action_set_priority->set_custom_minimum_size(Size2(50.0, 0.0)); + action_set_priority->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_priority_changed)); + action_set_hb->add_child(action_set_priority); + + add_action = memnew(Button); + add_action->set_tooltip("Add Action."); + add_action->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_add_action)); + add_action->set_flat(true); + action_set_hb->add_child(add_action); + + rem_action_set = memnew(Button); + rem_action_set->set_tooltip("Remove Action Set."); + rem_action_set->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set)); + rem_action_set->set_flat(true); + action_set_hb->add_child(rem_action_set); + + actions_vb = memnew(VBoxContainer); + actions_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(actions_vb); + + _update_actions(); +} diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h new file mode 100644 index 0000000000..f3960dcbf9 --- /dev/null +++ b/modules/openxr/editor/openxr_action_set_editor.h @@ -0,0 +1,88 @@ +/*************************************************************************/ +/* openxr_action_set_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_ACTION_SET_EDITOR_H +#define OPENXR_ACTION_SET_EDITOR_H + +#include "../action_map/openxr_action_map.h" +#include "../action_map/openxr_action_set.h" +#include "openxr_action_editor.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/text_edit.h" + +class OpenXRActionSetEditor : public HBoxContainer { + GDCLASS(OpenXRActionSetEditor, HBoxContainer); + +private: + Ref<OpenXRActionMap> action_map; + Ref<OpenXRActionSet> action_set; + + bool is_expanded = true; + + PanelContainer *panel = nullptr; + Button *fold_btn = nullptr; + VBoxContainer *main_vb = nullptr; + HBoxContainer *action_set_hb = nullptr; + LineEdit *action_set_name = nullptr; + LineEdit *action_set_localized_name = nullptr; + TextEdit *action_set_priority = nullptr; + Button *add_action = nullptr; + Button *rem_action_set = nullptr; + VBoxContainer *actions_vb = nullptr; + + void _set_fold_icon(); + void _theme_changed(); + OpenXRActionEditor *_add_action_editor(Ref<OpenXRAction> p_action); + void _update_actions(); + + void _on_toggle_expand(); + void _on_action_set_name_changed(const String p_new_text); + void _on_action_set_localized_name_changed(const String p_new_text); + void _on_action_set_priority_changed(const String p_new_text); + void _on_add_action(); + void _on_remove_action_set(); + + void _on_remove_action(Object *p_action_editor); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + Ref<OpenXRActionSet> get_action_set() { return action_set; }; + void set_focus_on_entry(); + + OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set); +}; + +#endif // !OPENXR_ACTION_SET_EDITOR_H diff --git a/modules/bullet/constraint_bullet.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp index e610727685..b87b538511 100644 --- a/modules/bullet/constraint_bullet.cpp +++ b/modules/openxr/editor/openxr_editor_plugin.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* constraint_bullet.cpp */ +/* openxr_editor_plugin.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,35 +28,31 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "constraint_bullet.h" +#include "openxr_editor_plugin.h" -#include "collision_object_bullet.h" -#include "space_bullet.h" +#include "../action_map/openxr_action_map.h" +#include "editor/editor_node.h" -/** - @author AndreaCatania -*/ - -ConstraintBullet::ConstraintBullet() {} - -void ConstraintBullet::setup(btTypedConstraint *p_constraint) { - constraint = p_constraint; - constraint->setUserConstraintPtr(this); +void OpenXREditorPlugin::edit(Object *p_node) { + if (Object::cast_to<OpenXRActionMap>(p_node)) { + String path = Object::cast_to<OpenXRActionMap>(p_node)->get_path(); + if (path.is_resource_file()) { + action_map_editor->open_action_map(path); + } + } } -void ConstraintBullet::set_space(SpaceBullet *p_space) { - space = p_space; +bool OpenXREditorPlugin::handles(Object *p_node) const { + return (Object::cast_to<OpenXRActionMap>(p_node) != nullptr); } -void ConstraintBullet::destroy_internal_constraint() { - space->remove_constraint(this); +void OpenXREditorPlugin::make_visible(bool p_visible) { } -void ConstraintBullet::disable_collisions_between_bodies(const bool p_disabled) { - disabled_collisions_between_bodies = p_disabled; +OpenXREditorPlugin::OpenXREditorPlugin() { + action_map_editor = memnew(OpenXRActionMapEditor); + EditorNode::get_singleton()->add_bottom_panel_item(TTR("OpenXR Action Map"), action_map_editor); +} - if (space) { - space->remove_constraint(this); - space->add_constraint(this, disabled_collisions_between_bodies); - } +OpenXREditorPlugin::~OpenXREditorPlugin() { } diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/openxr/editor/openxr_editor_plugin.h index 7e51f7d644..af8ee7d54c 100644 --- a/modules/bullet/cone_twist_joint_bullet.h +++ b/modules/openxr/editor/openxr_editor_plugin.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* cone_twist_joint_bullet.h */ +/* openxr_editor_plugin.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,26 +28,26 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONE_TWIST_JOINT_BULLET_H -#define CONE_TWIST_JOINT_BULLET_H +#ifndef OPENXR_EDITOR_PLUGIN_H +#define OPENXR_EDITOR_PLUGIN_H -#include "joint_bullet.h" +#include "editor/editor_plugin.h" +#include "openxr_action_map_editor.h" -/** - @author AndreaCatania -*/ +class OpenXREditorPlugin : public EditorPlugin { + GDCLASS(OpenXREditorPlugin, EditorPlugin); -class RigidBodyBullet; - -class ConeTwistJointBullet : public JointBullet { - class btConeTwistConstraint *coneConstraint; + OpenXRActionMapEditor *action_map_editor = nullptr; public: - ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame); - - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; } - - void set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value); - real_t get_param(PhysicsServer3D::ConeTwistJointParam p_param) const; + virtual String get_name() const override { return "OpenXRPlugin"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_node) override; + virtual bool handles(Object *p_node) const override; + virtual void make_visible(bool p_visible) override; + + OpenXREditorPlugin(); + ~OpenXREditorPlugin(); }; -#endif + +#endif // !OPENXR_EDITOR_PLUGIN_H diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp new file mode 100644 index 0000000000..24ac5494dd --- /dev/null +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -0,0 +1,274 @@ +/*************************************************************************/ +/* openxr_interaction_profile_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_interaction_profile_editor.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/text_edit.h" + +/////////////////////////////////////////////////////////////////////////// +// Interaction profile editor base + +void OpenXRInteractionProfileEditorBase::_bind_methods() { + ClassDB::bind_method(D_METHOD("_add_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_add_binding); + ClassDB::bind_method(D_METHOD("_remove_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_remove_binding); + ClassDB::bind_method(D_METHOD("_update_interaction_profile"), &OpenXRInteractionProfileEditorBase::_update_interaction_profile); +} + +void OpenXRInteractionProfileEditorBase::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _update_interaction_profile(); + } break; + + case NOTIFICATION_THEME_CHANGED: { + _theme_changed(); + } break; + } +} + +void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, const String p_path) { + ERR_FAIL_COND(action_map.is_null()); + ERR_FAIL_COND(interaction_profile.is_null()); + + Ref<OpenXRAction> action = action_map->get_action(p_action); + ERR_FAIL_COND(action.is_null()); + + Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action); + if (binding.is_null()) { + // create a new binding + binding.instantiate(); + binding->set_action(action); + interaction_profile->add_binding(binding); + } + + binding->add_path(p_path); + + // Update our toplevel paths + action->set_toplevel_paths(action_map->get_top_level_paths(action)); + + call_deferred("_update_interaction_profile"); +} + +void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, const String p_path) { + ERR_FAIL_COND(action_map.is_null()); + ERR_FAIL_COND(interaction_profile.is_null()); + + Ref<OpenXRAction> action = action_map->get_action(p_action); + ERR_FAIL_COND(action.is_null()); + + Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action); + if (binding.is_valid()) { + binding->remove_path(p_path); + + if (binding->get_path_count() == 0) { + interaction_profile->remove_binding(binding); + } + + // Update our toplevel paths + action->set_toplevel_paths(action_map->get_top_level_paths(action)); + + call_deferred("_update_interaction_profile"); + } +} + +OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) { + action_map = p_action_map; + interaction_profile = p_interaction_profile; + String profile_path = interaction_profile->get_interaction_profile_path(); + String profile_name = profile_path; + + profile_def = OpenXRDefs::get_profile(profile_path); + if (profile_def != nullptr) { + profile_name = profile_def->display_name; + } + + set_name(profile_name); + set_h_size_flags(SIZE_EXPAND_FILL); + set_v_size_flags(SIZE_EXPAND_FILL); +} + +/////////////////////////////////////////////////////////////////////////// +// Default interaction profile editor + +void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) { + selecting_for_io_path = p_io_path; + select_action_dialog->open(); +} + +void OpenXRInteractionProfileEditor::action_selected(const String p_action) { + _add_binding(p_action, selecting_for_io_path); + selecting_for_io_path = ""; +} + +void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path) { + HBoxContainer *path_hb = memnew(HBoxContainer); + path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + p_container->add_child(path_hb); + + Label *path_label = memnew(Label); + path_label->set_text(p_io_path->display_name); + path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + path_hb->add_child(path_label); + + Label *type_label = memnew(Label); + switch (p_io_path->action_type) { + case OpenXRAction::OPENXR_ACTION_BOOL: { + type_label->set_text(TTR("Boolean")); + } break; + case OpenXRAction::OPENXR_ACTION_FLOAT: { + type_label->set_text(TTR("Float")); + } break; + case OpenXRAction::OPENXR_ACTION_VECTOR2: { + type_label->set_text(TTR("Vector2")); + } break; + case OpenXRAction::OPENXR_ACTION_POSE: { + type_label->set_text(TTR("Pose")); + } break; + case OpenXRAction::OPENXR_ACTION_HAPTIC: { + type_label->set_text(TTR("Haptic")); + } break; + default: { + type_label->set_text(TTR("Unknown")); + } break; + } + type_label->set_custom_minimum_size(Size2(50.0, 0.0)); + path_hb->add_child(type_label); + + Button *path_add = memnew(Button); + path_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + path_add->set_flat(true); + Vector<Variant> add_binds; + add_binds.push_back(String(p_io_path->openxr_path)); + path_add->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for), add_binds); + path_hb->add_child(path_add); + + if (interaction_profile.is_valid()) { + String io_path = String(p_io_path->openxr_path); + Array bindings = interaction_profile->get_bindings(); + for (int i = 0; i < bindings.size(); i++) { + Ref<OpenXRIPBinding> binding = bindings[i]; + if (binding->has_path(io_path)) { + Ref<OpenXRAction> action = binding->get_action(); + + HBoxContainer *action_hb = memnew(HBoxContainer); + action_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + p_container->add_child(action_hb); + + Control *indent_node = memnew(Control); + indent_node->set_custom_minimum_size(Size2(10.0, 0.0)); + action_hb->add_child(indent_node); + + Label *action_label = memnew(Label); + action_label->set_text(action->get_name_with_set() + ": " + action->get_localized_name()); + action_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + action_hb->add_child(action_label); + + Button *action_rem = memnew(Button); + action_rem->set_flat(true); + action_rem->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); + Vector<Variant> remove_binds; + remove_binds.push_back(action->get_name_with_set()); + remove_binds.push_back(String(p_io_path->openxr_path)); + action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditorBase *)this, &OpenXRInteractionProfileEditorBase::_remove_binding), remove_binds); + action_hb->add_child(action_rem); + } + } + } +} + +void OpenXRInteractionProfileEditor::_update_interaction_profile() { + ERR_FAIL_NULL(profile_def); + + // out with the old... + while (main_hb->get_child_count() > 0) { + memdelete(main_hb->get_child(0)); + } + + // in with the new... + + // Determine toplevel paths + Vector<const OpenXRDefs::TopLevelPath *> top_level_paths; + for (int i = 0; i < profile_def->io_path_count; i++) { + const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[i]; + + if (!top_level_paths.has(io_path->top_level_path)) { + top_level_paths.push_back(io_path->top_level_path); + } + } + + for (int i = 0; i < top_level_paths.size(); i++) { + PanelContainer *panel = memnew(PanelContainer); + panel->set_v_size_flags(Control::SIZE_EXPAND_FILL); + main_hb->add_child(panel); + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + + VBoxContainer *container = memnew(VBoxContainer); + panel->add_child(container); + + Label *label = memnew(Label); + label->set_text(top_level_paths[i]->display_name); + container->add_child(label); + + for (int j = 0; j < profile_def->io_path_count; j++) { + const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[j]; + if (io_path->top_level_path == top_level_paths[i]) { + _add_io_path(container, io_path); + } + } + } +} + +void OpenXRInteractionProfileEditor::_theme_changed() { + for (int i = 0; i < main_hb->get_child_count(); i++) { + Control *panel = static_cast<Control *>(main_hb->get_child(i)); + if (panel) { + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + } + } +} + +OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) : + OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) { + // TODO background of scrollbox should be darker with our VBoxContainers we're adding in _update_interaction_profile the normal color + + main_hb = memnew(HBoxContainer); + add_child(main_hb); + + select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map)); + select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected)); + add_child(select_action_dialog); + + _update_interaction_profile(); +} diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h new file mode 100644 index 0000000000..f50da1a003 --- /dev/null +++ b/modules/openxr/editor/openxr_interaction_profile_editor.h @@ -0,0 +1,83 @@ +/*************************************************************************/ +/* openxr_interaction_profile_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_INTERACTION_PROFILE_EDITOR_H +#define OPENXR_INTERACTION_PROFILE_EDITOR_H + +#include "../action_map/openxr_action_map.h" +#include "../action_map/openxr_defs.h" +#include "../action_map/openxr_interaction_profile.h" +#include "scene/gui/scroll_container.h" + +#include "openxr_select_action_dialog.h" + +class OpenXRInteractionProfileEditorBase : public ScrollContainer { + GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer); + +protected: + Ref<OpenXRInteractionProfile> interaction_profile; + Ref<OpenXRActionMap> action_map; + + static void _bind_methods(); + void _notification(int p_what); + + const OpenXRDefs::InteractionProfile *profile_def = nullptr; + +public: + Ref<OpenXRInteractionProfile> get_interaction_profile() { return interaction_profile; } + + virtual void _update_interaction_profile() {} + virtual void _theme_changed() {} + void _add_binding(const String p_action, const String p_path); + void _remove_binding(const String p_action, const String p_path); + + OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile); +}; + +class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase { + GDCLASS(OpenXRInteractionProfileEditor, OpenXRInteractionProfileEditorBase); + +private: + String selecting_for_io_path; + HBoxContainer *main_hb = nullptr; + OpenXRSelectActionDialog *select_action_dialog = nullptr; + + void _add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path); + +public: + void select_action_for(const String p_io_path); + void action_selected(const String p_action); + + virtual void _update_interaction_profile() override; + virtual void _theme_changed() override; + OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile); +}; + +#endif // !OPENXR_INTERACTION_PROFILE_EDITOR_H diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp new file mode 100644 index 0000000000..c2a2965200 --- /dev/null +++ b/modules/openxr/editor/openxr_select_action_dialog.cpp @@ -0,0 +1,135 @@ +/*************************************************************************/ +/* openxr_select_action_dialog.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_select_action_dialog.h" +#include "editor/editor_node.h" + +void OpenXRSelectActionDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("action_selected", PropertyInfo(Variant::STRING, "action"))); +} + +void OpenXRSelectActionDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + } break; + } +} + +void OpenXRSelectActionDialog::_on_select_action(const String p_action) { + if (selected_action != "") { + NodePath button_path = action_buttons[selected_action]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(true); + } + } + + selected_action = p_action; + + if (selected_action != "") { + NodePath button_path = action_buttons[selected_action]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(false); + } + } +} + +void OpenXRSelectActionDialog::open() { + ERR_FAIL_COND(action_map.is_null()); + + // out with the old... + while (main_vb->get_child_count() > 0) { + memdelete(main_vb->get_child(0)); + } + + selected_action = ""; + action_buttons.clear(); + + Array action_sets = action_map->get_action_sets(); + for (int i = 0; i < action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = action_sets[i]; + + Label *action_set_label = memnew(Label); + action_set_label->set_text(action_set->get_localized_name()); + main_vb->add_child(action_set_label); + + Array actions = action_set->get_actions(); + for (int j = 0; j < actions.size(); j++) { + Ref<OpenXRAction> action = actions[j]; + + HBoxContainer *action_hb = memnew(HBoxContainer); + main_vb->add_child(action_hb); + + Control *indent_node = memnew(Control); + indent_node->set_custom_minimum_size(Size2(10.0, 0.0)); + action_hb->add_child(indent_node); + + Button *action_button = memnew(Button); + String action_name = action->get_name_with_set(); + Vector<Variant> binds; + binds.push_back(action_name); + action_button->set_flat(true); + action_button->set_text(action->get_name() + ": " + action->get_localized_name()); + action_button->connect("pressed", callable_mp(this, &OpenXRSelectActionDialog::_on_select_action), binds); + action_hb->add_child(action_button); + + action_buttons[action_name] = action_button->get_path(); + } + } + + popup_centered(); +} + +void OpenXRSelectActionDialog::ok_pressed() { + if (selected_action == "") { + return; + } + + emit_signal("action_selected", selected_action); + + hide(); +} + +OpenXRSelectActionDialog::OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map) { + action_map = p_action_map; + + set_title(TTR("Select an action")); + + scroll = memnew(ScrollContainer); + scroll->set_custom_minimum_size(Size2(600.0, 400.0)); + add_child(scroll); + + main_vb = memnew(VBoxContainer); + main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + scroll->add_child(main_vb); +} diff --git a/modules/gdnative/gdnative_library_singleton_editor.h b/modules/openxr/editor/openxr_select_action_dialog.h index 5bb823d920..ea2c30373b 100644 --- a/modules/gdnative/gdnative_library_singleton_editor.h +++ b/modules/openxr/editor/openxr_select_action_dialog.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* gdnative_library_singleton_editor.h */ +/* openxr_select_action_dialog.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,35 +28,40 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GD_NATIVE_LIBRARY_EDITOR_H -#define GD_NATIVE_LIBRARY_EDITOR_H +#ifndef OPENXR_SELECT_ACTION_DIALOG_H +#define OPENXR_SELECT_ACTION_DIALOG_H -#ifdef TOOLS_ENABLED -#include "editor/editor_file_system.h" -#include "editor/project_settings_editor.h" +#include "../action_map/openxr_action_map.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/label.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/text_edit.h" -class GDNativeLibrarySingletonEditor : public VBoxContainer { - GDCLASS(GDNativeLibrarySingletonEditor, VBoxContainer); +class OpenXRSelectActionDialog : public ConfirmationDialog { + GDCLASS(OpenXRSelectActionDialog, ConfirmationDialog); private: - Tree *libraries; - UndoRedo *undo_redo; + Ref<OpenXRActionMap> action_map; + String selected_action; + Dictionary action_buttons; - bool updating; - - static Set<String> _find_singletons_recursive(EditorFileSystemDirectory *p_dir); + VBoxContainer *main_vb = nullptr; + ScrollContainer *scroll = nullptr; protected: - void _notification(int p_what); static void _bind_methods(); - - void _discover_singletons(); - void _item_edited(); - void _update_libraries(); + void _notification(int p_what); public: - GDNativeLibrarySingletonEditor(); + void _on_select_action(const String p_action); + void open(); + virtual void ok_pressed() override; + + OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map); }; -#endif -#endif // GD_NATIVE_LIBRARY_EDITOR_H +#endif // !OPENXR_SELECT_ACTION_DIALOG_H diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp new file mode 100644 index 0000000000..12b110f146 --- /dev/null +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -0,0 +1,125 @@ +/*************************************************************************/ +/* openxr_select_interaction_profile_dialog.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_select_interaction_profile_dialog.h" + +void OpenXRSelectInteractionProfileDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("interaction_profile_selected", PropertyInfo(Variant::STRING, "interaction_profile"))); +} + +void OpenXRSelectInteractionProfileDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + } break; + } +} + +void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const String p_interaction_profile) { + if (selected_interaction_profile != "") { + NodePath button_path = ip_buttons[selected_interaction_profile]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(true); + } + } + + selected_interaction_profile = p_interaction_profile; + + if (selected_interaction_profile != "") { + NodePath button_path = ip_buttons[selected_interaction_profile]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(false); + } + } +} + +void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) { + int available_count = 0; + + // out with the old... + while (main_vb->get_child_count() > 0) { + memdelete(main_vb->get_child(0)); + } + + selected_interaction_profile = ""; + ip_buttons.clear(); + + // in with the new + PackedStringArray interaction_profiles = OpenXRDefs::get_interaction_profile_paths(); + for (int i = 0; i < interaction_profiles.size(); i++) { + String path = interaction_profiles[i]; + if (!p_do_not_include.has(path)) { + Button *ip_button = memnew(Button); + Vector<Variant> binds; + binds.push_back(path); + ip_button->set_flat(true); + ip_button->set_text(OpenXRDefs::get_profile(path)->display_name); + ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile), binds); + main_vb->add_child(ip_button); + + ip_buttons[path] = ip_button->get_path(); + available_count++; + } + } + + if (available_count == 0) { + // give warning that we have all profiles selected + + } else { + // TODO maybe if we only have one, auto select it? + + popup_centered(); + } +} + +void OpenXRSelectInteractionProfileDialog::ok_pressed() { + if (selected_interaction_profile == "") { + return; + } + + emit_signal("interaction_profile_selected", selected_interaction_profile); + + hide(); +} + +OpenXRSelectInteractionProfileDialog::OpenXRSelectInteractionProfileDialog() { + set_title("Select an interaction profile"); + + scroll = memnew(ScrollContainer); + scroll->set_custom_minimum_size(Size2(600.0, 400.0)); + add_child(scroll); + + main_vb = memnew(VBoxContainer); + // main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + scroll->add_child(main_vb); +} diff --git a/modules/bullet/constraint_bullet.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h index 6afd8c9b52..d177861ff3 100644 --- a/modules/bullet/constraint_bullet.h +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* constraint_bullet.h */ +/* openxr_select_interaction_profile_dialog.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,44 +28,39 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONSTRAINT_BULLET_H -#define CONSTRAINT_BULLET_H +#ifndef OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H +#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H -#include "bullet_utilities.h" -#include "rid_bullet.h" +#include "../action_map/openxr_defs.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/label.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/text_edit.h" -#include <BulletDynamics/ConstraintSolver/btTypedConstraint.h> +class OpenXRSelectInteractionProfileDialog : public ConfirmationDialog { + GDCLASS(OpenXRSelectInteractionProfileDialog, ConfirmationDialog); -/** - @author AndreaCatania -*/ +private: + String selected_interaction_profile; + Dictionary ip_buttons; -class RigidBodyBullet; -class SpaceBullet; -class btTypedConstraint; + VBoxContainer *main_vb = nullptr; + ScrollContainer *scroll = nullptr; -class ConstraintBullet : public RIDBullet { protected: - SpaceBullet *space = nullptr; - btTypedConstraint *constraint = nullptr; - bool disabled_collisions_between_bodies = true; + static void _bind_methods(); + void _notification(int p_what); public: - ConstraintBullet(); + void _on_select_interaction_profile(const String p_interaction_profile); + void open(PackedStringArray p_do_not_include); + virtual void ok_pressed() override; - virtual void setup(btTypedConstraint *p_constraint); - virtual void set_space(SpaceBullet *p_space); - virtual void destroy_internal_constraint(); - - void disable_collisions_between_bodies(const bool p_disabled); - _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } - -public: - virtual ~ConstraintBullet() { - bulletdelete(constraint); - constraint = nullptr; - } - - _FORCE_INLINE_ btTypedConstraint *get_bt_constraint() { return constraint; } + OpenXRSelectInteractionProfileDialog(); }; -#endif + +#endif // !OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H diff --git a/modules/gdnative/gdnative/string_name.cpp b/modules/openxr/extensions/openxr_android_extension.cpp index bd8f69674e..3bd4db169c 100644 --- a/modules/gdnative/gdnative/string_name.cpp +++ b/modules/openxr/extensions/openxr_android_extension.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* string_name.cpp */ +/* openxr_android_extension.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,35 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gdnative/string_name.h" +#include "openxr_android_extension.h" -#include "core/string/string_name.h" +#include <openxr/openxr.h> +#include <openxr/openxr_platform.h> -static_assert(sizeof(godot_string_name) == sizeof(StringName), "StringName size mismatch"); +OpenXRAndroidExtension *OpenXRAndroidExtension::singleton = nullptr; -#ifdef __cplusplus -extern "C" { -#endif - -void GDAPI godot_string_name_new(godot_string_name *r_dest) { - StringName *dest = (StringName *)r_dest; - memnew_placement(dest, StringName); +OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() { + return singleton; } -void GDAPI godot_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src) { - memnew_placement(r_dest, StringName(*(StringName *)p_src)); -} +OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + singleton = this; -void GDAPI godot_string_name_new_with_latin1_chars(godot_string_name *r_dest, const char *p_contents) { - StringName *dest = (StringName *)r_dest; - memnew_placement(dest, StringName(p_contents)); -} + request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available + + // Initialize the loader + PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR; + result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction *)(&xrInitializeLoaderKHR)); + ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to retrieve pointer to xrInitializeLoaderKHR"); + + // TODO fix this code, this is still code from GDNative! + JNIEnv *env = android_api->godot_android_get_env(); + JavaVM *vm; + env->GetJavaVM(&vm); + jobject activity_object = env->NewGlobalRef(android_api->godot_android_get_activity()); -void GDAPI godot_string_name_destroy(godot_string_name *p_self) { - StringName *self = (StringName *)p_self; - self->~StringName(); + XrLoaderInitInfoAndroidKHR loader_init_info_android = { + .type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, + .next = nullptr, + .applicationVM = vm, + .applicationContext = activity_object + }; + xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android); + ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR"); } -#ifdef __cplusplus +OpenXRAndroidExtension::~OpenXRAndroidExtension() { + singleton = nullptr; } -#endif diff --git a/modules/bullet/joint_bullet.h b/modules/openxr/extensions/openxr_android_extension.h index 5bb8b50961..e102197a55 100644 --- a/modules/bullet/joint_bullet.h +++ b/modules/openxr/extensions/openxr_android_extension.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* joint_bullet.h */ +/* openxr_android_extension.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,24 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JOINT_BULLET_H -#define JOINT_BULLET_H +#ifndef OPENXR_ANDROID_EXTENSION_H +#define OPENXR_ANDROID_EXTENSION_H -#include "constraint_bullet.h" -#include "servers/physics_server_3d.h" +#include "openxr_extension_wrapper.h" -/** - @author AndreaCatania -*/ - -class RigidBodyBullet; -class btTypedConstraint; - -class JointBullet : public ConstraintBullet { +class OpenXRAndroidExtension : public OpenXRExtensionWrapper { public: - JointBullet(); - virtual ~JointBullet(); + static OpenXRAndroidExtension *get_singleton(); - virtual PhysicsServer3D::JointType get_type() const = 0; + OpenXRAndroidExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRAndroidExtension() override; + +private: + static OpenXRAndroidExtension *singleton; }; -#endif + +#endif // !OPENXR_ANDROID_EXTENSION_H diff --git a/modules/bullet/rid_bullet.h b/modules/openxr/extensions/openxr_composition_layer_provider.h index face6b4861..019dffa2a8 100644 --- a/modules/bullet/rid_bullet.h +++ b/modules/openxr/extensions/openxr_composition_layer_provider.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rid_bullet.h */ +/* openxr_composition_layer_provider.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,26 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RID_BULLET_H -#define RID_BULLET_H +#ifndef OPENXR_COMPOSITION_LAYER_PROVIDER_H +#define OPENXR_COMPOSITION_LAYER_PROVIDER_H -#include "core/templates/rid.h" - -/** - @author AndreaCatania -*/ - -class BulletPhysicsServer3D; - -class RIDBullet { - RID self; - BulletPhysicsServer3D *physicsServer = nullptr; +#include <openxr/openxr.h> +// Interface for OpenXR extensions that provide a composition layer. +class OpenXRCompositionLayerProvider { public: - _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } - _FORCE_INLINE_ RID get_self() const { return self; } - - _FORCE_INLINE_ void _set_physics_server(BulletPhysicsServer3D *p_physicsServer) { physicsServer = p_physicsServer; } - _FORCE_INLINE_ BulletPhysicsServer3D *get_physics_server() const { return physicsServer; } + // TODO changed to normal method definition for now + // CI complains until we implement this, haven't ported it yet from plugin + // virtual XrCompositionLayerBaseHeader *get_composition_layer() = 0; + XrCompositionLayerBaseHeader *get_composition_layer() { return nullptr; }; }; -#endif + +#endif // OPENXR_COMPOSITION_LAYER_PROVIDER_H diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h new file mode 100644 index 0000000000..f3064041b8 --- /dev/null +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -0,0 +1,107 @@ +/*************************************************************************/ +/* openxr_extension_wrapper.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_EXTENSION_WRAPPER_H +#define OPENXR_EXTENSION_WRAPPER_H + +#include "core/error/error_macros.h" +#include "core/math/camera_matrix.h" +#include "core/templates/map.h" +#include "core/templates/rid.h" + +#include "thirdparty/openxr/src/common/xr_linear.h" +#include <openxr/openxr.h> + +class OpenXRAPI; +class OpenXRActionMap; + +class OpenXRExtensionWrapper { +protected: + OpenXRAPI *openxr_api = nullptr; + + // Store extension we require. + // If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available + // If bool pointer is set, value will be set to true or false depending on whether extension is available + Map<const char *, bool *> request_extensions; + +public: + virtual Map<const char *, bool *> get_request_extensions() { + return request_extensions; + } + + // These functions allow an extension to add entries to a struct chain. + // `p_next_pointer` points to the last struct that was created for this chain + // and should be used as the value for the `pNext` pointer in the first struct you add. + // You should return the pointer to the last struct you define as your result. + // If you are not adding any structs, just return `p_next_pointer`. + // See existing extensions for examples of this implementation. + virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + + virtual void on_instance_created(const XrInstance p_instance) {} + virtual void on_instance_destroyed() {} + virtual void on_session_created(const XrSession p_instance) {} + virtual void on_process() {} + virtual void on_pre_render() {} + virtual void on_session_destroyed() {} + + virtual void on_state_idle() {} + virtual void on_state_ready() {} + virtual void on_state_synchronized() {} + virtual void on_state_visible() {} + virtual void on_state_focused() {} + virtual void on_state_stopping() {} + virtual void on_state_loss_pending() {} + virtual void on_state_exiting() {} + + // Returns true if the event was handled, false otherwise. + virtual bool on_event_polled(const XrEventDataBuffer &event) { + return false; + } + + OpenXRExtensionWrapper(OpenXRAPI *p_openxr_api) { openxr_api = p_openxr_api; }; + virtual ~OpenXRExtensionWrapper() = default; +}; + +class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper { +public: + virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0; + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0; + virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0; + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) = 0; + virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) = 0; + + OpenXRGraphicsExtensionWrapper(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api){}; +}; + +#endif // ~OPENXR_EXTENSION_WRAPPER_H diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp new file mode 100644 index 0000000000..1eb7635a82 --- /dev/null +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -0,0 +1,751 @@ +/*************************************************************************/ +/* openxr_vulkan_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "core/string/print_string.h" + +#include "../extensions/openxr_vulkan_extension.h" +#include "../openxr_api.h" +#include "../openxr_util.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" +#include "servers/rendering/rendering_server_globals.h" +#include "servers/rendering_server.h" + +// need to include Vulkan so we know of type definitions +#define XR_USE_GRAPHICS_API_VULKAN + +#ifdef WINDOWS_ENABLED +// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform +// however due to the way the openxr headers are put together, we have no choice. +#include <windows.h> +#endif + +// include platform dependent structs +#include <openxr/openxr_platform.h> + +PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR_ptr = nullptr; +PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR_ptr = nullptr; +PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR_ptr = nullptr; +PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR_ptr = nullptr; + +OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) : + OpenXRGraphicsExtensionWrapper(p_openxr_api) { + VulkanContext::set_vulkan_hooks(this); + + request_extensions[XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME] = nullptr; // must be available + + ERR_FAIL_NULL(openxr_api); +} + +OpenXRVulkanExtension::~OpenXRVulkanExtension() { + VulkanContext::set_vulkan_hooks(nullptr); +} + +void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) { + XrResult result; + + ERR_FAIL_NULL(openxr_api); + + // Obtain pointers to functions we're accessing here, they are (not yet) part of core. + result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrGetVulkanGraphicsRequirements2KHR entry point [", openxr_api->get_error_string(result), "]"); + } + + result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrCreateVulkanInstanceKHR entry point [", openxr_api->get_error_string(result), "]"); + } + + result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrGetVulkanGraphicsDevice2KHR entry point [", openxr_api->get_error_string(result), "]"); + } + + result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR_ptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to xrCreateVulkanDeviceKHR entry point [", openxr_api->get_error_string(result), "]"); + } +} + +XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements) { + ERR_FAIL_NULL_V(xrGetVulkanGraphicsRequirements2KHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrGetVulkanGraphicsRequirements2KHR_ptr)(p_instance, p_system_id, p_graphics_requirements); +} + +bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) { + ERR_FAIL_NULL_V(openxr_api, false); + + XrGraphicsRequirementsVulkan2KHR vulkan_requirements = { + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR, // type + nullptr, // next + 0, // minApiVersionSupported + 0 // maxApiVersionSupported + }; + + XrResult result = xrGetVulkanGraphicsRequirements2KHR(openxr_api->get_instance(), openxr_api->get_system_id(), &vulkan_requirements); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get vulkan graphics requirements [", openxr_api->get_error_string(result), "]"); + return false; + } + + // #ifdef DEBUG + print_line("OpenXR: XrGraphicsRequirementsVulkan2KHR:"); + print_line(" - minApiVersionSupported: ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported)); + print_line(" - maxApiVersionSupported: ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported)); + // #endif + + if (p_desired_version < vulkan_requirements.minApiVersionSupported) { + print_line("OpenXR: Requested Vulkan version does not meet the minimum version this runtime supports."); + print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version)); + print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported)); + print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported)); + return false; + } + + if (p_desired_version > vulkan_requirements.maxApiVersionSupported) { + print_line("OpenXR: Requested Vulkan version exceeds the maximum version this runtime has been tested on and is known to support."); + print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version)); + print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported)); + print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported)); + } + + return true; +} + +XrResult OpenXRVulkanExtension::xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result) { + ERR_FAIL_NULL_V(xrCreateVulkanInstanceKHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrCreateVulkanInstanceKHR_ptr)(p_instance, p_create_info, r_vulkan_instance, r_vulkan_result); +} + +bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { + // get the vulkan version we are creating + uint32_t vulkan_version = p_vulkan_create_info->pApplicationInfo->apiVersion; + uint32_t major_version = VK_VERSION_MAJOR(vulkan_version); + uint32_t minor_version = VK_VERSION_MINOR(vulkan_version); + uint32_t patch_version = VK_VERSION_PATCH(vulkan_version); + XrVersion desired_version = XR_MAKE_VERSION(major_version, minor_version, patch_version); + + // check if this is supported + if (!check_graphics_api_support(desired_version)) { + return false; + } + + XrVulkanInstanceCreateInfoKHR xr_vulkan_instance_info = { + XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, // type + nullptr, // next + openxr_api->get_system_id(), // systemId + 0, // createFlags + vkGetInstanceProcAddr, // pfnGetInstanceProcAddr + p_vulkan_create_info, // vulkanCreateInfo + nullptr, // vulkanAllocator + }; + + VkResult vk_result = VK_SUCCESS; + XrResult result = xrCreateVulkanInstanceKHR(openxr_api->get_instance(), &xr_vulkan_instance_info, &vulkan_instance, &vk_result); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create vulkan instance [", openxr_api->get_error_string(result), "]"); + return false; + } + + ERR_FAIL_COND_V_MSG(vk_result == VK_ERROR_INCOMPATIBLE_DRIVER, false, + "Cannot find a compatible Vulkan installable client driver (ICD).\n\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(vk_result == VK_ERROR_EXTENSION_NOT_PRESENT, false, + "Cannot find a specified extension library.\n" + "Make sure your layers path is set appropriately.\n" + "vkCreateInstance Failure"); + ERR_FAIL_COND_V_MSG(vk_result, false, + "vkCreateInstance failed.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "Please look at the Getting Started guide for additional information.\n" + "vkCreateInstance Failure"); + + *r_instance = vulkan_instance; + + return true; +} + +XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device) { + ERR_FAIL_NULL_V(xrGetVulkanGraphicsDevice2KHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrGetVulkanGraphicsDevice2KHR_ptr)(p_instance, p_get_info, r_vulkan_physical_device); +} + +bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) { + ERR_FAIL_NULL_V(openxr_api, false); + + XrVulkanGraphicsDeviceGetInfoKHR get_info = { + XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, // type + nullptr, // next + openxr_api->get_system_id(), // systemId + vulkan_instance, // vulkanInstance + }; + + XrResult result = xrGetVulkanGraphicsDevice2KHR(openxr_api->get_instance(), &get_info, &vulkan_physical_device); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to obtain vulkan physical device [", openxr_api->get_error_string(result), "]"); + return false; + } + + *r_device = vulkan_physical_device; + + return true; +} + +XrResult OpenXRVulkanExtension::xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result) { + ERR_FAIL_NULL_V(xrCreateVulkanDeviceKHR_ptr, XR_ERROR_HANDLE_INVALID); + + return (*xrCreateVulkanDeviceKHR_ptr)(p_instance, p_create_info, r_device, r_result); +} + +bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { + ERR_FAIL_NULL_V(openxr_api, false); + + // the first entry in our queue list should be the one we need to remember... + vulkan_queue_family_index = p_device_create_info->pQueueCreateInfos[0].queueFamilyIndex; + vulkan_queue_index = 0; // ?? + + XrVulkanDeviceCreateInfoKHR create_info = { + XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, // type + nullptr, // next + openxr_api->get_system_id(), // systemId + 0, // createFlags + vkGetInstanceProcAddr, // pfnGetInstanceProcAddr + vulkan_physical_device, // vulkanPhysicalDevice + p_device_create_info, // vulkanCreateInfo + nullptr // vulkanAllocator + }; + + VkResult vk_result = VK_SUCCESS; + XrResult result = xrCreateVulkanDeviceKHR(openxr_api->get_instance(), &create_info, &vulkan_device, &vk_result); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create vulkan device [", openxr_api->get_error_string(result), "]"); + return false; + } + + if (vk_result != VK_SUCCESS) { + print_line("OpenXR: Failed to create vulkan device [vulkan error", vk_result, "]"); + } + + *r_device = vulkan_device; + + return true; +} + +XrGraphicsBindingVulkanKHR OpenXRVulkanExtension::graphics_binding_vulkan; + +void *OpenXRVulkanExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) { + graphics_binding_vulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR; + graphics_binding_vulkan.next = p_next_pointer; + graphics_binding_vulkan.instance = vulkan_instance; + graphics_binding_vulkan.physicalDevice = vulkan_physical_device; + graphics_binding_vulkan.device = vulkan_device; + graphics_binding_vulkan.queueFamilyIndex = vulkan_queue_family_index; + graphics_binding_vulkan.queueIndex = vulkan_queue_index; + + return &graphics_binding_vulkan; +} + +void OpenXRVulkanExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) { + // We might want to do more here especially if we keep things in linear color space + // Possibly add in R10G10B10A2 as an option if we're using the mobile renderer. + p_usable_swap_chains.push_back(VK_FORMAT_R8G8B8A8_SRGB); + p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_SRGB); + p_usable_swap_chains.push_back(VK_FORMAT_R8G8B8A8_UINT); + p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_UINT); +} + +bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) { + XrSwapchainImageVulkanKHR *images = nullptr; + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL_V(rendering_server, false); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL_V(rendering_device, false); + + uint32_t swapchain_length; + XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]"); + return false; + } + + images = (XrSwapchainImageVulkanKHR *)memalloc(sizeof(XrSwapchainImageVulkanKHR) * swapchain_length); + ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image"); + + for (uint64_t i = 0; i < swapchain_length; i++) { + images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; + images[i].next = nullptr; + images[i].image = VK_NULL_HANDLE; + } + + result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]"); + memfree(images); + return false; + } + + // SwapchainGraphicsData *data = (SwapchainGraphicsData *)memalloc(sizeof(SwapchainGraphicsData)); + SwapchainGraphicsData *data = memnew(SwapchainGraphicsData); + if (data == nullptr) { + print_line("OpenXR: Failed to allocate memory for swapchain data"); + memfree(images); + return false; + } + *r_swapchain_graphics_data = data; + data->is_multiview = (p_array_size > 1); + + RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; + RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1; + uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + switch (p_swapchain_format) { + case VK_FORMAT_R8G8B8A8_SRGB: + // Even though this is an sRGB framebuffer format we're using UNORM here. + // The reason here is because Godot does a linear to sRGB conversion while + // with the sRGB format, this conversion would be doubled by the hardware. + // This also means we're reading the values as is for our preview on screen. + // The OpenXR runtime however is still treating this as an sRGB format and + // will thus do an sRGB -> Linear conversion as expected. + // format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; + format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM; + break; + case VK_FORMAT_B8G8R8A8_SRGB: + // format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB; + format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM; + break; + case VK_FORMAT_R8G8B8A8_UINT: + format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT; + break; + case VK_FORMAT_B8G8R8A8_UINT: + format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UINT; + break; + default: + // continue with our default value + print_line("Unsupported swapchain format ", p_swapchain_format); + break; + } + + switch (p_sample_count) { + case 1: + samples = RenderingDevice::TEXTURE_SAMPLES_1; + break; + case 2: + samples = RenderingDevice::TEXTURE_SAMPLES_2; + break; + case 4: + samples = RenderingDevice::TEXTURE_SAMPLES_4; + break; + case 8: + samples = RenderingDevice::TEXTURE_SAMPLES_8; + break; + case 16: + samples = RenderingDevice::TEXTURE_SAMPLES_16; + break; + case 32: + samples = RenderingDevice::TEXTURE_SAMPLES_32; + break; + case 64: + samples = RenderingDevice::TEXTURE_SAMPLES_64; + break; + default: + // continue with our default value + print_line("Unsupported sample count ", p_sample_count); + break; + } + + Vector<RID> image_rids; + Vector<RID> framebuffers; + + // create Godot texture objects for each entry in our swapchain + for (uint64_t i = 0; i < swapchain_length; i++) { + RID image_rid = rendering_device->texture_create_from_extension( + p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY, + format, + samples, + usage_flags, + (uint64_t)images[i].image, + p_width, + p_height, + 1, + p_array_size); + + image_rids.push_back(image_rid); + + { + Vector<RID> fb; + fb.push_back(image_rid); + + RID fb_rid = rendering_device->framebuffer_create(fb, RenderingDevice::INVALID_ID, p_array_size); + framebuffers.push_back(fb_rid); + } + } + + data->image_rids = image_rids; + data->framebuffers = framebuffers; + + memfree(images); + + return true; +} + +bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) { + // Even though this is a Vulkan renderer we're using OpenGL coordinate systems + XrMatrix4x4f matrix; + XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + r_camera_matrix.matrix[j][i] = matrix.m[j * 4 + i]; + } + } + + return true; +} + +bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) { + SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data; + ERR_FAIL_NULL_V(data, false); + ERR_FAIL_COND_V(p_from_render_target.is_null(), false); + ERR_FAIL_NULL_V(RendererStorageRD::base_singleton, false); + + RID source_image = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(p_from_render_target); + ERR_FAIL_COND_V(source_image.is_null(), false); + + RID depth_image; // TODO implement + + ERR_FAIL_INDEX_V(p_image_index, data->framebuffers.size(), false); + RID fb = data->framebuffers[p_image_index]; + ERR_FAIL_COND_V(fb.is_null(), false); + + // Our vulkan extension can only be used in conjunction with our vulkan renderer. + // We need access to the effects object in order to have access to our copy logic. + // Breaking all the rules but there is no nice way to do this. + EffectsRD *effects = RendererStorageRD::base_singleton->get_effects(); + ERR_FAIL_NULL_V(effects, false); + effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview); + + return true; +} + +void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) { + if (*p_swapchain_graphics_data == nullptr) { + return; + } + + SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data; + + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + RenderingDevice *rendering_device = rendering_server->get_rendering_device(); + ERR_FAIL_NULL(rendering_device); + + for (int i = 0; i < data->image_rids.size(); i++) { + // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain + rendering_device->free(data->image_rids[i]); + } + data->image_rids.clear(); + + for (int i = 0; i < data->framebuffers.size(); i++) { + // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain + rendering_device->free(data->framebuffers[i]); + } + data->framebuffers.clear(); + + memdelete(data); + *p_swapchain_graphics_data = nullptr; +} + +#define ENUM_TO_STRING_CASE(e) \ + case e: { \ + return String(#e); \ + } break; + +String OpenXRVulkanExtension::get_swapchain_format_name(int64_t p_swapchain_format) const { + // This really should be in vulkan_context... + VkFormat format = VkFormat(p_swapchain_format); + switch (format) { + ENUM_TO_STRING_CASE(VK_FORMAT_UNDEFINED) + ENUM_TO_STRING_CASE(VK_FORMAT_R4G4_UNORM_PACK8) + ENUM_TO_STRING_CASE(VK_FORMAT_R4G4B4A4_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B4G4R4A4_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R5G6B5_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B5G6R5_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R5G5B5A1_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B5G5R5A1_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_A1R5G5B5_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SRGB) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_USCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SSCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_UINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SRGB_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_USCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SSCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_UINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_USCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SSCALED_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_UINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SINT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_USCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SSCALED) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_SINT) + ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_B10G11R11_UFLOAT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_D16_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_X8_D24_UNORM_PACK32) + ENUM_TO_STRING_CASE(VK_FORMAT_D32_SFLOAT) + ENUM_TO_STRING_CASE(VK_FORMAT_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_D16_UNORM_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_D24_UNORM_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_D32_SFLOAT_S8_UINT) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGB_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGB_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGBA_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGBA_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC2_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC2_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC3_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC3_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC4_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC4_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC5_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC6H_UFLOAT_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC6H_SFLOAT_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC7_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_BC7_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11G11_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11G11_SNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_UNORM_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_SRGB_BLOCK) + ENUM_TO_STRING_CASE(VK_FORMAT_G8B8G8R8_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8G8_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_R10X6_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R10X6G10X6_UNORM_2PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R12X4_UNORM_PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R12X4G12X4_UNORM_2PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16) + ENUM_TO_STRING_CASE(VK_FORMAT_G16B16G16R16_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_B16G16R16G16_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_420_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_422_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT) + ENUM_TO_STRING_CASE(VK_FORMAT_MAX_ENUM) + default: { + return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format)); + } break; + } +} diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h new file mode 100644 index 0000000000..1e34fe1f80 --- /dev/null +++ b/modules/openxr/extensions/openxr_vulkan_extension.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* openxr_vulkan_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_VULKAN_EXTENSION_H +#define OPENXR_VULKAN_EXTENSION_H + +#include "core/templates/vector.h" +#include "openxr_extension_wrapper.h" + +#include "drivers/vulkan/vulkan_context.h" + +// Forward declare these so we don't need OpenXR headers where-ever this is included +// Including OpenXR at this point gives loads and loads of compile issues especially +// on Windows because windows.h is EVIL and really shouldn't be included outside of platform +// but we really don't have a choice in the matter + +struct XrGraphicsRequirementsVulkanKHR; +struct XrVulkanInstanceCreateInfoKHR; +struct XrVulkanGraphicsDeviceGetInfoKHR; +struct XrVulkanDeviceCreateInfoKHR; +struct XrGraphicsBindingVulkanKHR; + +class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks { +public: + OpenXRVulkanExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRVulkanExtension() override; + + virtual void on_instance_created(const XrInstance p_instance) override; + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; + + virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) override; + virtual bool get_physical_device(VkPhysicalDevice *r_device) override; + virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override; + + virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override; + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override; + virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override; + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override; + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) override; + virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) override; + +private: + static OpenXRVulkanExtension *singleton; + static XrGraphicsBindingVulkanKHR graphics_binding_vulkan; // declaring this as static so we don't need to know its size and we only need it once when creating our session + + struct SwapchainGraphicsData { + bool is_multiview; + Vector<RID> image_rids; + Vector<RID> framebuffers; + }; + + bool check_graphics_api_support(XrVersion p_desired_version); + + VkInstance vulkan_instance = nullptr; + VkPhysicalDevice vulkan_physical_device = nullptr; + VkDevice vulkan_device = nullptr; + uint32_t vulkan_queue_family_index = 0; + uint32_t vulkan_queue_index = 0; + + XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements); + XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result); + XrResult xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device); + XrResult xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result); +}; + +#endif // !OPENXR_VULKAN_EXTENSION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp new file mode 100644 index 0000000000..2e9be48f01 --- /dev/null +++ b/modules/openxr/openxr_api.cpp @@ -0,0 +1,2422 @@ +/*************************************************************************/ +/* openxr_api.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_api.h" +#include "openxr_util.h" + +#include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/os/memory.h" +#include "core/version.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif + +#ifdef ANDROID_ENABLED +#include "extensions/openxr_android_extension.h" +#endif + +#ifdef VULKAN_ENABLED +#include "extensions/openxr_vulkan_extension.h" +#endif + +#include "openxr_interface.h" + +OpenXRAPI *OpenXRAPI::singleton = nullptr; + +bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { + // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled" + + if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) { +#ifdef TOOLS_ENABLED + // Disabled for now, using XR inside of the editor we'll be working on during the coming months. + return false; + + // bool enabled = GLOBAL_GET("xr/openxr/in_editor"); // EDITOR_GET("xr/openxr/in_editor"); + // return enabled; +#else + // we should never get here, editor hint won't be true if the editor isn't compiled in. + return false; +#endif + } else { + bool enabled = GLOBAL_GET("xr/openxr/enabled"); + return enabled; + } +} + +OpenXRAPI *OpenXRAPI::get_singleton() { + return singleton; +} + +String OpenXRAPI::get_default_action_map_resource_name() { + String name = GLOBAL_GET("xr/openxr/default_action_map"); + + return name; +} + +String OpenXRAPI::get_error_string(XrResult result) { + if (XR_SUCCEEDED(result)) { + return String("Succeeded"); + } + + if (instance == XR_NULL_HANDLE) { + Array args; + args.push_back(Variant(result)); + return String("Error code {0}").format(args); + } + + char resultString[XR_MAX_RESULT_STRING_SIZE]; + xrResultToString(instance, result, resultString); + + return String(resultString); +} + +String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const { + // This is rendering engine dependent... + if (graphics_extension) { + return graphics_extension->get_swapchain_format_name(p_swapchain_format); + } + + return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format)); +} + +bool OpenXRAPI::load_layer_properties() { + // This queries additional layers that are available and can be initialized when we create our OpenXR instance + if (layer_properties != nullptr) { + // already retrieved this + return true; + } + + // Note, instance is not yet setup so we can't use get_error_string to retrieve our error + XrResult result = xrEnumerateApiLayerProperties(0, &num_layer_properties, nullptr); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of api layer properties"); + + layer_properties = (XrApiLayerProperties *)memalloc(sizeof(XrApiLayerProperties) * num_layer_properties); + ERR_FAIL_NULL_V(layer_properties, false); + for (uint32_t i = 0; i < num_layer_properties; i++) { + layer_properties[i].type = XR_TYPE_API_LAYER_PROPERTIES; + layer_properties[i].next = nullptr; + } + + result = xrEnumerateApiLayerProperties(num_layer_properties, &num_layer_properties, layer_properties); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate api layer properties"); + +#ifdef DEBUG + for (uint32_t i = 0; i < num_layer_properties; i++) { + print_line("OpenXR: Found OpenXR layer ", layer_properties[i].layerName); + } +#endif + + return true; +} + +bool OpenXRAPI::load_supported_extensions() { + // This queries supported extensions that are available and can be initialized when we create our OpenXR instance + + if (supported_extensions != nullptr) { + // already retrieved this + return true; + } + + // Note, instance is not yet setup so we can't use get_error_string to retrieve our error + XrResult result = xrEnumerateInstanceExtensionProperties(nullptr, 0, &num_supported_extensions, nullptr); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate number of extension properties"); + + supported_extensions = (XrExtensionProperties *)memalloc(sizeof(XrExtensionProperties) * num_supported_extensions); + ERR_FAIL_NULL_V(supported_extensions, false); + + // set our types + for (uint32_t i = 0; i < num_supported_extensions; i++) { + supported_extensions[i].type = XR_TYPE_EXTENSION_PROPERTIES; + supported_extensions[i].next = nullptr; + } + result = xrEnumerateInstanceExtensionProperties(nullptr, num_supported_extensions, &num_supported_extensions, supported_extensions); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate extension properties"); + +#ifdef DEBUG + for (uint32_t i = 0; i < num_supported_extensions; i++) { + print_line("OpenXR: Found OpenXR extension ", supported_extensions[i].extensionName); + } +#endif + + return true; +} + +bool OpenXRAPI::is_extension_supported(const char *p_extension) const { + for (uint32_t i = 0; i < num_supported_extensions; i++) { + if (strcmp(supported_extensions[i].extensionName, p_extension) == 0) { +#ifdef DEBUG + print_line("OpenXR: requested extension", p_extension, "is supported"); +#endif + return true; + } + } + +#ifdef DEBUG + print_line("OpenXR: requested extension", p_extension, "is not supported"); +#endif + + return false; +} + +void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) { + CharString char_string = p_string.utf8(); + int len = char_string.length(); + if (len < p_buffer_len - 1) { + // was having weird CI issues with strcpy so.... + memcpy(p_buffer, char_string.get_data(), len); + p_buffer[len] = '\0'; + } else { + memcpy(p_buffer, char_string.get_data(), p_buffer_len - 1); + p_buffer[p_buffer_len - 1] = '\0'; + } +} + +bool OpenXRAPI::create_instance() { + // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable. + + // Append the extensions requested by the registered extension wrappers. + Map<const char *, bool *> requested_extensions; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + Map<const char *, bool *> wrapper_request_extensions = wrapper->get_request_extensions(); + + // requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end()); + for (auto &requested_extension : wrapper_request_extensions) { + requested_extensions[requested_extension.key] = requested_extension.value; + } + } + + // Add optional extensions for controllers that may be supported. + // Overkill to create extension classes for this. + requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available; + requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available; + requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available; + requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available; + requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available; + + // Check which extensions are supported + enabled_extensions.clear(); + for (auto &requested_extension : requested_extensions) { + if (!is_extension_supported(requested_extension.key)) { + if (requested_extension.value == nullptr) { + // nullptr means this is a manditory extension so we fail + ERR_FAIL_V_MSG(false, "OpenXR: OpenXR Runtime does not support OpenGL extension!"); + } else { + // set this extension as not supported + *requested_extension.value = false; + } + } else if (requested_extension.value != nullptr) { + // set this extension as supported + *requested_extension.value = true; + + // and record that we want to enable it + enabled_extensions.push_back(requested_extension.key); + } else { + // record that we want to enable this + enabled_extensions.push_back(requested_extension.key); + } + } + + // Get our project name + String project_name = GLOBAL_GET("application/config/name"); + + // Create our OpenXR instance + XrApplicationInfo application_info{ + "", // applicationName, we'll set this down below + 1, // applicationVersion, we don't currently have this + "Godot Game Engine", // engineName + VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc. + XR_CURRENT_API_VERSION // apiVersion + }; + + XrInstanceCreateInfo instance_create_info = { + XR_TYPE_INSTANCE_CREATE_INFO, // type + nullptr, // next + 0, // createFlags + application_info, // applicationInfo + 0, // enabledApiLayerCount, need to find out if we need support for this? + nullptr, // enabledApiLayerNames + uint32_t(enabled_extensions.size()), // enabledExtensionCount + enabled_extensions.ptr() // enabledExtensionNames + }; + + copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE); + + XrResult result = xrCreateInstance(&instance_create_info, &instance); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance."); + + // from this point on we can use get_error_string to get more info about our errors... + + XrInstanceProperties instanceProps = { + XR_TYPE_INSTANCE_PROPERTIES, // type; + nullptr, // next + 0, // runtimeVersion, from here will be set by our get call + "" // runtimeName + }; + result = xrGetInstanceProperties(instance, &instanceProps); + if (XR_FAILED(result)) { + // not fatal probably + print_line("OpenXR: Failed to get XR instance properties [", get_error_string(result), "]"); + } else { + print_line("OpenXR: Running on OpenXR runtime: ", instanceProps.runtimeName, " ", OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion)); + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_instance_created(instance); + } + + return true; +} + +bool OpenXRAPI::get_system_info() { + // Retrieve basic OpenXR system info based on the form factor we desire + + // Retrieve the system for our form factor, fails if form factor is not available + XrSystemGetInfo system_get_info = { + XR_TYPE_SYSTEM_GET_INFO, // type; + nullptr, // next + form_factor // formFactor + }; + + XrResult result = xrGetSystem(instance, &system_get_info, &system_id); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get system for our form factor [", get_error_string(result), "]"); + return false; + } + + // obtain info about our system, writing this out completely to make CI on Linux happy.. + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_system_properties_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + + XrSystemProperties system_properties = { + XR_TYPE_SYSTEM_PROPERTIES, // type + next_pointer, // next + 0, // systemId, from here will be set by our get call + 0, // vendorId + "", // systemName + { + 0, // maxSwapchainImageHeight + 0, // maxSwapchainImageWidth + 0, // maxLayerCount + }, // graphicsProperties + { + false, // orientationTracking + false // positionTracking + } // trackingProperties + }; + + result = xrGetSystemProperties(instance, system_id, &system_properties); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get System properties [", get_error_string(result), "]"); + return false; + } + + // remember this state, we'll use it later + system_name = String(system_properties.systemName); + vendor_id = system_properties.vendorId; + graphics_properties = system_properties.graphicsProperties; + tracking_properties = system_properties.trackingProperties; + + return true; +} + +bool OpenXRAPI::load_supported_view_configuration_types() { + // This queries the supported configuration types, likely there will only be one choosing between Mono (phone AR) and Stereo (HMDs) + + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + if (supported_view_configuration_types != nullptr) { + // free previous results + memfree(supported_view_configuration_types); + supported_view_configuration_types = nullptr; + } + + XrResult result = xrEnumerateViewConfigurations(instance, system_id, 0, &num_view_configuration_types, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]"); + return false; + } + + supported_view_configuration_types = (XrViewConfigurationType *)memalloc(sizeof(XrViewConfigurationType) * num_view_configuration_types); + ERR_FAIL_NULL_V(supported_view_configuration_types, false); + + result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations"); + +#ifdef DEBUG + for (uint32_t i = 0; i < num_view_configuration_types; i++) { + print_line("OpenXR: Found supported view configuration ", OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i])); + } +#endif + + return true; +} + +bool OpenXRAPI::is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const { + ERR_FAIL_NULL_V(supported_view_configuration_types, false); + + for (uint32_t i = 0; i < num_view_configuration_types; i++) { + if (supported_view_configuration_types[i] == p_configuration_type) { + return true; + } + } + + return false; +} + +bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type) { + // This loads our view configuration for each view so for a stereo HMD, we'll get two entries (that are likely identical) + // The returned data supplies us with the recommended render target size + + if (!is_view_configuration_supported(p_configuration_type)) { + print_line("OpenXR: View configuration ", OpenXRUtil::get_view_configuration_name(view_configuration), " is not supported."); + return false; + } + + if (view_configuration_views != nullptr) { + // free previous results + memfree(view_configuration_views); + view_configuration_views = nullptr; + } + + XrResult result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, 0, &view_count, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get view configuration count [", get_error_string(result), "]"); + return false; + } + + view_configuration_views = (XrViewConfigurationView *)memalloc(sizeof(XrViewConfigurationView) * view_count); + ERR_FAIL_NULL_V(view_configuration_views, false); + + for (uint32_t i = 0; i < view_count; i++) { + view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW; + view_configuration_views[i].next = nullptr; + } + + result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate view configurations"); + +#ifdef DEBUG + for (uint32_t i = 0; i < view_count; i++) { + print_line("OpenXR: Found supported view configuration view"); + print_line(" - width: ", view_configuration_views[i].maxImageRectWidth); + print_line(" - height: ", view_configuration_views[i].maxImageRectHeight); + print_line(" - sample count: ", view_configuration_views[i].maxSwapchainSampleCount); + print_line(" - recommended render width: ", view_configuration_views[i].recommendedImageRectWidth); + print_line(" - recommended render height: ", view_configuration_views[i].recommendedImageRectHeight); + print_line(" - recommended render sample count: ", view_configuration_views[i].recommendedSwapchainSampleCount); + } +#endif + + return true; +} + +void OpenXRAPI::destroy_instance() { + if (view_configuration_views != nullptr) { + memfree(view_configuration_views); + view_configuration_views = nullptr; + } + + if (supported_view_configuration_types != nullptr) { + memfree(supported_view_configuration_types); + supported_view_configuration_types = nullptr; + } + + if (instance != XR_NULL_HANDLE) { + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_instance_destroyed(); + } + + xrDestroyInstance(instance); + instance = XR_NULL_HANDLE; + } + enabled_extensions.clear(); +} + +bool OpenXRAPI::create_session() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + ERR_FAIL_COND_V(session != XR_NULL_HANDLE, false); + + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_session_create_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + + XrSessionCreateInfo session_create_info = { + XR_TYPE_SESSION_CREATE_INFO, // type + next_pointer, // next + 0, // createFlags + system_id // systemId + }; + + XrResult result = xrCreateSession(instance, &session_create_info, &session); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create session [", get_error_string(result), "]"); + return false; + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_session_created(session); + } + + return true; +} + +bool OpenXRAPI::load_supported_reference_spaces() { + // loads the supported reference spaces for our OpenXR session + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + if (supported_reference_spaces != nullptr) { + // free previous results + memfree(supported_reference_spaces); + supported_reference_spaces = nullptr; + } + + XrResult result = xrEnumerateReferenceSpaces(session, 0, &num_reference_spaces, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get reference space count [", get_error_string(result), "]"); + return false; + } + + supported_reference_spaces = (XrReferenceSpaceType *)memalloc(sizeof(XrReferenceSpaceType) * num_reference_spaces); + ERR_FAIL_NULL_V(supported_reference_spaces, false); + + result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces"); + + // #ifdef DEBUG + for (uint32_t i = 0; i < num_reference_spaces; i++) { + print_line("OpenXR: Found supported reference space ", OpenXRUtil::get_reference_space_name(supported_reference_spaces[i])); + } + // #endif + + return true; +} + +bool OpenXRAPI::is_reference_space_supported(XrReferenceSpaceType p_reference_space) { + ERR_FAIL_NULL_V(supported_reference_spaces, false); + + for (uint32_t i = 0; i < num_reference_spaces; i++) { + if (supported_reference_spaces[i] == p_reference_space) { + return true; + } + } + + return false; +} + +bool OpenXRAPI::setup_spaces() { + XrResult result; + + XrPosef identityPose = { + { 0.0, 0.0, 0.0, 1.0 }, + { 0.0, 0.0, 0.0 } + }; + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + // create play space + { + if (!is_reference_space_supported(reference_space)) { + print_line("OpenXR: reference space ", OpenXRUtil::get_reference_space_name(reference_space), " is not supported."); + return false; + } + + XrReferenceSpaceCreateInfo play_space_create_info = { + XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type + nullptr, // next + reference_space, // referenceSpaceType + identityPose // poseInReferenceSpace + }; + + result = xrCreateReferenceSpace(session, &play_space_create_info, &play_space); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create play space [", get_error_string(result), "]"); + return false; + } + } + + // create view space + { + if (!is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_VIEW)) { + print_line("OpenXR: reference space XR_REFERENCE_SPACE_TYPE_VIEW is not supported."); + return false; + } + + XrReferenceSpaceCreateInfo view_space_create_info = { + XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type + nullptr, // next + XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType + identityPose // poseInReferenceSpace + }; + + result = xrCreateReferenceSpace(session, &view_space_create_info, &view_space); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create view space [", get_error_string(result), "]"); + return false; + } + } + + return true; +} + +bool OpenXRAPI::load_supported_swapchain_formats() { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + if (supported_swapchain_formats != nullptr) { + // free previous results + memfree(supported_swapchain_formats); + supported_swapchain_formats = nullptr; + } + + XrResult result = xrEnumerateSwapchainFormats(session, 0, &num_swapchain_formats, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchain format count [", get_error_string(result), "]"); + return false; + } + + supported_swapchain_formats = (int64_t *)memalloc(sizeof(int64_t) * num_swapchain_formats); + ERR_FAIL_NULL_V(supported_swapchain_formats, false); + + result = xrEnumerateSwapchainFormats(session, num_swapchain_formats, &num_swapchain_formats, supported_swapchain_formats); + ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate swapchain formats"); + + // #ifdef DEBUG + for (uint32_t i = 0; i < num_swapchain_formats; i++) { + print_line("OpenXR: Found supported swapchain format ", get_swapchain_format_name(supported_swapchain_formats[i])); + } + // #endif + + return true; +} + +bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) { + ERR_FAIL_NULL_V(supported_swapchain_formats, false); + + for (uint32_t i = 0; i < num_swapchain_formats; i++) { + if (supported_swapchain_formats[i] == p_swapchain_format) { + return true; + } + } + + return false; +} + +bool OpenXRAPI::create_main_swapchain() { + ERR_FAIL_NULL_V(graphics_extension, false); + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + /* + TODO: We need to improve on this, for now we're taking our old approach of creating our main swapchains and substituting + those for the ones Godot normally creates. + This however means we can only use swapchains for our main XR view. + + It would have been nicer if we could override the swapchain creation in Godot with ours but we have a timing issue here. + We can't create XR swapchains until after our XR session is fully instantiated, yet Godot creates its swapchain much earlier. + + Also Godot only creates a swapchain for the main output. + OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system + to optimise text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're + already rendering the next frame. + + Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create, + as we render 3D content into internal buffers that are copied into the swapchain, we don't get any of the performance gains + until such time as we implement VRS. + */ + + // Build a vector with swapchain formats we want to use, from best fit to worst + Vector<int64_t> usable_swapchain_formats; + int64_t swapchain_format_to_use = 0; + + graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats); + + // now find out which one is supported + for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { + if (is_swapchain_format_supported(usable_swapchain_formats[i])) { + swapchain_format_to_use = usable_swapchain_formats[i]; + } + } + + if (swapchain_format_to_use == 0) { + swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... + print_line("Couldn't find usable swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); + } else { + print_line("Using swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); + } + + Size2 recommended_size = get_recommended_target_size(); + + if (!create_swapchain(swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchain, &swapchain_graphics_data)) { + return false; + } + + views = (XrView *)memalloc(sizeof(XrView) * view_count); + ERR_FAIL_NULL_V_MSG(views, false, "OpenXR Couldn't allocate memory for views"); + + projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count); + ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views"); + + for (uint32_t i = 0; i < view_count; i++) { + views[i].type = XR_TYPE_VIEW; + views[i].next = nullptr; + + projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; + projection_views[i].next = nullptr; + projection_views[i].subImage.swapchain = swapchain; + projection_views[i].subImage.imageArrayIndex = i; + projection_views[i].subImage.imageRect.offset.x = 0; + projection_views[i].subImage.imageRect.offset.y = 0; + projection_views[i].subImage.imageRect.extent.width = recommended_size.width; + projection_views[i].subImage.imageRect.extent.height = recommended_size.height; + }; + + return true; +}; + +void OpenXRAPI::destroy_session() { + if (running && session != XR_NULL_HANDLE) { + xrEndSession(session); + } + + if (graphics_extension) { + graphics_extension->cleanup_swapchain_graphics_data(&swapchain_graphics_data); + } + + if (views != nullptr) { + memfree(views); + views = nullptr; + } + + if (projection_views != nullptr) { + memfree(projection_views); + projection_views = nullptr; + } + + if (swapchain != XR_NULL_HANDLE) { + xrDestroySwapchain(swapchain); + swapchain = XR_NULL_HANDLE; + } + + if (supported_swapchain_formats != nullptr) { + memfree(supported_swapchain_formats); + supported_swapchain_formats = nullptr; + } + + // destroy our spaces + if (play_space != XR_NULL_HANDLE) { + xrDestroySpace(play_space); + play_space = XR_NULL_HANDLE; + } + if (view_space != XR_NULL_HANDLE) { + xrDestroySpace(view_space); + view_space = XR_NULL_HANDLE; + } + + if (supported_reference_spaces != nullptr) { + // free previous results + memfree(supported_reference_spaces); + supported_reference_spaces = nullptr; + } + + if (session != XR_NULL_HANDLE) { + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_session_destroyed(); + } + + xrDestroySession(session); + session = XR_NULL_HANDLE; + } +} + +bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + ERR_FAIL_NULL_V(graphics_extension, false); + + XrResult result; + + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_swapchain_create_info_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + + XrSwapchainCreateInfo swapchain_create_info = { + XR_TYPE_SWAPCHAIN_CREATE_INFO, // type + next_pointer, // next + 0, // createFlags + XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, // usageFlags + p_swapchain_format, // format + p_sample_count, // sampleCount + p_width, // width + p_height, // height + 1, // faceCount + p_array_size, // arraySize + 1 // mipCount + }; + + XrSwapchain new_swapchain; + result = xrCreateSwapchain(session, &swapchain_create_info, &new_swapchain); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchain [", get_error_string(result), "]"); + return false; + } + + if (!graphics_extension->get_swapchain_image_data(new_swapchain, p_swapchain_format, p_width, p_height, p_sample_count, p_array_size, r_swapchain_graphics_data)) { + xrDestroySwapchain(new_swapchain); + return false; + } + + r_swapchain = new_swapchain; + + return true; +} + +bool OpenXRAPI::on_state_idle() { +#ifdef DEBUG + print_line("On state idle"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_idle(); + } + + return true; +} + +bool OpenXRAPI::on_state_ready() { +#ifdef DEBUG + print_line("On state ready"); +#endif + + // begin session + XrSessionBeginInfo session_begin_info = { + XR_TYPE_SESSION_BEGIN_INFO, // type + nullptr, // next + view_configuration // primaryViewConfigurationType + }; + + XrResult result = xrBeginSession(session, &session_begin_info); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to begin session [", get_error_string(result), "]"); + return false; + } + + // This is when we create our swapchain, this can be a "long" time after Godot finishes, we can deal with this for now + // but once we want to provide Viewports for additional layers where OpenXR requires us to create further swapchains, + // we'll be creating those viewport WAY before we reach this point. + // We may need to implement a wait in our init in main.cpp polling our events until the session is ready. + // That will be very very ugly + // The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module + + if (!create_main_swapchain()) { + return false; + } + + // we're running + running = true; + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_ready(); + } + + if (xr_interface) { + xr_interface->on_state_ready(); + } + + // TODO Tell android + + return true; +} + +bool OpenXRAPI::on_state_synchronized() { +#ifdef DEBUG + print_line("On state synchronized"); +#endif + + // Just in case, see if we already have active trackers... + List<RID> trackers; + tracker_owner.get_owned_list(&trackers); + for (int i = 0; i < trackers.size(); i++) { + tracker_check_profile(trackers[i]); + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_synchronized(); + } + + return true; +} + +bool OpenXRAPI::on_state_visible() { +#ifdef DEBUG + print_line("On state visible"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_visible(); + } + + if (xr_interface) { + xr_interface->on_state_visible(); + } + + return true; +} + +bool OpenXRAPI::on_state_focused() { +#ifdef DEBUG + print_line("On state focused"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_focused(); + } + + if (xr_interface) { + xr_interface->on_state_focused(); + } + + return true; +} + +bool OpenXRAPI::on_state_stopping() { +#ifdef DEBUG + print_line("On state stopping"); +#endif + + if (xr_interface) { + xr_interface->on_state_stopping(); + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_stopping(); + } + + if (running) { + XrResult result = xrEndSession(session); + if (XR_FAILED(result)) { + // we only report this.. + print_line("OpenXR: Failed to end session [", get_error_string(result), "]"); + } + + running = false; + } + + // TODO further cleanup + + return true; +} + +bool OpenXRAPI::on_state_loss_pending() { +#ifdef DEBUG + print_line("On state loss pending"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_loss_pending(); + } + + // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting) + + return true; +} + +bool OpenXRAPI::on_state_exiting() { +#ifdef DEBUG + print_line("On state existing"); +#endif + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_state_exiting(); + } + + // TODO need to look into the correct action here, read up on the spec but we may need to signal Godot to exit (if it's not already exiting) + + return true; +} + +bool OpenXRAPI::is_initialized() { + return (instance != XR_NULL_HANDLE); +} + +bool OpenXRAPI::is_running() { + if (instance == XR_NULL_HANDLE) { + return false; + } + if (session == XR_NULL_HANDLE) { + return false; + } + + return running; +} + +bool OpenXRAPI::initialize(const String &p_rendering_driver) { + ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created"); + + if (p_rendering_driver == "vulkan") { +#ifdef VULKAN_ENABLED + graphics_extension = memnew(OpenXRVulkanExtension(this)); + register_extension_wrapper(graphics_extension); +#else + // shouldn't be possible... + ERR_FAIL_V(false); +#endif + } else if (p_rendering_driver == "opengl3") { +#ifdef OPENGL3_ENABLED + // graphics_extension = memnew(OpenXROpenGLExtension(this)); + // register_extension_wrapper(graphics_extension); + ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time."); +#else + // shouldn't be possible... + ERR_FAIL_V(false); +#endif + } else { + ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device."); + } + + // initialize + if (!load_layer_properties()) { + destroy_instance(); + return false; + } + + if (!load_supported_extensions()) { + destroy_instance(); + return false; + } + + if (!create_instance()) { + destroy_instance(); + return false; + } + + if (!get_system_info()) { + destroy_instance(); + return false; + } + + if (!load_supported_view_configuration_types()) { + destroy_instance(); + return false; + } + + if (!load_supported_view_configuration_views(view_configuration)) { + destroy_instance(); + return false; + } + + return true; +} + +bool OpenXRAPI::initialize_session() { + if (!create_session()) { + destroy_session(); + return false; + } + + if (!load_supported_reference_spaces()) { + destroy_session(); + return false; + } + + if (!setup_spaces()) { + destroy_session(); + return false; + } + + if (!load_supported_swapchain_formats()) { + destroy_session(); + return false; + } + + return true; +} + +void OpenXRAPI::finish() { + destroy_session(); + + destroy_instance(); +} + +void OpenXRAPI::set_xr_interface(OpenXRInterface *p_xr_interface) { + xr_interface = p_xr_interface; +} + +void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) { + registered_extension_wrappers.push_back(p_extension_wrapper); +} + +Size2 OpenXRAPI::get_recommended_target_size() { + ERR_FAIL_NULL_V(view_configuration_views, Size2()); + + Size2 target_size; + + target_size.width = view_configuration_views[0].recommendedImageRectWidth; + target_size.height = view_configuration_views[0].recommendedImageRectHeight; + + return target_size; +} + +XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) { + XrResult result; + + ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE); + + // xrWaitFrame not run yet + if (frame_state.predictedDisplayTime == 0) { + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + // Get timing for the next frame, as that is the current frame we're processing + XrTime display_time = get_next_frame_time(); + + XrSpaceVelocity velocity = { + XR_TYPE_SPACE_VELOCITY, // type + nullptr, // next + 0, // velocityFlags + { 0.0, 0.0, 0.0 }, // linearVelocity + { 0.0, 0.0, 0.0 } // angularVelocity + }; + + XrSpaceLocation location = { + XR_TYPE_SPACE_LOCATION, // type + &velocity, // next + 0, // locationFlags + { + { 0.0, 0.0, 0.0, 0.0 }, // orientation + { 0.0, 0.0, 0.0 } // position + } // pose + }; + + result = xrLocateSpace(view_space, play_space, display_time, &location); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to locate view space in play space [", get_error_string(result), "]"); + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform); + parse_velocities(velocity, r_linear_velocity, r_angular_velocity); + + if (head_pose_confidence != confidence) { + // prevent error spam + head_pose_confidence = confidence; + if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) { + print_line("OpenXR head space location not valid (check tracking?)"); +#ifdef DEBUG + } else if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_LOW) { + print_line("OpenVR Head pose now tracking with low confidence"); + } else { + print_line("OpenVR Head pose now tracking with high confidence"); +#endif + } + } + + return confidence; +} + +bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) { + ERR_FAIL_COND_V(!running, false); + + // xrWaitFrame not run yet + if (frame_state.predictedDisplayTime == 0) { + return false; + } + + // we don't have valid view info + if (views == nullptr || !view_pose_valid) { + return false; + } + + // Note, the timing of this is set right before rendering, which is what we need here. + r_transform = transform_from_pose(views[p_view].pose); + + return true; +} + +bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix) { + ERR_FAIL_COND_V(!running, false); + ERR_FAIL_NULL_V(graphics_extension, false); + + // xrWaitFrame not run yet + if (frame_state.predictedDisplayTime == 0) { + return false; + } + + // we don't have valid view info + if (views == nullptr || !view_pose_valid) { + return false; + } + + return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); +} + +bool OpenXRAPI::poll_events() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + XrEventDataBuffer runtimeEvent; + runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER; + runtimeEvent.next = nullptr; + // runtimeEvent.varying = ... + + XrResult pollResult = xrPollEvent(instance, &runtimeEvent); + while (pollResult == XR_SUCCESS) { + bool handled = false; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + handled |= wrapper->on_event_polled(runtimeEvent); + } + switch (runtimeEvent.type) { + case XR_TYPE_EVENT_DATA_EVENTS_LOST: { + XrEventDataEventsLost *event = (XrEventDataEventsLost *)&runtimeEvent; + + // We probably didn't poll fast enough, just output warning + WARN_PRINT("OpenXR EVENT: " + itos(event->lostEventCount) + " event data lost!"); + } break; + case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: { + // XrEventDataVisibilityMaskChangedKHR *event = (XrEventDataVisibilityMaskChangedKHR *)&runtimeEvent; + + // TODO implement this in the future, we should call xrGetVisibilityMaskKHR to obtain a mask, + // this will allow us to prevent rendering the part of our view which is never displayed giving us + // a decent performance improvement. + + print_verbose("OpenXR EVENT: STUB: visibility mask changed"); + } break; + case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: { + XrEventDataInstanceLossPending *event = (XrEventDataInstanceLossPending *)&runtimeEvent; + + // TODO We get this event if we're about to loose our OpenXR instance. + // We should queue exiting Godot at this point. + + print_verbose("OpenXR EVENT: instance loss pending at " + itos(event->lossTime)); + return false; + } break; + case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { + XrEventDataSessionStateChanged *event = (XrEventDataSessionStateChanged *)&runtimeEvent; + + session_state = event->state; + if (session_state >= XR_SESSION_STATE_MAX_ENUM) { + print_verbose("OpenXR EVENT: session state changed to UNKNOWN - " + itos(session_state)); + } else { + print_verbose("OpenXR EVENT: session state changed to " + OpenXRUtil::get_session_state_name(session_state)); + + switch (session_state) { + case XR_SESSION_STATE_IDLE: + on_state_idle(); + break; + case XR_SESSION_STATE_READY: + on_state_ready(); + break; + case XR_SESSION_STATE_SYNCHRONIZED: + on_state_synchronized(); + break; + case XR_SESSION_STATE_VISIBLE: + on_state_visible(); + break; + case XR_SESSION_STATE_FOCUSED: + on_state_focused(); + break; + case XR_SESSION_STATE_STOPPING: + on_state_stopping(); + break; + case XR_SESSION_STATE_LOSS_PENDING: + on_state_loss_pending(); + break; + case XR_SESSION_STATE_EXITING: + on_state_exiting(); + break; + default: + break; + } + } + } break; + case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: { + XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent; + + print_verbose("OpenXR EVENT: reference space type " + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!"); + if (event->poseValid && xr_interface) { + xr_interface->on_pose_recentered(); + } + } break; + case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: { + print_verbose("OpenXR EVENT: interaction profile changed!"); + + XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent; + + List<RID> trackers; + tracker_owner.get_owned_list(&trackers); + for (int i = 0; i < trackers.size(); i++) { + tracker_check_profile(trackers[i], event->session); + } + + } break; + default: + if (!handled) { + print_verbose("OpenXR Unhandled event type " + OpenXRUtil::get_structure_type_name(runtimeEvent.type)); + } + break; + } + + runtimeEvent.type = XR_TYPE_EVENT_DATA_BUFFER; + pollResult = xrPollEvent(instance, &runtimeEvent); + } + + if (pollResult == XR_EVENT_UNAVAILABLE) { + // processed all events in the queue + return true; + } else { + ERR_FAIL_V_MSG(false, "OpenXR: Failed to poll events!"); + } +} + +bool OpenXRAPI::process() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + if (!poll_events()) { + return false; + } + + if (!running) { + return false; + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_process(); + } + + return true; +} + +bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) { + ERR_FAIL_COND_V(image_acquired, true); // this was not released when it should be, error out and re-use... + + XrResult result; + XrSwapchainImageAcquireInfo swapchain_image_acquire_info = { + XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type + nullptr // next + }; + result = xrAcquireSwapchainImage(p_swapchain, &swapchain_image_acquire_info, &r_image_index); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]"); + return false; + } + + XrSwapchainImageWaitInfo swapchain_image_wait_info = { + XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, // type + nullptr, // next + 17000000 // timeout in nanoseconds + }; + + result = xrWaitSwapchainImage(p_swapchain, &swapchain_image_wait_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]"); + return false; + } + + return true; +} + +bool OpenXRAPI::release_image(XrSwapchain p_swapchain) { + XrSwapchainImageReleaseInfo swapchain_image_release_info = { + XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type + nullptr // next + }; + XrResult result = xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]"); + return false; + } + + return true; +} + +void OpenXRAPI::pre_render() { + ERR_FAIL_COND(instance == XR_NULL_HANDLE); + + if (!running) { + return; + } + + // Waitframe does 2 important things in our process: + // 1) It provides us with predictive timing, telling us when OpenXR expects to display the frame we're about to commit + // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible + // This must thus be called as close to when we start rendering as possible + XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr }; + XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state); + if (XR_FAILED(result)) { + print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]"); + + // reset just in case + frame_state.predictedDisplayTime = 0; + frame_state.predictedDisplayPeriod = 0; + frame_state.shouldRender = false; + + return; + } + + if (frame_state.predictedDisplayPeriod > 500000000) { + // display period more then 0.5 seconds? must be wrong data + print_verbose("OpenXR resetting invalid display period " + rtos(frame_state.predictedDisplayPeriod)); + frame_state.predictedDisplayPeriod = 0; + } + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_pre_render(); + } + + // Get our view info for the frame we're about to render, note from the OpenXR manual: + // "Repeatedly calling xrLocateViews with the same time may not necessarily return the same result. Instead the prediction gets increasingly accurate as the function is called closer to the given time for which a prediction is made" + + // We're calling this "relatively" early, the positioning we're obtaining here will be used to do our frustum culling, + // occlusion culling, etc. There is however a technique that we can investigate in the future where after our entire + // Vulkan command buffer is build, but right before vkSubmitQueue is called, we call xrLocateViews one more time and + // update the view and projection matrix once more with a slightly more accurate predication and then submit the + // command queues. + + // That is not possible yet but worth investigating in the future. + + XrViewLocateInfo view_locate_info = { + XR_TYPE_VIEW_LOCATE_INFO, // type + nullptr, // next + view_configuration, // viewConfigurationType + frame_state.predictedDisplayTime, // displayTime + play_space // space + }; + XrViewState view_state = { + XR_TYPE_VIEW_STATE, // type + nullptr, // next + 0 // viewStateFlags + }; + uint32_t view_count_output; + result = xrLocateViews(session, &view_locate_info, &view_state, view_count, &view_count_output, views); + if (XR_FAILED(result)) { + print_line("OpenXR: Couldn't locate views [", get_error_string(result), "]"); + return; + } + + bool pose_valid = true; + for (uint64_t i = 0; i < view_count_output; i++) { + if ((view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0 || + (view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0) { + pose_valid = false; + } + } + if (view_pose_valid != pose_valid) { + view_pose_valid = pose_valid; +#ifdef DEBUG + if (!view_pose_valid) { + print_line("OpenXR View pose became invalid"); + } else { + print_line("OpenXR View pose became valid"); + } +#endif + } + + // let's start our frame.. + XrFrameBeginInfo frame_begin_info = { + XR_TYPE_FRAME_BEGIN_INFO, // type + nullptr // next + }; + result = xrBeginFrame(session, &frame_begin_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to being frame [", get_error_string(result), "]"); + return; + } +} + +bool OpenXRAPI::pre_draw_viewport(RID p_render_target) { + if (!can_render()) { + return false; + } + + // TODO: at some point in time we may support multiple viewports in which case we need to handle that... + + return true; +} + +void OpenXRAPI::post_draw_viewport(RID p_render_target) { + if (!can_render()) { + return; + } + + // TODO: at some point in time we may support multiple viewports in which case we need to handle that... + + // TODO: if we can get PR 51179 to work properly we can change away from this approach and move this into get_external_texture or something + if (!image_acquired) { + if (!acquire_image(swapchain, image_index)) { + return; + } + image_acquired = true; + + // print_line("OpenXR: acquired image " + itos(image_index) + ", copying..."); + + // Copy our buffer into our swap chain (remove once PR 51179 is done) + graphics_extension->copy_render_target_to_image(p_render_target, swapchain_graphics_data, image_index); + } +}; + +void OpenXRAPI::end_frame() { + XrResult result; + + ERR_FAIL_COND(instance == XR_NULL_HANDLE); + + if (!running) { + return; + } + + if (frame_state.shouldRender && view_pose_valid && !image_acquired) { + print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!"); + } + + // must have: + // - shouldRender set to true + // - a valid view pose for projection_views[eye].pose to submit layer + // - an image to render + if (!frame_state.shouldRender || !view_pose_valid || !image_acquired) { + // submit 0 layers when we shouldn't render + XrFrameEndInfo frame_end_info = { + XR_TYPE_FRAME_END_INFO, // type + nullptr, // next + frame_state.predictedDisplayTime, // displayTime + XR_ENVIRONMENT_BLEND_MODE_OPAQUE, // environmentBlendMode + 0, // layerCount + nullptr // layers + }; + result = xrEndFrame(session, &frame_end_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to end frame! [", get_error_string(result), "]"); + return; + } + + // neither eye is rendered + return; + } + + // release our swapchain image if we acquired it + if (image_acquired) { + image_acquired = false; // whether we succeed or not, consider this released. + + release_image(swapchain); + } + + for (uint32_t eye = 0; eye < view_count; eye++) { + projection_views[eye].fov = views[eye].fov; + projection_views[eye].pose = views[eye].pose; + } + + Vector<const XrCompositionLayerBaseHeader *> layers_list; + + // Add composition layers from providers + for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) { + XrCompositionLayerBaseHeader *layer = provider->get_composition_layer(); + if (layer) { + layers_list.push_back(layer); + } + } + + XrCompositionLayerProjection projection_layer = { + XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type + nullptr, // next + layers_list.size() > 1 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags + play_space, // space + view_count, // viewCount + projection_views, // views + }; + layers_list.push_back((const XrCompositionLayerBaseHeader *)&projection_layer); + + XrFrameEndInfo frame_end_info = { + XR_TYPE_FRAME_END_INFO, // type + nullptr, // next + frame_state.predictedDisplayTime, // displayTime + XR_ENVIRONMENT_BLEND_MODE_OPAQUE, // environmentBlendMode + static_cast<uint32_t>(layers_list.size()), // layerCount + layers_list.ptr() // layers + }; + result = xrEndFrame(session, &frame_end_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to end frame! [", get_error_string(result), "]"); + return; + } +} + +OpenXRAPI::OpenXRAPI() { + // OpenXRAPI is only constructed if OpenXR is enabled. + singleton = this; + + if (Engine::get_singleton()->is_editor_hint()) { + // Enabled OpenXR in the editor? Adjust our settings for the editor + + } else { + // Load settings from project settings + int ff = GLOBAL_GET("xr/openxr/form_factor"); + switch (ff) { + case 0: { + form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; + } break; + case 1: { + form_factor = XR_FORM_FACTOR_HANDHELD_DISPLAY; + } break; + default: + break; + } + + int vc = GLOBAL_GET("xr/openxr/view_configuration"); + switch (vc) { + case 0: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO; + } break; + case 1: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; + } break; + /* we don't support quad and observer configurations (yet) + case 2: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO; + } break; + case 3: { + view_configuration = XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT; + } break; + */ + default: + break; + } + + int rs = GLOBAL_GET("xr/openxr/reference_space"); + switch (rs) { + case 0: { + reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL; + } break; + case 1: { + reference_space = XR_REFERENCE_SPACE_TYPE_STAGE; + } break; + default: + break; + } + } + + // reset a few things that can't be done in our class definition + frame_state.predictedDisplayTime = 0; + frame_state.predictedDisplayPeriod = 0; + +#ifdef ANDROID_ENABLED + // our android wrapper will initialize our android loader at this point + register_extension_wrapper(memnew(OpenXRAndroidExtension(this))); +#endif +} + +OpenXRAPI::~OpenXRAPI() { + // cleanup our composition layer providers + for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) { + memdelete(provider); + } + composition_layer_providers.clear(); + + // cleanup our extension wrappers + for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { + memdelete(extension_wrapper); + } + registered_extension_wrappers.clear(); + + if (supported_extensions != nullptr) { + memfree(supported_extensions); + supported_extensions = nullptr; + } + + if (layer_properties != nullptr) { + memfree(layer_properties); + layer_properties = nullptr; + } + + singleton = nullptr; +} + +Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) { + Quaternion q(p_pose.orientation.x, p_pose.orientation.y, p_pose.orientation.z, p_pose.orientation.w); + Basis basis(q); + Vector3 origin(p_pose.position.x, p_pose.position.y, p_pose.position.z); + + return Transform3D(basis, origin); +} + +template <typename T> +XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) { + Basis basis; + Vector3 origin; + XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; + const auto &pose = p_location.pose; + + // Check orientation + if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { + Quaternion q(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w); + r_transform.basis = Basis(q); + + if (p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) { + // Fully valid orientation, so either 3DOF or 6DOF tracking with high confidence so default to HIGH_TRACKING + confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + } else { + // Orientation is being tracked but we're using old/predicted data, so low tracking confidence + confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW; + } + } else { + r_transform.basis = Basis(); + } + + // Check location + if (p_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { + r_transform.origin = Vector3(pose.position.x, pose.position.y, pose.position.z); + + if (!(p_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT)) { + // Location is being tracked but we're using old/predicted data, so low tracking confidence + confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW; + } else if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) { + // Position tracking without orientation tracking? + confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + } + } else { + // No tracking or 3DOF I guess.. + r_transform.origin = Vector3(); + } + + return confidence; +} + +XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform) { + return _transform_from_location(p_location, r_transform); +} + +XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform) { + return _transform_from_location(p_location, r_transform); +} + +void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity) { + if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) { + XrVector3f linear_velocity = p_velocity.linearVelocity; + r_linear_velocity = Vector3(linear_velocity.x, linear_velocity.y, linear_velocity.z); + } else { + r_linear_velocity = Vector3(); + } + if (p_velocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) { + XrVector3f angular_velocity = p_velocity.angularVelocity; + r_angular_velocity = Vector3(angular_velocity.x, angular_velocity.y, angular_velocity.z); + } else { + r_angular_velocity = Vector3(); + } +} + +RID OpenXRAPI::get_tracker_rid(XrPath p_path) { + List<RID> current; + tracker_owner.get_owned_list(¤t); + for (int i = 0; i < current.size(); i++) { + Tracker *tracker = tracker_owner.get_or_null(current[i]); + if (tracker && tracker->toplevel_path == p_path) { + return current[i]; + } + } + + return RID(); +} + +RID OpenXRAPI::tracker_create(const String p_name) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID()); + + Tracker new_tracker; + new_tracker.name = p_name; + new_tracker.toplevel_path = XR_NULL_PATH; + new_tracker.active_profile_rid = RID(); + + XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_tracker.toplevel_path); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + return tracker_owner.make_rid(new_tracker); +} + +String OpenXRAPI::tracker_get_name(RID p_tracker) { + if (p_tracker.is_null()) { + return String("None"); + } + + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL_V(tracker, String()); + + return tracker->name; +} + +void OpenXRAPI::tracker_check_profile(RID p_tracker, XrSession p_session) { + if (p_session == XR_NULL_HANDLE) { + p_session = session; + } + + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL(tracker); + + if (tracker->toplevel_path == XR_NULL_PATH) { + // no path, how was this even created? + return; + } + + XrInteractionProfileState profile_state = { + XR_TYPE_INTERACTION_PROFILE_STATE, // type + nullptr, // next + XR_NULL_PATH // interactionProfile + }; + + XrResult result = xrGetCurrentInteractionProfile(p_session, tracker->toplevel_path, &profile_state); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get interaction profile for", itos(tracker->toplevel_path), "[", get_error_string(result), "]"); + return; + } + + XrPath new_profile = profile_state.interactionProfile; + XrPath was_profile = get_interaction_profile_path(tracker->active_profile_rid); + if (was_profile != new_profile) { + tracker->active_profile_rid = get_interaction_profile_rid(new_profile); + + if (xr_interface) { + xr_interface->tracker_profile_changed(p_tracker, tracker->active_profile_rid); + } + } +} + +void OpenXRAPI::tracker_free(RID p_tracker) { + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL(tracker); + + // there is nothing to free here + + tracker_owner.free(p_tracker); +} + +RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_name, const int p_priority) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID()); + ActionSet action_set; + + action_set.name = p_name; + action_set.is_attached = false; + + // create our action set... + XrActionSetCreateInfo action_set_info = { + XR_TYPE_ACTION_SET_CREATE_INFO, // type + nullptr, // next + "", // actionSetName + "", // localizedActionSetName + uint32_t(p_priority) // priority + }; + + copy_string_to_char_buffer(p_name, action_set_info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE); + copy_string_to_char_buffer(p_localized_name, action_set_info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE); + + // print_line("Creating action set ", action_set_info.actionSetName, " - ", action_set_info.localizedActionSetName, " (", itos(action_set_info.priority), ")"); + + XrResult result = xrCreateActionSet(instance, &action_set_info, &action_set.handle); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to create action set ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + return action_set_owner.make_rid(action_set); +} + +String OpenXRAPI::action_set_get_name(RID p_action_set) { + if (p_action_set.is_null()) { + return String("None"); + } + + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL_V(action_set, String()); + + return action_set->name; +} + +bool OpenXRAPI::action_set_attach(RID p_action_set) { + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL_V(action_set, false); + + if (action_set->is_attached) { + // already attached + return true; + } + + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + // So according to the docs, once we attach our action set to our session it becomes read only.. + // https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/xrAttachSessionActionSets.html + XrSessionActionSetsAttachInfo attach_info = { + XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, // type + nullptr, // next + 1, // countActionSets, + &action_set->handle // actionSets + }; + + XrResult result = xrAttachSessionActionSets(session, &attach_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to attach action set! [", get_error_string(result), "]"); + return false; + } + + action_set->is_attached = true; + + /* For debugging: + print_verbose("Attached set " + action_set->name); + List<RID> action_rids; + action_owner.get_owned_list(&action_rids); + for (int i = 0; i < action_rids.size(); i++) { + Action * action = action_owner.get_or_null(action_rids[i]); + if (action && action->action_set_rid == p_action_set) { + print_verbose(" - Action " + action->name + ": " + OpenXRUtil::get_action_type_name(action->action_type)); + for (int j = 0; j < action->trackers.size(); j++) { + Tracker * tracker = tracker_owner.get_or_null(action->trackers[j].tracker_rid); + if (tracker) { + print_verbose(" - " + tracker->name); + } + } + } + } + */ + + return true; +} + +void OpenXRAPI::action_set_free(RID p_action_set) { + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL(action_set); + + if (action_set->handle != XR_NULL_HANDLE) { + xrDestroyActionSet(action_set->handle); + } + + action_set_owner.free(p_action_set); +} + +RID OpenXRAPI::get_action_rid(XrAction p_action) { + List<RID> current; + action_owner.get_owned_list(¤t); + for (int i = 0; i < current.size(); i++) { + Action *action = action_owner.get_or_null(current[i]); + if (action && action->handle == p_action) { + return current[i]; + } + } + + return RID(); +} + +RID OpenXRAPI::action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_trackers) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, RID()); + + Action action; + action.name = p_name; + + ActionSet *action_set = action_set_owner.get_or_null(p_action_set); + ERR_FAIL_NULL_V(action_set, RID()); + ERR_FAIL_COND_V(action_set->handle == XR_NULL_HANDLE, RID()); + action.action_set_rid = p_action_set; + + switch (p_action_type) { + case OpenXRAction::OPENXR_ACTION_BOOL: + action.action_type = XR_ACTION_TYPE_BOOLEAN_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_FLOAT: + action.action_type = XR_ACTION_TYPE_FLOAT_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_VECTOR2: + action.action_type = XR_ACTION_TYPE_VECTOR2F_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_POSE: + action.action_type = XR_ACTION_TYPE_POSE_INPUT; + break; + case OpenXRAction::OPENXR_ACTION_HAPTIC: + action.action_type = XR_ACTION_TYPE_VIBRATION_OUTPUT; + break; + default: + ERR_FAIL_V(RID()); + break; + } + + Vector<XrPath> toplevel_paths; + for (int i = 0; i < p_trackers.size(); i++) { + Tracker *tracker = tracker_owner.get_or_null(p_trackers[i]); + if (tracker != nullptr && tracker->toplevel_path != XR_NULL_PATH) { + ActionTracker action_tracker = { + p_trackers[i], // tracker + XR_NULL_HANDLE, // space + false // was_location_valid + }; + action.trackers.push_back(action_tracker); + + toplevel_paths.push_back(tracker->toplevel_path); + } + } + + XrActionCreateInfo action_info = { + XR_TYPE_ACTION_CREATE_INFO, // type + nullptr, // next + "", // actionName + action.action_type, // actionType + uint32_t(toplevel_paths.size()), // countSubactionPaths + toplevel_paths.ptr(), // subactionPaths + "" // localizedActionName + }; + + copy_string_to_char_buffer(p_name, action_info.actionName, XR_MAX_ACTION_NAME_SIZE); + copy_string_to_char_buffer(p_localized_name, action_info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE); + + // print_line("Creating action ", action_info.actionName, action_info.localizedActionName, action_info.countSubactionPaths); + + XrResult result = xrCreateAction(action_set->handle, &action_info, &action.handle); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to create action ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + return action_owner.make_rid(action); +} + +String OpenXRAPI::action_get_name(RID p_action) { + if (p_action.is_null()) { + return String("None"); + } + + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, String()); + + return action->name; +} + +void OpenXRAPI::action_free(RID p_action) { + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL(action); + + if (action->handle != XR_NULL_HANDLE) { + xrDestroyAction(action->handle); + } + + action_owner.free(p_action); +} + +RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) { + List<RID> current; + interaction_profile_owner.get_owned_list(¤t); + for (int i = 0; i < current.size(); i++) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(current[i]); + if (ip && ip->path == p_path) { + return current[i]; + } + } + + return RID(); +} + +XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) { + if (p_interaction_profile.is_null()) { + return XR_NULL_PATH; + } + + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL_V(ip, XR_NULL_PATH); + + return ip->path; +} + +RID OpenXRAPI::interaction_profile_create(const String p_name) { + InteractionProfile new_interaction_profile; + + XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_interaction_profile.path); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]"); + return RID(); + } + + RID existing_ip = get_interaction_profile_rid(new_interaction_profile.path); + if (existing_ip.is_valid()) { + return existing_ip; + } + + new_interaction_profile.name = p_name; + return interaction_profile_owner.make_rid(new_interaction_profile); +} + +String OpenXRAPI::interaction_profile_get_name(RID p_interaction_profile) { + if (p_interaction_profile.is_null()) { + return String("None"); + } + + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL_V(ip, String()); + + return ip->name; +} + +void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL(ip); + + ip->bindings.clear(); +} + +bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL_V(ip, false); + + XrActionSuggestedBinding binding; + + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, false); + + binding.action = action->handle; + + XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &binding.binding); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]"); + return false; + } + + ip->bindings.push_back(binding); + + return true; +} + +bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile) { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL_V(ip, false); + + const XrInteractionProfileSuggestedBinding suggested_bindings = { + XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type + nullptr, // next + ip->path, // interactionProfile + uint32_t(ip->bindings.size()), // countSuggestedBindings + ip->bindings.ptr() // suggestedBindings + }; + + XrResult result = xrSuggestInteractionProfileBindings(instance, &suggested_bindings); + if (result == XR_ERROR_PATH_UNSUPPORTED) { + // this is fine, not all runtimes support all devices. + print_verbose("OpenXR Interaction profile " + ip->name + " is not supported on this runtime"); + } else if (XR_FAILED(result)) { + print_line("OpenXR: failed to suggest bindings for ", ip->name, "! [", get_error_string(result), "]"); + // reporting is enough... + } + + /* For debugging: + print_verbose("Suggested bindings for " + ip->name); + for (int i = 0; i < ip->bindings.size(); i++) { + uint32_t strlen; + char path[XR_MAX_PATH_LENGTH]; + + String action_name = action_get_name(get_action_rid(ip->bindings[i].action)); + + XrResult result = xrPathToString(instance, ip->bindings[i].binding, XR_MAX_PATH_LENGTH, &strlen, path); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to retrieve bindings for ", action_name, "! [", get_error_string(result), "]"); + } + print_verbose(" - " + action_name + " => " + String(path)); + } + */ + + return true; +} + +void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); + ERR_FAIL_NULL(ip); + + ip->bindings.clear(); + + interaction_profile_owner.free(p_interaction_profile); +} + +bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + + if (!running) { + return false; + } + + Vector<XrActiveActionSet> active_sets; + for (int i = 0; i < p_active_sets.size(); i++) { + ActionSet *action_set = action_set_owner.get_or_null(p_active_sets[i]); + if (action_set && action_set->handle != XR_NULL_HANDLE) { + XrActiveActionSet aset; + aset.actionSet = action_set->handle; + aset.subactionPath = XR_NULL_PATH; + active_sets.push_back(aset); + } + } + + ERR_FAIL_COND_V(active_sets.size() == 0, false); + + XrActionsSyncInfo sync_info = { + XR_TYPE_ACTIONS_SYNC_INFO, // type + nullptr, // next + uint32_t(active_sets.size()), // countActiveActionSets + active_sets.ptr() // activeActionSets + }; + + XrResult result = xrSyncActions(session, &sync_info); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]"); + return false; + } + + return true; +} + +bool OpenXRAPI::get_action_bool(RID p_action, RID p_tracker) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, false); + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL_V(tracker, false); + + if (!running) { + return false; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_BOOLEAN_INPUT, false); + + XrActionStateGetInfo get_info = { + XR_TYPE_ACTION_STATE_GET_INFO, // type + nullptr, // next + action->handle, // action + tracker->toplevel_path // subactionPath + }; + + XrActionStateBoolean result_state; + result_state.type = XR_TYPE_ACTION_STATE_BOOLEAN, + result_state.next = nullptr; + XrResult result = xrGetActionStateBoolean(session, &get_info, &result_state); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't get action boolean! [", get_error_string(result), "]"); + return false; + } + + return result_state.isActive && result_state.currentState; +} + +float OpenXRAPI::get_action_float(RID p_action, RID p_tracker) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, 0.0); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, 0.0); + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL_V(tracker, 0.0); + + if (!running) { + return 0.0; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_FLOAT_INPUT, 0.0); + + XrActionStateGetInfo get_info = { + XR_TYPE_ACTION_STATE_GET_INFO, // type + nullptr, // next + action->handle, // action + tracker->toplevel_path // subactionPath + }; + + XrActionStateFloat result_state; + result_state.type = XR_TYPE_ACTION_STATE_FLOAT, + result_state.next = nullptr; + XrResult result = xrGetActionStateFloat(session, &get_info, &result_state); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't get action float! [", get_error_string(result), "]"); + return 0.0; + } + + return result_state.isActive ? result_state.currentState : 0.0; +} + +Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, Vector2()); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, Vector2()); + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL_V(tracker, Vector2()); + + if (!running) { + return Vector2(); + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VECTOR2F_INPUT, Vector2()); + + XrActionStateGetInfo get_info = { + XR_TYPE_ACTION_STATE_GET_INFO, // type + nullptr, // next + action->handle, // action + tracker->toplevel_path // subactionPath + }; + + XrActionStateVector2f result_state; + result_state.type = XR_TYPE_ACTION_STATE_VECTOR2F, + result_state.next = nullptr; + XrResult result = xrGetActionStateVector2f(session, &get_info, &result_state); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't get action vector2! [", get_error_string(result), "]"); + return Vector2(); + } + + return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2(); +} + +XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE); + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL_V(tracker, XRPose::XR_TRACKING_CONFIDENCE_NONE); + + if (!running) { + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_POSE_INPUT, XRPose::XR_TRACKING_CONFIDENCE_NONE); + + // print_verbose("Checking " + action->name + " => " + tracker->name + " (" + itos(tracker->toplevel_path) + ")"); + + uint64_t index = 0xFFFFFFFF; + uint64_t size = uint64_t(action->trackers.size()); + for (uint64_t i = 0; i < size && index == 0xFFFFFFFF; i++) { + if (action->trackers[i].tracker_rid == p_tracker) { + index = i; + } + } + + if (index == 0xFFFFFFFF) { + // couldn't find it? + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + XrTime display_time = get_next_frame_time(); + if (display_time == 0) { + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + if (action->trackers[index].space == XR_NULL_HANDLE) { + // if this is a pose we need to define spaces + + XrActionSpaceCreateInfo action_space_info = { + XR_TYPE_ACTION_SPACE_CREATE_INFO, // type + nullptr, // next + action->handle, // action + tracker->toplevel_path, // subactionPath + { + { 0.0, 0.0, 0.0, 1.0 }, // orientation + { 0.0, 0.0, 0.0 } // position + } // poseInActionSpace + }; + + XrSpace space; + XrResult result = xrCreateActionSpace(session, &action_space_info, &space); + if (XR_FAILED(result)) { + print_line("OpenXR: couldn't create action space! [", get_error_string(result), "]"); + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + action->trackers.ptrw()[index].space = space; + } + + XrSpaceVelocity velocity = { + XR_TYPE_SPACE_VELOCITY, // type + nullptr, // next + 0, // velocityFlags + { 0.0, 0.0, 0.0 }, // linearVelocity + { 0.0, 0.0, 0.0 } // angularVelocity + }; + + XrSpaceLocation location = { + XR_TYPE_SPACE_LOCATION, // type + &velocity, // next + 0, // locationFlags + { + { 0.0, 0.0, 0.0, 0.0 }, // orientation + { 0.0, 0.0, 0.0 } // position + } // pose + }; + + XrResult result = xrLocateSpace(action->trackers[index].space, play_space, display_time, &location); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to locate space! [", get_error_string(result), "]"); + return XRPose::XR_TRACKING_CONFIDENCE_NONE; + } + + XRPose::TrackingConfidence confidence = transform_from_location(location, r_transform); + parse_velocities(velocity, r_linear_velocity, r_angular_velocity); + + return confidence; +} + +bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns) { + ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); + Action *action = action_owner.get_or_null(p_action); + ERR_FAIL_NULL_V(action, false); + Tracker *tracker = tracker_owner.get_or_null(p_tracker); + ERR_FAIL_NULL_V(tracker, false); + + if (!running) { + return false; + } + + ERR_FAIL_COND_V(action->action_type != XR_ACTION_TYPE_VIBRATION_OUTPUT, false); + + XrHapticActionInfo action_info = { + XR_TYPE_HAPTIC_ACTION_INFO, // type + nullptr, // next + action->handle, // action + tracker->toplevel_path // subactionPath + }; + + XrHapticVibration vibration = { + XR_TYPE_HAPTIC_VIBRATION, // type + nullptr, // next + p_duration_ns, // duration + p_frequency, // frequency + p_amplitude, // amplitude + }; + + XrResult result = xrApplyHapticFeedback(session, &action_info, (const XrHapticBaseHeader *)&vibration); + if (XR_FAILED(result)) { + print_line("OpenXR: failed to apply haptic feedback! [", get_error_string(result), "]"); + return false; + } + + return true; +} diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h new file mode 100644 index 0000000000..702f6b9b1d --- /dev/null +++ b/modules/openxr/openxr_api.h @@ -0,0 +1,295 @@ +/*************************************************************************/ +/* openxr_api.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_DRIVER_H +#define OPENXR_DRIVER_H + +#include "core/error/error_macros.h" +#include "core/math/camera_matrix.h" +#include "core/math/transform_3d.h" +#include "core/math/vector2.h" +#include "core/os/memory.h" +#include "core/string/ustring.h" +#include "core/templates/map.h" +#include "core/templates/rid_owner.h" +#include "core/templates/vector.h" +#include "servers/xr/xr_pose.h" + +#include "thirdparty/openxr/src/common/xr_linear.h" +#include <openxr/openxr.h> + +#include "action_map/openxr_action.h" + +#include "extensions/openxr_composition_layer_provider.h" +#include "extensions/openxr_extension_wrapper.h" + +// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initialising structs which ensures zeroing out unspecified members. +// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set. + +// forward declarations, we don't want to include these fully +class OpenXRVulkanExtension; +class OpenXRInterface; + +class OpenXRAPI { +private: + // our singleton + static OpenXRAPI *singleton; + + // linked XR interface + OpenXRInterface *xr_interface = nullptr; + + // layers + uint32_t num_layer_properties = 0; + XrApiLayerProperties *layer_properties = nullptr; + + // extensions + uint32_t num_supported_extensions = 0; + XrExtensionProperties *supported_extensions = nullptr; + Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; + Vector<const char *> enabled_extensions; + + bool ext_hp_mixed_reality_available = false; + bool ext_samsung_odyssey_available = false; + bool ext_vive_cosmos_available = false; + bool ext_vive_focus3_available = false; + bool ext_huawei_controller_available = false; + + // composition layer providers + Vector<OpenXRCompositionLayerProvider *> composition_layer_providers; + + // view configuration + uint32_t num_view_configuration_types = 0; + XrViewConfigurationType *supported_view_configuration_types = nullptr; + + // reference spaces + uint32_t num_reference_spaces = 0; + XrReferenceSpaceType *supported_reference_spaces = nullptr; + + // swapchains (note these are platform dependent) + uint32_t num_swapchain_formats = 0; + int64_t *supported_swapchain_formats = nullptr; + + // configuration + XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; + XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; + XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE; + XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; + + // state + XrInstance instance = XR_NULL_HANDLE; + XrSystemId system_id = 0; + String system_name; + uint32_t vendor_id = 0; + XrSystemTrackingProperties tracking_properties; + XrSession session = XR_NULL_HANDLE; + XrSessionState session_state = XR_SESSION_STATE_UNKNOWN; + bool running = false; + XrFrameState frame_state = { XR_TYPE_FRAME_STATE, NULL, 0, 0, false }; + + OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr; + XrSystemGraphicsProperties graphics_properties; + void *swapchain_graphics_data = nullptr; + uint32_t image_index = 0; + bool image_acquired = false; + + uint32_t view_count = 0; + XrViewConfigurationView *view_configuration_views = nullptr; + XrView *views = nullptr; + XrCompositionLayerProjectionView *projection_views = nullptr; + XrSwapchain swapchain = XR_NULL_HANDLE; + + XrSpace play_space = XR_NULL_HANDLE; + XrSpace view_space = XR_NULL_HANDLE; + bool view_pose_valid = false; + XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; + + bool load_layer_properties(); + bool load_supported_extensions(); + bool is_extension_supported(const char *p_extension) const; + + // instance + bool create_instance(); + bool get_system_info(); + bool load_supported_view_configuration_types(); + bool is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const; + bool load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type); + void destroy_instance(); + + // session + bool create_session(); + bool load_supported_reference_spaces(); + bool is_reference_space_supported(XrReferenceSpaceType p_reference_space); + bool setup_spaces(); + bool load_supported_swapchain_formats(); + bool is_swapchain_format_supported(int64_t p_swapchain_format); + bool create_main_swapchain(); + void destroy_session(); + + // swapchains + bool create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data); + bool acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index); + bool release_image(XrSwapchain p_swapchain); + + // action map + struct Tracker { // Trackers represent tracked physical objects such as controllers, pucks, etc. + String name; // Name for this tracker (i.e. "/user/hand/left") + XrPath toplevel_path; // OpenXR XrPath for this tracker + RID active_profile_rid; // RID of the active profile for this tracker + }; + RID_Owner<Tracker, true> tracker_owner; + RID get_tracker_rid(XrPath p_path); + + struct ActionSet { // Action sets define a set of actions that can be enabled together + String name; // Name for this action set (i.e. "godot_action_set") + bool is_attached; // If true our action set has been attached to the session and can no longer be modified + XrActionSet handle; // OpenXR handle for this action set + }; + RID_Owner<ActionSet, true> action_set_owner; + + struct ActionTracker { // Links and action to a tracker + RID tracker_rid; // RID of the tracker + XrSpace space; // Optional space for pose actions + bool was_location_valid; // If true the last position we obtained was valid + }; + + struct Action { // Actions define the inputs and outputs in OpenXR + RID action_set_rid; // RID of the action set this action belongs to + String name; // Name for this action (i.e. "aim_pose") + XrActionType action_type; // Type of action (bool, float, etc.) + Vector<ActionTracker> trackers; // The trackers this action can be used with + XrAction handle; // OpenXR handle for this action + }; + RID_Owner<Action, true> action_owner; + RID get_action_rid(XrAction p_action); + + struct InteractionProfile { // Interaction profiles define suggested bindings between the physical inputs on controller types and our actions + String name; // Name of the interaction profile (i.e. "/interaction_profiles/valve/index_controller") + XrPath path; // OpenXR path for this profile + Vector<XrActionSuggestedBinding> bindings; // OpenXR action bindings + }; + RID_Owner<InteractionProfile, true> interaction_profile_owner; + RID get_interaction_profile_rid(XrPath p_path); + XrPath get_interaction_profile_path(RID p_interaction_profile); + + // state changes + bool poll_events(); + bool on_state_idle(); + bool on_state_ready(); + bool on_state_synchronized(); + bool on_state_visible(); + bool on_state_focused(); + bool on_state_stopping(); + bool on_state_loss_pending(); + bool on_state_exiting(); + + // convencience + void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len); + +protected: + friend class OpenXRVulkanExtension; + + XrInstance get_instance() const { return instance; }; + XrSystemId get_system_id() const { return system_id; }; + XrSession get_session() const { return session; }; + + // helper method to convert an XrPosef to a Transform3D + Transform3D transform_from_pose(const XrPosef &p_pose); + + // helper method to get a valid Transform3D from an openxr space location + XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform); + XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform); + void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity); + +public: + static bool openxr_is_enabled(bool p_check_run_in_editor = true); + static OpenXRAPI *get_singleton(); + + String get_error_string(XrResult result); + String get_swapchain_format_name(int64_t p_swapchain_format) const; + + void set_xr_interface(OpenXRInterface *p_xr_interface); + void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper); + + bool is_initialized(); + bool is_running(); + bool initialize(const String &p_rendering_driver); + bool initialize_session(); + void finish(); + + XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; }; + bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; }; + + Size2 get_recommended_target_size(); + XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity); + bool get_view_transform(uint32_t p_view, Transform3D &r_transform); + bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix); + bool process(); + + void pre_render(); + bool pre_draw_viewport(RID p_render_target); + void post_draw_viewport(RID p_render_target); + void end_frame(); + + // action map + String get_default_action_map_resource_name(); + + RID tracker_create(const String p_name); + String tracker_get_name(RID p_tracker); + void tracker_check_profile(RID p_tracker, XrSession p_session = XR_NULL_HANDLE); + void tracker_free(RID p_tracker); + + RID action_set_create(const String p_name, const String p_localized_name, const int p_priority); + String action_set_get_name(RID p_action_set); + bool action_set_attach(RID p_action_set); + void action_set_free(RID p_action_set); + + RID action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_trackers); + String action_get_name(RID p_action); + void action_free(RID p_action); + + RID interaction_profile_create(const String p_name); + String interaction_profile_get_name(RID p_interaction_profile); + void interaction_profile_clear_bindings(RID p_interaction_profile); + bool interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path); + bool interaction_profile_suggest_bindings(RID p_interaction_profile); + void interaction_profile_free(RID p_interaction_profile); + + bool sync_action_sets(const Vector<RID> p_active_sets); + bool get_action_bool(RID p_action, RID p_tracker); + float get_action_float(RID p_action, RID p_tracker); + Vector2 get_action_vector2(RID p_action, RID p_tracker); + XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity); + bool trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns); + + OpenXRAPI(); + ~OpenXRAPI(); +}; + +#endif // !OPENXR_DRIVER_H diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp new file mode 100644 index 0000000000..41ce8c019e --- /dev/null +++ b/modules/openxr/openxr_interface.cpp @@ -0,0 +1,771 @@ +/*************************************************************************/ +/* openxr_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_interface.h" + +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "servers/rendering/rendering_server_globals.h" + +void OpenXRInterface::_bind_methods() { + // lifecycle signals + ADD_SIGNAL(MethodInfo("session_begun")); + ADD_SIGNAL(MethodInfo("session_stopping")); + ADD_SIGNAL(MethodInfo("session_focussed")); + ADD_SIGNAL(MethodInfo("session_visible")); + ADD_SIGNAL(MethodInfo("pose_recentered")); +} + +StringName OpenXRInterface::get_name() const { + return StringName("OpenXR"); +}; + +uint32_t OpenXRInterface::get_capabilities() const { + return XRInterface::XR_VR + XRInterface::XR_STEREO; +}; + +PackedStringArray OpenXRInterface::get_suggested_tracker_names() const { + // These are hardcoded in OpenXR, note that they will only be available if added to our action map + + PackedStringArray arr = { + "left_hand", // /user/hand/left is mapped to our defaults + "right_hand", // /user/hand/right is mapped to our defaults + "/user/treadmill" + }; + + return arr; +} + +XRInterface::TrackingStatus OpenXRInterface::get_tracking_status() const { + return tracking_state; +} + +void OpenXRInterface::_load_action_map() { + ERR_FAIL_NULL(openxr_api); + + // This may seem a bit duplicitous to a little bit of background info here. + // OpenXRActionMap (with all its sub resource classes) is a class that allows us to configure and store an action map in. + // This gives the user the ability to edit the action map in a UI and customise the actions. + // OpenXR however requires us to submit an action map and it takes over from that point and we can no longer change it. + // This system does that push and we store the info needed to then work with this action map going forward. + + // Within our openxr device we maintain a number of classes that wrap the relevant OpenXR objects for this. + // Within OpenXRInterface we have a few internal classes that keep track of what we've created. + // This allow us to process the relevant actions each frame. + + // just in case clean up + free_trackers(); + free_interaction_profiles(); + free_action_sets(); + + Ref<OpenXRActionMap> action_map; + if (Engine::get_singleton()->is_editor_hint()) { +#ifdef TOOLS_ENABLED + action_map.instantiate(); + action_map->create_editor_action_sets(); +#endif + } else { + String default_tres_name = openxr_api->get_default_action_map_resource_name(); + + // Check if we can load our default + if (ResourceLoader::exists(default_tres_name)) { + action_map = ResourceLoader::load(default_tres_name); + } + + // Check if we need to create default action set + if (action_map.is_null()) { + action_map.instantiate(); + action_map->create_default_action_sets(); +#ifdef TOOLS_ENABLED + // Save our action sets so our user can + action_map->set_path(default_tres_name, true); + ResourceSaver::save(default_tres_name, action_map); +#endif + } + } + + // process our action map + if (action_map.is_valid()) { + Map<Ref<OpenXRAction>, Action *> xr_actions; + + Array action_sets = action_map->get_action_sets(); + for (int i = 0; i < action_sets.size(); i++) { + // Create our action set + Ref<OpenXRActionSet> xr_action_set = action_sets[i]; + ActionSet *action_set = create_action_set(xr_action_set->get_name(), xr_action_set->get_localized_name(), xr_action_set->get_priority()); + if (!action_set) { + continue; + } + + // Now create our actions for these + Array actions = xr_action_set->get_actions(); + for (int j = 0; j < actions.size(); j++) { + Ref<OpenXRAction> xr_action = actions[j]; + + PackedStringArray toplevel_paths = xr_action->get_toplevel_paths(); + Vector<Tracker *> trackers; + + for (int k = 0; k < toplevel_paths.size(); k++) { + Tracker *tracker = find_tracker(toplevel_paths[k], true); + if (tracker) { + trackers.push_back(tracker); + } + } + + Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers); + if (action) { + // we link our actions back to our trackers so we know which actions to check when we're processing our trackers + for (int t = 0; t < trackers.size(); t++) { + link_action_to_tracker(trackers[t], action); + } + + // add this to our map for creating our interaction profiles + xr_actions[xr_action] = action; + } + } + } + + // now do our suggestions + Array interaction_profiles = action_map->get_interaction_profiles(); + for (int i = 0; i < interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> xr_interaction_profile = interaction_profiles[i]; + + // Note, we can only have one entry per interaction profile so if it already exists we clear it out + RID ip = openxr_api->interaction_profile_create(xr_interaction_profile->get_interaction_profile_path()); + openxr_api->interaction_profile_clear_bindings(ip); + + Array xr_bindings = xr_interaction_profile->get_bindings(); + for (int j = 0; j < xr_bindings.size(); j++) { + Ref<OpenXRIPBinding> xr_binding = xr_bindings[j]; + Ref<OpenXRAction> xr_action = xr_binding->get_action(); + + Action *action = nullptr; + if (xr_actions.has(xr_action)) { + action = xr_actions[xr_action]; + } else { + print_line("Action ", xr_action->get_name(), " isn't part of an action set!"); + continue; + } + + PackedStringArray paths = xr_binding->get_paths(); + for (int k = 0; k < paths.size(); k++) { + openxr_api->interaction_profile_add_binding(ip, action->action_rid, paths[k]); + } + } + + // Now submit our suggestions + openxr_api->interaction_profile_suggest_bindings(ip); + + // And record it in our array so we can clean it up later on + if (interaction_profiles.has(ip)) { + interaction_profiles.push_back(ip); + } + } + } +} + +OpenXRInterface::ActionSet *OpenXRInterface::create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority) { + ERR_FAIL_NULL_V(openxr_api, nullptr); + + // find if it already exists + for (int i = 0; i < action_sets.size(); i++) { + if (action_sets[i]->action_set_name == p_action_set_name) { + // already exists in this set + return nullptr; + } + } + + ActionSet *action_set = memnew(ActionSet); + action_set->action_set_name = p_action_set_name; + action_set->is_active = true; + action_set->action_set_rid = openxr_api->action_set_create(p_action_set_name, p_localized_name, p_priority); + action_sets.push_back(action_set); + + return action_set; +} + +void OpenXRInterface::free_action_sets() { + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < action_sets.size(); i++) { + ActionSet *action_set = action_sets[i]; + + free_actions(action_set); + + openxr_api->action_set_free(action_set->action_set_rid); + + memfree(action_set); + } + action_sets.clear(); +} + +OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<Tracker *> p_trackers) { + ERR_FAIL_NULL_V(openxr_api, nullptr); + + for (int i = 0; i < p_action_set->actions.size(); i++) { + if (p_action_set->actions[i]->action_name == p_action_name) { + // already exists in this set + return nullptr; + } + } + + Vector<RID> tracker_rids; + for (int i = 0; i < p_trackers.size(); i++) { + tracker_rids.push_back(p_trackers[i]->tracker_rid); + } + + Action *action = memnew(Action); + if (p_action_type == OpenXRAction::OPENXR_ACTION_POSE) { + // We can't have dual action names in OpenXR hence we added _pose, + // but default, aim and grip and default pose action names in Godot so rename them on the tracker. + // NOTE need to decide on whether we should keep the naming convention or rename it on Godots side + if (p_action_name == "default_pose") { + action->action_name = "default"; + } else if (p_action_name == "aim_pose") { + action->action_name = "aim"; + } else if (p_action_name == "grip_pose") { + action->action_name = "grip"; + } else { + action->action_name = p_action_name; + } + } else { + action->action_name = p_action_name; + } + + action->action_type = p_action_type; + action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, tracker_rids); + p_action_set->actions.push_back(action); + + return action; +} + +OpenXRInterface::Action *OpenXRInterface::find_action(const String &p_action_name) { + // We just find the first action by this name + + for (int i = 0; i < action_sets.size(); i++) { + for (int j = 0; j < action_sets[i]->actions.size(); j++) { + if (action_sets[i]->actions[j]->action_name == p_action_name) { + return action_sets[i]->actions[j]; + } + } + } + + // not found + return nullptr; +} + +void OpenXRInterface::free_actions(ActionSet *p_action_set) { + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < p_action_set->actions.size(); i++) { + Action *action = p_action_set->actions[i]; + + openxr_api->action_free(action->action_rid); + + memdelete(action); + } + p_action_set->actions.clear(); +} + +OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_name, bool p_create) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, nullptr); + ERR_FAIL_NULL_V(openxr_api, nullptr); + + Tracker *tracker = nullptr; + for (int i = 0; i < trackers.size(); i++) { + tracker = trackers[i]; + if (tracker->tracker_name == p_tracker_name) { + return tracker; + } + } + + if (!p_create) { + return nullptr; + } + + // Create our RID + RID tracker_rid = openxr_api->tracker_create(p_tracker_name); + ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr); + + // create our positional tracker + Ref<XRPositionalTracker> positional_tracker; + positional_tracker.instantiate(); + + // We have standardised some names to make things nicer to the user so lets recognise the toplevel paths related to these. + if (p_tracker_name == "/user/hand/left") { + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name("left_hand"); + positional_tracker->set_tracker_desc("Left hand controller"); + positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT); + } else if (p_tracker_name == "/user/hand/right") { + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name("right_hand"); + positional_tracker->set_tracker_desc("Right hand controller"); + positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT); + } else { + positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); + positional_tracker->set_tracker_name(p_tracker_name); + positional_tracker->set_tracker_desc(p_tracker_name); + } + positional_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); + xr_server->add_tracker(positional_tracker); + + // create a new entry + tracker = memnew(Tracker); + tracker->tracker_name = p_tracker_name; + tracker->tracker_rid = tracker_rid; + tracker->positional_tracker = positional_tracker; + tracker->interaction_profile = RID(); + trackers.push_back(tracker); + + return tracker; +} + +void OpenXRInterface::tracker_profile_changed(RID p_tracker, RID p_interaction_profile) { + Tracker *tracker = nullptr; + for (int i = 0; i < trackers.size() && tracker == nullptr; i++) { + if (trackers[i]->tracker_rid == p_tracker) { + tracker = trackers[i]; + } + } + ERR_FAIL_NULL(tracker); + + tracker->interaction_profile = p_interaction_profile; + + if (p_interaction_profile.is_null()) { + print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + INTERACTION_PROFILE_NONE); + tracker->positional_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); + } else { + String name = openxr_api->interaction_profile_get_name(p_interaction_profile); + print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + name); + tracker->positional_tracker->set_tracker_profile(name); + } +} + +void OpenXRInterface::link_action_to_tracker(Tracker *p_tracker, Action *p_action) { + if (p_tracker->actions.find(p_action) == -1) { + p_tracker->actions.push_back(p_action); + } +} + +void OpenXRInterface::handle_tracker(Tracker *p_tracker) { + ERR_FAIL_NULL(openxr_api); + ERR_FAIL_COND(p_tracker->positional_tracker.is_null()); + + // Note, which actions are actually bound to inputs are handled by our interaction profiles however interaction + // profiles are suggested bindings for controller types we know about. OpenXR runtimes can stray away from these + // and rebind them or even offer bindings to controllers that are not known to us. + + // We don't really have a consistent way to detect whether a controller is active however as long as it is + // unbound it seems to be unavailable, so far unknown controller seem to mimic one of the profiles we've + // supplied. + if (p_tracker->interaction_profile.is_null()) { + return; + } + + // We check all actions that are related to our tracker. + for (int i = 0; i < p_tracker->actions.size(); i++) { + Action *action = p_tracker->actions[i]; + switch (action->action_type) { + case OpenXRAction::OPENXR_ACTION_BOOL: { + bool pressed = openxr_api->get_action_bool(action->action_rid, p_tracker->tracker_rid); + p_tracker->positional_tracker->set_input(action->action_name, Variant(pressed)); + } break; + case OpenXRAction::OPENXR_ACTION_FLOAT: { + real_t value = openxr_api->get_action_float(action->action_rid, p_tracker->tracker_rid); + p_tracker->positional_tracker->set_input(action->action_name, Variant(value)); + } break; + case OpenXRAction::OPENXR_ACTION_VECTOR2: { + Vector2 value = openxr_api->get_action_vector2(action->action_rid, p_tracker->tracker_rid); + p_tracker->positional_tracker->set_input(action->action_name, Variant(value)); + } break; + case OpenXRAction::OPENXR_ACTION_POSE: { + Transform3D transform; + Vector3 linear, angular; + + XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(action->action_rid, p_tracker->tracker_rid, transform, linear, angular); + + if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) { + p_tracker->positional_tracker->set_pose(action->action_name, transform, linear, angular, confidence); + } else { + p_tracker->positional_tracker->invalidate_pose(action->action_name); + } + } break; + default: { + // not yet supported + } break; + } + } +} + +void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) { + ERR_FAIL_NULL(openxr_api); + Action *action = find_action(p_action_name); + ERR_FAIL_NULL(action); + Tracker *tracker = find_tracker(p_tracker_name); + ERR_FAIL_NULL(tracker); + + // TODO OpenXR does not support delay, so we may need to add support for that somehow... + + XrDuration duration = XrDuration(p_duration_sec * 1000000000.0); // seconds -> nanoseconds + + openxr_api->trigger_haptic_pulse(action->action_rid, tracker->tracker_rid, p_frequency, p_amplitude, duration); +} + +void OpenXRInterface::free_trackers() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < trackers.size(); i++) { + Tracker *tracker = trackers[i]; + + openxr_api->tracker_free(tracker->tracker_rid); + xr_server->remove_tracker(tracker->positional_tracker); + tracker->positional_tracker.unref(); + + memdelete(tracker); + } + trackers.clear(); +} + +void OpenXRInterface::free_interaction_profiles() { + ERR_FAIL_NULL(openxr_api); + + for (int i = 0; i < interaction_profiles.size(); i++) { + openxr_api->interaction_profile_free(interaction_profiles[i]); + } + interaction_profiles.clear(); +} + +bool OpenXRInterface::initialize_on_startup() const { + if (openxr_api == nullptr) { + return false; + } else if (!openxr_api->is_initialized()) { + return false; + } else { + return true; + } +} + +bool OpenXRInterface::is_initialized() const { + return initialized; +}; + +bool OpenXRInterface::initialize() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, false); + + if (openxr_api == nullptr) { + return false; + } else if (!openxr_api->is_initialized()) { + return false; + } else if (initialized) { + return true; + } + + // load up our action sets before setting up our session, note that our profiles are suggestions, OpenXR takes ownership of (re)binding + _load_action_map(); + + if (!openxr_api->initialize_session()) { + return false; + } + + // we must create a tracker for our head + head.instantiate(); + head->set_tracker_type(XRServer::TRACKER_HEAD); + head->set_tracker_name("head"); + head->set_tracker_desc("Players head"); + xr_server->add_tracker(head); + + // attach action sets + for (int i = 0; i < action_sets.size(); i++) { + openxr_api->action_set_attach(action_sets[i]->action_set_rid); + } + + // make this our primary interface + xr_server->set_primary_interface(this); + + initialized = true; + + return initialized; +} + +void OpenXRInterface::uninitialize() { + // Our OpenXR driver will clean itself up properly when Godot exits, so we just do some basic stuff here + + // end the session if we need to? + + // cleanup stuff + free_trackers(); + free_interaction_profiles(); + free_action_sets(); + + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + if (head.is_valid()) { + xr_server->remove_tracker(head); + head.unref(); + } + } + + initialized = false; +} + +bool OpenXRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) { + return false; +} + +XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const { + return XRInterface::XR_PLAY_AREA_UNKNOWN; +} + +bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) { + return false; +} + +Size2 OpenXRInterface::get_render_target_size() { + if (openxr_api == nullptr) { + return Size2(); + } else { + return openxr_api->get_recommended_target_size(); + } +} + +uint32_t OpenXRInterface::get_view_count() { + // TODO set this based on our configuration + return 2; +} + +void OpenXRInterface::_set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye) { + p_transform = Transform3D(); + + // if we're not tracking, don't put our head on the floor... + p_transform.origin.y = 1.5 * p_world_scale; + + // overkill but.. + if (p_eye == 1) { + p_transform.origin.x = 0.03 * p_world_scale; + } else if (p_eye == 2) { + p_transform.origin.x = -0.03 * p_world_scale; + } +} + +Transform3D OpenXRInterface::get_camera_transform() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, Transform3D()); + + Transform3D hmd_transform; + double world_scale = xr_server->get_world_scale(); + + // head_transform should be updated in process + + hmd_transform.basis = head_transform.basis; + hmd_transform.origin = head_transform.origin * world_scale; + + return hmd_transform; +} + +Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, Transform3D()); + + Transform3D t; + if (openxr_api && openxr_api->get_view_transform(p_view, t)) { + // update our cached value if we have a valid transform + transform_for_view[p_view] = t; + } else { + // reuse cached value + t = transform_for_view[p_view]; + } + + // Apply our world scale + double world_scale = xr_server->get_world_scale(); + t.origin *= world_scale; + + return p_cam_transform * xr_server->get_reference_frame() * t; +} + +CameraMatrix OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) { + CameraMatrix cm; + + if (openxr_api) { + if (openxr_api->get_view_projection(p_view, p_z_near, p_z_far, cm)) { + return cm; + } + } + + // Failed to get from our OpenXR device? Default to some sort of sensible camera matrix.. + cm.set_for_hmd(p_view + 1, 1.0, 6.0, 14.5, 4.0, 1.5, p_z_near, p_z_far); + + return cm; +} + +void OpenXRInterface::process() { + if (openxr_api) { + // do our normal process + if (openxr_api->process()) { + Transform3D t; + Vector3 linear_velocity; + Vector3 angular_velocity; + XRPose::TrackingConfidence confidence = openxr_api->get_head_center(t, linear_velocity, angular_velocity); + if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) { + // Only update our transform if we have one to update it with + // note that poses are stored without world scale and reference frame applied! + head_transform = t; + head_linear_velocity = linear_velocity; + head_angular_velocity = angular_velocity; + } + } + + // handle our action sets.... + Vector<RID> active_sets; + for (int i = 0; i < action_sets.size(); i++) { + if (action_sets[i]->is_active) { + active_sets.push_back(action_sets[i]->action_set_rid); + } + } + + if (openxr_api->sync_action_sets(active_sets)) { + for (int i = 0; i < trackers.size(); i++) { + handle_tracker(trackers[i]); + } + } + } + + if (head.is_valid()) { + // TODO figure out how to get our velocities + + head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity); + + // TODO set confidence on pose once we support tracking this.. + } +} + +void OpenXRInterface::pre_render() { + if (openxr_api) { + openxr_api->pre_render(); + } +} + +bool OpenXRInterface::pre_draw_viewport(RID p_render_target) { + if (openxr_api) { + return openxr_api->pre_draw_viewport(p_render_target); + } else { + // don't render + return false; + } +} + +Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { + Vector<BlitToScreen> blit_to_screen; + + // If separate HMD we should output one eye to screen + if (p_screen_rect != Rect2()) { + BlitToScreen blit; + + blit.render_target = p_render_target; + blit.multi_view.use_layer = true; + blit.multi_view.layer = 0; + blit.lens_distortion.apply = false; + + Size2 render_size = get_render_target_size(); + Rect2 dst_rect = p_screen_rect; + float new_height = dst_rect.size.x * (render_size.y / render_size.x); + if (new_height > dst_rect.size.y) { + dst_rect.position.y = (0.5 * dst_rect.size.y) - (0.5 * new_height); + dst_rect.size.y = new_height; + } else { + float new_width = dst_rect.size.y * (render_size.x / render_size.y); + + dst_rect.position.x = (0.5 * dst_rect.size.x) - (0.5 * new_width); + dst_rect.size.x = new_width; + } + + blit.dst_rect = dst_rect; + blit_to_screen.push_back(blit); + } + + if (openxr_api) { + openxr_api->post_draw_viewport(p_render_target); + } + + return blit_to_screen; +} + +void OpenXRInterface::end_frame() { + if (openxr_api) { + openxr_api->end_frame(); + } +} + +void OpenXRInterface::on_state_ready() { + emit_signal(SNAME("session_begun")); +} + +void OpenXRInterface::on_state_visible() { + emit_signal(SNAME("session_visible")); +} + +void OpenXRInterface::on_state_focused() { + emit_signal(SNAME("session_focussed")); +} + +void OpenXRInterface::on_state_stopping() { + emit_signal(SNAME("session_stopping")); +} + +void OpenXRInterface::on_pose_recentered() { + emit_signal(SNAME("pose_recentered")); +} + +OpenXRInterface::OpenXRInterface() { + openxr_api = OpenXRAPI::get_singleton(); + if (openxr_api) { + openxr_api->set_xr_interface(this); + } + + // while we don't have head tracking, don't put the headset on the floor... + _set_default_pos(head_transform, 1.0, 0); + _set_default_pos(transform_for_view[0], 1.0, 1); + _set_default_pos(transform_for_view[1], 1.0, 2); +} + +OpenXRInterface::~OpenXRInterface() { + if (is_initialized()) { + uninitialize(); + } + + if (openxr_api) { + openxr_api->set_xr_interface(nullptr); + openxr_api = nullptr; + } +} diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h new file mode 100644 index 0000000000..a223acfed0 --- /dev/null +++ b/modules/openxr/openxr_interface.h @@ -0,0 +1,143 @@ +/*************************************************************************/ +/* openxr_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 OPENXR_INTERFACE_H +#define OPENXR_INTERFACE_H + +#include "servers/xr/xr_interface.h" +#include "servers/xr/xr_positional_tracker.h" + +#include "action_map/openxr_action_map.h" +#include "openxr_api.h" + +// declare some default strings +#define INTERACTION_PROFILE_NONE "/interaction_profiles/none" + +class OpenXRInterface : public XRInterface { + GDCLASS(OpenXRInterface, XRInterface); + +private: + OpenXRAPI *openxr_api = nullptr; + bool initialized = false; + XRInterface::TrackingStatus tracking_state; + + // At a minimum we need a tracker for our head + Ref<XRPositionalTracker> head; + Transform3D head_transform; + Vector3 head_linear_velocity; + Vector3 head_angular_velocity; + Transform3D transform_for_view[2]; // We currently assume 2, but could be 4 for VARJO which we do not support yet + + void _load_action_map(); + + struct Action { // An action we've registered with OpenXR + String action_name; // Name of our action as presented to Godot (can be altered from the action map) + OpenXRAction::ActionType action_type; // The action type of this action + RID action_rid; // RID of the action registered with our OpenXR API + }; + struct ActionSet { // An action set we've registered with OpenXR + String action_set_name; // Name of our action set + bool is_active; // If true this action set is active and we will sync it + Vector<Action *> actions; // List of actions in this action set + RID action_set_rid; // RID of the action registered with our OpenXR API + }; + struct Tracker { // A tracker we've registered with OpenXR + String tracker_name; // Name of our tracker (can be altered from the action map) + Vector<Action *> actions; // Actions related to this tracker + Ref<XRPositionalTracker> positional_tracker; // Our positional tracker object that holds our tracker state + RID tracker_rid; // RID of the tracker registered with our OpenXR API + RID interaction_profile; // RID of the interaction profile bound to this tracker (can be null) + }; + + Vector<ActionSet *> action_sets; + Vector<RID> interaction_profiles; + Vector<Tracker *> trackers; + + ActionSet *create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority); + void free_action_sets(); + + Action *create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<Tracker *> p_trackers); + Action *find_action(const String &p_action_name); + void free_actions(ActionSet *p_action_set); + + Tracker *find_tracker(const String &p_tracker_name, bool p_create = false); + void link_action_to_tracker(Tracker *p_tracker, Action *p_action); + void handle_tracker(Tracker *p_tracker); + void free_trackers(); + + void free_interaction_profiles(); + + void _set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye); + +protected: + static void _bind_methods(); + +public: + virtual StringName get_name() const override; + virtual uint32_t get_capabilities() const override; + + virtual PackedStringArray get_suggested_tracker_names() const override; + virtual TrackingStatus get_tracking_status() const override; + + bool initialize_on_startup() const; + virtual bool is_initialized() const override; + virtual bool initialize() override; + virtual void uninitialize() override; + + virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0) override; + + virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override; + virtual XRInterface::PlayAreaMode get_play_area_mode() const override; + virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override; + + virtual Size2 get_render_target_size() override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + 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, double p_aspect, double p_z_near, double p_z_far) override; + + virtual void process() override; + virtual void pre_render() override; + bool pre_draw_viewport(RID p_render_target) override; + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; + virtual void end_frame() override; + + void on_state_ready(); + void on_state_visible(); + void on_state_focused(); + void on_state_stopping(); + void on_pose_recentered(); + void tracker_profile_changed(RID p_tracker, RID p_interaction_profile); + + OpenXRInterface(); + ~OpenXRInterface(); +}; + +#endif // !OPENXR_INTERFACE_H diff --git a/modules/openxr/openxr_util.cpp b/modules/openxr/openxr_util.cpp new file mode 100644 index 0000000000..230b10c5f1 --- /dev/null +++ b/modules/openxr/openxr_util.cpp @@ -0,0 +1,305 @@ +/*************************************************************************/ +/* openxr_util.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "openxr_util.h" + +#define ENUM_TO_STRING_CASE(e) \ + case e: { \ + return String(#e); \ + } break; + +// TODO see if we can generate this code further using the xml file with meta data supplied by OpenXR + +String OpenXRUtil::get_view_configuration_name(XrViewConfigurationType p_view_configuration) { + switch (p_view_configuration) { + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT) + ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM) + default: { + return String("View Configuration ") + String::num_int64(int64_t(p_view_configuration)); + } break; + } +} + +String OpenXRUtil::get_reference_space_name(XrReferenceSpaceType p_reference_space) { + switch (p_reference_space) { + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_VIEW) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_LOCAL) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_STAGE) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO) + ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_MAX_ENUM) + default: { + return String("Reference space ") + String::num_int64(int64_t(p_reference_space)); + } break; + } +} + +String OpenXRUtil::get_structure_type_name(XrStructureType p_structure_type) { + switch (p_structure_type) { + ENUM_TO_STRING_CASE(XR_TYPE_UNKNOWN) + ENUM_TO_STRING_CASE(XR_TYPE_API_LAYER_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_EXTENSION_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_GET_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_LOCATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_BEGIN_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_STATE) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_END_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_HAPTIC_VIBRATION) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_BUFFER) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_BOOLEAN) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_FLOAT) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_VECTOR2F) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_POSE) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_SET_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_WAIT_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PROJECTION) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_QUAD) + ENUM_TO_STRING_CASE(XR_TYPE_REFERENCE_SPACE_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_SPACE_CREATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_VIEW) + ENUM_TO_STRING_CASE(XR_TYPE_SPACE_LOCATION) + ENUM_TO_STRING_CASE(XR_TYPE_SPACE_VELOCITY) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_STATE) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) + ENUM_TO_STRING_CASE(XR_TYPE_FRAME_BEGIN_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_EVENTS_LOST) + ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) + ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_STATE) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_GET_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_HAPTIC_ACTION_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_ACTIONS_SYNC_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_LABEL_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_VISIBILITY_MASK_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINT_LOCATIONS_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINT_VELOCITIES_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) + ENUM_TO_STRING_CASE(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) + ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) + ENUM_TO_STRING_CASE(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBJECTS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_PLANES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESHES_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_BUFFERS_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) + ENUM_TO_STRING_CASE(XR_TYPE_VIVE_TRACKER_PATHS_HTCX) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_MESH_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_SCALE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_AIM_STATE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) + ENUM_TO_STRING_CASE(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) + ENUM_TO_STRING_CASE(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_STYLE_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) + ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) + ENUM_TO_STRING_CASE(XR_TYPE_BINDING_MODIFICATIONS_KHR) + ENUM_TO_STRING_CASE(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) + ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) + ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) + ENUM_TO_STRING_CASE(XR_STRUCTURE_TYPE_MAX_ENUM) + default: { + return String("Structure type ") + String::num_int64(int64_t(p_structure_type)); + } break; + } +} + +String OpenXRUtil::get_session_state_name(XrSessionState p_session_state) { + switch (p_session_state) { + ENUM_TO_STRING_CASE(XR_SESSION_STATE_UNKNOWN) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_IDLE) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_READY) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_SYNCHRONIZED) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_VISIBLE) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_FOCUSED) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_STOPPING) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_LOSS_PENDING) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_EXITING) + ENUM_TO_STRING_CASE(XR_SESSION_STATE_MAX_ENUM) + default: { + return String("Session state ") + String::num_int64(int64_t(p_session_state)); + } break; + } +} + +String OpenXRUtil::get_action_type_name(XrActionType p_action_type) { + switch (p_action_type) { + ENUM_TO_STRING_CASE(XR_ACTION_TYPE_BOOLEAN_INPUT) + ENUM_TO_STRING_CASE(XR_ACTION_TYPE_FLOAT_INPUT) + ENUM_TO_STRING_CASE(XR_ACTION_TYPE_VECTOR2F_INPUT) + ENUM_TO_STRING_CASE(XR_ACTION_TYPE_POSE_INPUT) + ENUM_TO_STRING_CASE(XR_ACTION_TYPE_VIBRATION_OUTPUT) + ENUM_TO_STRING_CASE(XR_ACTION_TYPE_MAX_ENUM) + default: { + return String("Action type ") + String::num_int64(int64_t(p_action_type)); + } break; + } +} + +String OpenXRUtil::make_xr_version_string(XrVersion p_version) { + String version; + + version += String::num_int64(XR_VERSION_MAJOR(p_version)); + version += String("."); + version += String::num_int64(XR_VERSION_MINOR(p_version)); + version += String("."); + version += String::num_int64(XR_VERSION_PATCH(p_version)); + + return version; +} diff --git a/modules/gdnative/nativescript/api_generator.h b/modules/openxr/openxr_util.h index 611abb2a2d..4371b74d2f 100644 --- a/modules/gdnative/nativescript/api_generator.h +++ b/modules/openxr/openxr_util.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* api_generator.h */ +/* openxr_util.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). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,13 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef API_GENERATOR_H -#define API_GENERATOR_H +#ifndef OPENXR_UTIL_H +#define OPENXR_UTIL_H #include "core/string/ustring.h" -#include "core/typedefs.h" +#include <openxr/openxr.h> -Error generate_c_api(const String &p_path); -Error generate_c_builtin_api(const String &p_path); +class OpenXRUtil { +public: + static String get_view_configuration_name(XrViewConfigurationType p_view_configuration); + static String get_reference_space_name(XrReferenceSpaceType p_reference_space); + static String get_structure_type_name(XrStructureType p_structure_type); + static String get_session_state_name(XrSessionState p_session_state); + static String get_action_type_name(XrActionType p_action_type); + static String make_xr_version_string(XrVersion p_version); +}; -#endif // API_GENERATOR_H +#endif // !OPENXR_UTIL_H diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp new file mode 100644 index 0000000000..c765f169dc --- /dev/null +++ b/modules/openxr/register_types.cpp @@ -0,0 +1,130 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "main/main.h" + +#include "openxr_interface.h" + +#include "action_map/openxr_action.h" +#include "action_map/openxr_action_map.h" +#include "action_map/openxr_action_set.h" +#include "action_map/openxr_interaction_profile.h" + +#ifdef TOOLS_ENABLED + +#include "editor/editor_node.h" +#include "editor/openxr_editor_plugin.h" + +static void _editor_init() { + if (OpenXRAPI::openxr_is_enabled(false)) { + // Only add our OpenXR action map editor if OpenXR is enabled for our project + + OpenXREditorPlugin *openxr_plugin = memnew(OpenXREditorPlugin()); + EditorNode::get_singleton()->add_editor_plugin(openxr_plugin); + } +} + +#endif + +static OpenXRAPI *openxr_api = nullptr; +static Ref<OpenXRInterface> openxr_interface; + +void initialize_openxr_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon. + + if (OpenXRAPI::openxr_is_enabled()) { + openxr_api = memnew(OpenXRAPI); + ERR_FAIL_NULL(openxr_api); + + if (!openxr_api->initialize(Main::get_rendering_driver_name())) { + memdelete(openxr_api); + openxr_api = nullptr; + return; + } + } + } + + if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { + GDREGISTER_CLASS(OpenXRInterface); + + GDREGISTER_CLASS(OpenXRAction); + GDREGISTER_CLASS(OpenXRActionSet); + GDREGISTER_CLASS(OpenXRActionMap); + GDREGISTER_CLASS(OpenXRIPBinding); + GDREGISTER_CLASS(OpenXRInteractionProfile); + + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + openxr_interface.instantiate(); + xr_server->add_interface(openxr_interface); + + if (openxr_interface->initialize_on_startup()) { + openxr_interface->initialize(); + } + } + +#ifdef TOOLS_ENABLED + EditorNode::add_init_callback(_editor_init); +#endif + } +} + +void uninitialize_openxr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + if (openxr_interface.is_valid()) { + // uninitialize just in case + if (openxr_interface->is_initialized()) { + openxr_interface->uninitialize(); + } + + // unregister our interface from the XR server + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + if (xr_server->get_primary_interface() == openxr_interface) { + xr_server->set_primary_interface(Ref<XRInterface>()); + } + xr_server->remove_interface(openxr_interface); + } + + // and release + openxr_interface.unref(); + } + + if (openxr_api) { + openxr_api->finish(); + memdelete(openxr_api); + openxr_api = nullptr; + } +} diff --git a/modules/bullet/register_types.h b/modules/openxr/register_types.h index e405996705..1b3d98422d 100644 --- a/modules/bullet/register_types.h +++ b/modules/openxr/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,13 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REGISTER_BULLET_TYPES_H -#define REGISTER_BULLET_TYPES_H +#ifndef OPENXR_REGISTER_TYPES_H +#define OPENXR_REGISTER_TYPES_H -/** - @author AndreaCatania -*/ +#define MODULE_OPENXR_HAS_PREREGISTER -void register_bullet_types(); -void unregister_bullet_types(); -#endif +#include "modules/register_module_types.h" + +void initialize_openxr_module(ModuleInitializationLevel p_level); +void uninitialize_openxr_module(ModuleInitializationLevel p_level); + +#endif // OPENXR_REGISTER_TYPES_H diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub deleted file mode 100644 index 36052cffed..0000000000 --- a/modules/pvr/SCsub +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_pvr = env_modules.Clone() - -# Thirdparty source files - -thirdparty_obj = [] - -# Not unbundled so far since not widespread as shared library -thirdparty_dir = "#thirdparty/pvrtccompressor/" -thirdparty_sources = [ - "BitScale.cpp", - "MortonTable.cpp", - "PvrTcDecoder.cpp", - "PvrTcEncoder.cpp", - "PvrTcPacket.cpp", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env_pvr.Prepend(CPPPATH=[thirdparty_dir]) - -env_thirdparty = env_pvr.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_pvr.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/pvr/config.py b/modules/pvr/config.py deleted file mode 100644 index d22f9454ed..0000000000 --- a/modules/pvr/config.py +++ /dev/null @@ -1,6 +0,0 @@ -def can_build(env, platform): - return True - - -def configure(env): - pass diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp deleted file mode 100644 index 980cac17d3..0000000000 --- a/modules/pvr/image_compress_pvrtc.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************/ -/* image_compress_pvrtc.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_pvrtc.h" - -#include "core/io/image.h" -#include "core/object/ref_counted.h" - -#include <PvrTcEncoder.h> -#include <RgbaBitmap.h> - -static void _compress_pvrtc1_4bpp(Image *p_img) { - Ref<Image> img = p_img->duplicate(); - - bool make_mipmaps = false; - 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) { - img->generate_mipmaps(); - } - - bool use_alpha = img->detect_alpha(); - - Ref<Image> new_img; - 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(); - { - uint8_t *wr = data.ptrw(); - const uint8_t *r = img->get_data().ptr(); - - for (int i = 0; i <= new_img->get_mipmap_count(); i++) { - int ofs, size, w, h; - img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::RgbaBitmap bm(w, h); - void *dst = (void *)bm.GetData(); - 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. - SWAP(dp[j].r, dp[j].b); - } - new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm); - } - } - - p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data); -} - -void _register_pvrtc_compress_func() { - Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp; -} diff --git a/modules/pvr/image_compress_pvrtc.h b/modules/pvr/image_compress_pvrtc.h deleted file mode 100644 index 985076ce4d..0000000000 --- a/modules/pvr/image_compress_pvrtc.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************/ -/* image_compress_pvrtc.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_PVRTC_H -#define IMAGE_COMPRESS_PVRTC_H - -void _register_pvrtc_compress_func(); - -#endif // IMAGE_COMPRESS_PVRTC_H diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp deleted file mode 100644 index ef72087d25..0000000000 --- a/modules/pvr/register_types.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "image_compress_pvrtc.h" -#include "texture_loader_pvr.h" - -static Ref<ResourceFormatPVR> resource_loader_pvr; - -void register_pvr_types() { - resource_loader_pvr.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_pvr); - - _register_pvrtc_compress_func(); -} - -void unregister_pvr_types() { - ResourceLoader::remove_resource_format_loader(resource_loader_pvr); - resource_loader_pvr.unref(); -} diff --git a/modules/pvr/register_types.h b/modules/pvr/register_types.h deleted file mode 100644 index 74fcfe2ce4..0000000000 --- a/modules/pvr/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef PVR_REGISTER_TYPES_H -#define PVR_REGISTER_TYPES_H - -void register_pvr_types(); -void unregister_pvr_types(); - -#endif // PVR_REGISTER_TYPES_H diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp deleted file mode 100644 index ffa900ef99..0000000000 --- a/modules/pvr/texture_loader_pvr.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/*************************************************************************/ -/* texture_loader_pvr.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_pvr.h" - -#include "core/io/file_access.h" - -static void _pvrtc_decompress(Image *p_img); - -enum PVRFLags { - PVR_HAS_MIPMAPS = 0x00000100, - PVR_TWIDDLED = 0x00000200, - PVR_NORMAL_MAP = 0x00000400, - PVR_BORDER = 0x00000800, - PVR_CUBE_MAP = 0x00001000, - PVR_FALSE_MIPMAPS = 0x00002000, - PVR_VOLUME_TEXTURES = 0x00004000, - PVR_HAS_ALPHA = 0x00008000, - PVR_VFLIP = 0x00010000 -}; - -RES ResourceFormatPVR::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 faref(f); - - ERR_FAIL_COND_V(err, RES()); - - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - - uint32_t hsize = f->get_32(); - - ERR_FAIL_COND_V(hsize != 52, RES()); - uint32_t height = f->get_32(); - uint32_t width = f->get_32(); - uint32_t mipmaps = f->get_32(); - uint32_t flags = f->get_32(); - uint32_t surfsize = f->get_32(); - f->seek(f->get_position() + 20); // bpp, rmask, gmask, bmask, amask - uint8_t pvrid[5] = { 0, 0, 0, 0, 0 }; - f->get_buffer(pvrid, 4); - ERR_FAIL_COND_V(String((char *)pvrid) != "PVR!", RES()); - f->get_32(); // surfcount - - /* - print_line("height: "+itos(height)); - print_line("width: "+itos(width)); - print_line("mipmaps: "+itos(mipmaps)); - print_line("flags: "+itos(flags)); - print_line("surfsize: "+itos(surfsize)); - print_line("bpp: "+itos(bpp)); - print_line("rmask: "+itos(rmask)); - print_line("gmask: "+itos(gmask)); - print_line("bmask: "+itos(bmask)); - print_line("amask: "+itos(amask)); - print_line("surfcount: "+itos(surfcount)); - */ - - Vector<uint8_t> data; - data.resize(surfsize); - - ERR_FAIL_COND_V(data.size() == 0, RES()); - - uint8_t *w = data.ptrw(); - f->get_buffer(&w[0], surfsize); - err = f->get_error(); - ERR_FAIL_COND_V(err != OK, RES()); - - Image::Format format = Image::FORMAT_MAX; - - switch (flags & 0xFF) { - case 0x18: - case 0xC: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2; - break; - case 0x19: - case 0xD: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4; - break; - case 0x16: - format = Image::FORMAT_L8; - break; - case 0x17: - format = Image::FORMAT_LA8; - break; - case 0x20: - case 0x80: - case 0x81: - format = Image::FORMAT_DXT1; - break; - case 0x21: - case 0x22: - case 0x82: - case 0x83: - format = Image::FORMAT_DXT3; - break; - case 0x23: - case 0x24: - case 0x84: - case 0x85: - format = Image::FORMAT_DXT5; - break; - case 0x4: - case 0x15: - format = Image::FORMAT_RGB8; - break; - case 0x5: - case 0x12: - format = Image::FORMAT_RGBA8; - break; - case 0x36: - format = Image::FORMAT_ETC; - break; - default: - ERR_FAIL_V_MSG(RES(), "Unsupported format in PVR texture: " + itos(flags & 0xFF) + "."); - } - - Ref<Image> image = memnew(Image(width, height, mipmaps, format, data)); - ERR_FAIL_COND_V(image->is_empty(), RES()); - - Ref<ImageTexture> texture = memnew(ImageTexture); - texture->create_from_image(image); - - if (r_error) { - *r_error = OK; - } - - return texture; -} - -void ResourceFormatPVR::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("pvr"); -} - -bool ResourceFormatPVR::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Texture2D"); -} - -String ResourceFormatPVR::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "pvr") { - return "Texture2D"; - } - return ""; -} - -ResourceFormatPVR::ResourceFormatPVR() { - Image::_image_decompress_pvrtc = _pvrtc_decompress; -} - -///////////////////////////////////////////////////////// - -//PVRTC decompressor, Based on PVRTC decompressor by IMGTEC. - -///////////////////////////////////////////////////////// - -#define PT_INDEX 2 -#define BLK_Y_SIZE 4 -#define BLK_X_MAX 8 -#define BLK_X_2BPP 8 -#define BLK_X_4BPP 4 - -#define WRAP_COORD(Val, Size) ((Val) & ((Size)-1)) - -/* - Define an expression to either wrap or clamp large or small vals to the - legal coordinate range -*/ -#define LIMIT_COORD(Val, Size, p_tiled) \ - ((p_tiled) ? WRAP_COORD((Val), (Size)) : CLAMP((Val), 0, (Size)-1)) - -struct PVRTCBlock { - //blocks are 64 bits - uint32_t data[2] = {}; -}; - -_FORCE_INLINE_ bool is_po2(uint32_t p_input) { - if (p_input == 0) { - return false; - } - uint32_t minus1 = p_input - 1; - return ((p_input | minus1) == (p_input ^ minus1)) ? true : false; -} - -static void unpack_5554(const PVRTCBlock *p_block, int p_ab_colors[2][4]) { - uint32_t raw_bits[2]; - raw_bits[0] = p_block->data[1] & (0xFFFE); - raw_bits[1] = p_block->data[1] >> 16; - - for (int i = 0; i < 2; i++) { - if (raw_bits[i] & (1 << 15)) { - p_ab_colors[i][0] = (raw_bits[i] >> 10) & 0x1F; - p_ab_colors[i][1] = (raw_bits[i] >> 5) & 0x1F; - p_ab_colors[i][2] = raw_bits[i] & 0x1F; - if (i == 0) { - p_ab_colors[0][2] |= p_ab_colors[0][2] >> 4; - } - p_ab_colors[i][3] = 0xF; - } else { - p_ab_colors[i][0] = (raw_bits[i] >> (8 - 1)) & 0x1E; - p_ab_colors[i][1] = (raw_bits[i] >> (4 - 1)) & 0x1E; - - p_ab_colors[i][0] |= p_ab_colors[i][0] >> 4; - p_ab_colors[i][1] |= p_ab_colors[i][1] >> 4; - - p_ab_colors[i][2] = (raw_bits[i] & 0xF) << 1; - - if (i == 0) { - p_ab_colors[0][2] |= p_ab_colors[0][2] >> 3; - } else { - p_ab_colors[0][2] |= p_ab_colors[0][2] >> 4; - } - - p_ab_colors[i][3] = (raw_bits[i] >> 11) & 0xE; - } - } -} - -static void unpack_modulations(const PVRTCBlock *p_block, const int p_2bit, int p_modulation[8][16], int p_modulation_modes[8][16], int p_x, int p_y) { - int block_mod_mode = p_block->data[1] & 1; - uint32_t modulation_bits = p_block->data[0]; - - if (p_2bit && block_mod_mode) { - for (int y = 0; y < BLK_Y_SIZE; y++) { - for (int x = 0; x < BLK_X_2BPP; x++) { - p_modulation_modes[y + p_y][x + p_x] = block_mod_mode; - - if (((x ^ y) & 1) == 0) { - p_modulation[y + p_y][x + p_x] = modulation_bits & 3; - modulation_bits >>= 2; - } - } - } - - } else if (p_2bit) { - for (int y = 0; y < BLK_Y_SIZE; y++) { - for (int x = 0; x < BLK_X_2BPP; x++) { - p_modulation_modes[y + p_y][x + p_x] = block_mod_mode; - - if (modulation_bits & 1) { - p_modulation[y + p_y][x + p_x] = 0x3; - } else { - p_modulation[y + p_y][x + p_x] = 0x0; - } - - modulation_bits >>= 1; - } - } - } else { - for (int y = 0; y < BLK_Y_SIZE; y++) { - for (int x = 0; x < BLK_X_4BPP; x++) { - p_modulation_modes[y + p_y][x + p_x] = block_mod_mode; - p_modulation[y + p_y][x + p_x] = modulation_bits & 3; - modulation_bits >>= 2; - } - } - } - - ERR_FAIL_COND(modulation_bits != 0); -} - -static void interpolate_colors(const int p_colorp[4], const int p_colorq[4], const int p_colorr[4], const int p_colors[4], bool p_2bit, const int x, const int y, int r_result[4]) { - int u, v, uscale; - int k; - - int tmp1, tmp2; - - int P[4], Q[4], R[4], S[4]; - - for (k = 0; k < 4; k++) { - P[k] = p_colorp[k]; - Q[k] = p_colorq[k]; - R[k] = p_colorr[k]; - S[k] = p_colors[k]; - } - - v = (y & 0x3) | ((~y & 0x2) << 1); - - if (p_2bit) { - u = (x & 0x7) | ((~x & 0x4) << 1); - } else { - u = (x & 0x3) | ((~x & 0x2) << 1); - } - - v = v - BLK_Y_SIZE / 2; - - if (p_2bit) { - u = u - BLK_X_2BPP / 2; - uscale = 8; - } else { - u = u - BLK_X_4BPP / 2; - uscale = 4; - } - - for (k = 0; k < 4; k++) { - tmp1 = P[k] * uscale + u * (Q[k] - P[k]); - tmp2 = R[k] * uscale + u * (S[k] - R[k]); - - tmp1 = tmp1 * 4 + v * (tmp2 - tmp1); - - r_result[k] = tmp1; - } - - if (p_2bit) { - for (k = 0; k < 3; k++) { - r_result[k] >>= 2; - } - - r_result[3] >>= 1; - } else { - for (k = 0; k < 3; k++) { - r_result[k] >>= 1; - } - } - - for (k = 0; k < 4; k++) { - ERR_FAIL_COND(r_result[k] >= 256); - } - - for (k = 0; k < 3; k++) { - r_result[k] += r_result[k] >> 5; - } - - r_result[3] += r_result[3] >> 4; - - for (k = 0; k < 4; k++) { - ERR_FAIL_COND(r_result[k] >= 256); - } -} - -static void get_modulation_value(int x, int y, const int p_2bit, const int p_modulation[8][16], const int p_modulation_modes[8][16], int *r_mod, int *p_dopt) { - static const int rep_vals0[4] = { 0, 3, 5, 8 }; - static const int rep_vals1[4] = { 0, 4, 4, 8 }; - - int mod_val; - - y = (y & 0x3) | ((~y & 0x2) << 1); - - if (p_2bit) { - x = (x & 0x7) | ((~x & 0x4) << 1); - } else { - x = (x & 0x3) | ((~x & 0x2) << 1); - } - - *p_dopt = 0; - - if (p_modulation_modes[y][x] == 0) { - mod_val = rep_vals0[p_modulation[y][x]]; - } else if (p_2bit) { - if (((x ^ y) & 1) == 0) { - mod_val = rep_vals0[p_modulation[y][x]]; - } else if (p_modulation_modes[y][x] == 1) { - mod_val = (rep_vals0[p_modulation[y - 1][x]] + - rep_vals0[p_modulation[y + 1][x]] + - rep_vals0[p_modulation[y][x - 1]] + - rep_vals0[p_modulation[y][x + 1]] + 2) / - 4; - } else if (p_modulation_modes[y][x] == 2) { - mod_val = (rep_vals0[p_modulation[y][x - 1]] + - rep_vals0[p_modulation[y][x + 1]] + 1) / - 2; - } else { - mod_val = (rep_vals0[p_modulation[y - 1][x]] + - rep_vals0[p_modulation[y + 1][x]] + 1) / - 2; - } - } else { - mod_val = rep_vals1[p_modulation[y][x]]; - - *p_dopt = p_modulation[y][x] == PT_INDEX; - } - - *r_mod = mod_val; -} - -static int disable_twiddling = 0; - -static uint32_t twiddle_uv(uint32_t p_height, uint32_t p_width, uint32_t p_y, uint32_t p_x) { - uint32_t twiddled; - - uint32_t min_dimension; - uint32_t max_value; - - uint32_t scr_bit_pos; - uint32_t dst_bit_pos; - - int shift_count; - - ERR_FAIL_COND_V(p_y >= p_height, 0); - ERR_FAIL_COND_V(p_x >= p_width, 0); - - ERR_FAIL_COND_V(!is_po2(p_height), 0); - ERR_FAIL_COND_V(!is_po2(p_width), 0); - - if (p_height < p_width) { - min_dimension = p_height; - max_value = p_x; - } else { - min_dimension = p_width; - max_value = p_y; - } - - if (disable_twiddling) { - return (p_y * p_width + p_x); - } - - scr_bit_pos = 1; - dst_bit_pos = 1; - twiddled = 0; - shift_count = 0; - - while (scr_bit_pos < min_dimension) { - if (p_y & scr_bit_pos) { - twiddled |= dst_bit_pos; - } - - if (p_x & scr_bit_pos) { - twiddled |= (dst_bit_pos << 1); - } - - scr_bit_pos <<= 1; - dst_bit_pos <<= 2; - shift_count += 1; - } - - max_value >>= shift_count; - - twiddled |= (max_value << (2 * shift_count)); - - return twiddled; -} - -static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int p_width, const int p_height, const int p_tiled, unsigned char *p_dst) { - int x, y; - int i, j; - - int block_x, blk_y; - int block_xp1, blk_yp1; - int x_block_size; - int block_width, block_height; - - int p_x, p_y; - - int p_modulation[8][16] = { { 0 } }; - int p_modulation_modes[8][16] = { { 0 } }; - - int Mod, DoPT; - - unsigned int u_pos; - - // local neighbourhood of blocks - PVRTCBlock *p_blocks[2][2]; - - PVRTCBlock *prev[2][2] = { { nullptr, nullptr }, { nullptr, nullptr } }; - - struct - { - int Reps[2][4]; - } colors5554[2][2]; - - int ASig[4], BSig[4]; - - int r_result[4]; - - if (p_2bit) { - x_block_size = BLK_X_2BPP; - } else { - x_block_size = BLK_X_4BPP; - } - - block_width = MAX(2, p_width / x_block_size); - block_height = MAX(2, p_height / BLK_Y_SIZE); - - for (y = 0; y < p_height; y++) { - for (x = 0; x < p_width; x++) { - block_x = (x - x_block_size / 2); - blk_y = (y - BLK_Y_SIZE / 2); - - block_x = LIMIT_COORD(block_x, p_width, p_tiled); - blk_y = LIMIT_COORD(blk_y, p_height, p_tiled); - - block_x /= x_block_size; - blk_y /= BLK_Y_SIZE; - - block_xp1 = LIMIT_COORD(block_x + 1, block_width, p_tiled); - blk_yp1 = LIMIT_COORD(blk_y + 1, block_height, p_tiled); - - p_blocks[0][0] = p_comp_img + twiddle_uv(block_height, block_width, blk_y, block_x); - p_blocks[0][1] = p_comp_img + twiddle_uv(block_height, block_width, blk_y, block_xp1); - p_blocks[1][0] = p_comp_img + twiddle_uv(block_height, block_width, blk_yp1, block_x); - p_blocks[1][1] = p_comp_img + twiddle_uv(block_height, block_width, blk_yp1, block_xp1); - - if (memcmp(prev, p_blocks, 4 * sizeof(void *)) != 0) { - p_y = 0; - for (i = 0; i < 2; i++) { - p_x = 0; - for (j = 0; j < 2; j++) { - unpack_5554(p_blocks[i][j], colors5554[i][j].Reps); - - unpack_modulations( - p_blocks[i][j], - p_2bit, - p_modulation, - p_modulation_modes, - p_x, p_y); - - p_x += x_block_size; - } - - p_y += BLK_Y_SIZE; - } - - memcpy(prev, p_blocks, 4 * sizeof(void *)); - } - - interpolate_colors( - colors5554[0][0].Reps[0], - colors5554[0][1].Reps[0], - colors5554[1][0].Reps[0], - colors5554[1][1].Reps[0], - p_2bit, x, y, - ASig); - - interpolate_colors( - colors5554[0][0].Reps[1], - colors5554[0][1].Reps[1], - colors5554[1][0].Reps[1], - colors5554[1][1].Reps[1], - p_2bit, x, y, - BSig); - - get_modulation_value(x, y, p_2bit, (const int(*)[16])p_modulation, (const int(*)[16])p_modulation_modes, - &Mod, &DoPT); - - for (i = 0; i < 4; i++) { - r_result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]); - r_result[i] >>= 3; - } - - if (DoPT) { - r_result[3] = 0; - } - - u_pos = (x + y * p_width) << 2; - p_dst[u_pos + 0] = (uint8_t)r_result[0]; - p_dst[u_pos + 1] = (uint8_t)r_result[1]; - p_dst[u_pos + 2] = (uint8_t)r_result[2]; - p_dst[u_pos + 3] = (uint8_t)r_result[3]; - } - } -} - -static void _pvrtc_decompress(Image *p_img) { - ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A); - - bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A); - - Vector<uint8_t> data = p_img->get_data(); - const uint8_t *r = data.ptr(); - - Vector<uint8_t> newdata; - newdata.resize(p_img->get_width() * p_img->get_height() * 4); - uint8_t *w = newdata.ptrw(); - - decompress_pvrtc((PVRTCBlock *)r, _2bit, p_img->get_width(), p_img->get_height(), 0, (unsigned char *)w); - - bool make_mipmaps = p_img->has_mipmaps(); - p_img->create(p_img->get_width(), p_img->get_height(), false, Image::FORMAT_RGBA8, newdata); - if (make_mipmaps) { - p_img->generate_mipmaps(); - } -} diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h deleted file mode 100644 index 26071ce30f..0000000000 --- a/modules/pvr/texture_loader_pvr.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* texture_loader_pvr.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 TEXTURE_LOADER_PVR_H -#define TEXTURE_LOADER_PVR_H - -#include "core/io/resource_loader.h" -#include "scene/resources/texture.h" - -class ResourceFormatPVR : 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; - - ResourceFormatPVR(); - virtual ~ResourceFormatPVR() {} -}; - -#endif // TEXTURE_LOADER_PVR_H diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp index fdcf509da8..ecc256bff9 100644 --- a/modules/raycast/lightmap_raycaster.cpp +++ b/modules/raycast/lightmap_raycaster.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h index 290b0a1cf3..c420e617e5 100644 --- a/modules/raycast/lightmap_raycaster.h +++ b/modules/raycast/lightmap_raycaster.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index 75491c98e5..1550f0ef8b 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -85,7 +85,7 @@ void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D td.z_near = p_cam_projection.get_z_near(); td.z_far = p_cam_projection.get_z_far() * 1.05f; td.camera_pos = p_cam_transform.origin; - td.camera_dir = -p_cam_transform.basis.get_axis(2); + td.camera_dir = -p_cam_transform.basis.get_column(2); td.camera_orthogonal = p_cam_orthogonal; CameraMatrix inv_camera_matrix = p_cam_projection.inverse(); @@ -270,13 +270,14 @@ void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, OccluderInstance &instance = scenario.instances[p_instance]; + bool changed = false; + if (instance.removed) { instance.removed = false; scenario.removed_instances.erase(p_instance); + changed = true; // It was removed and re-added, we might have missed some changes } - bool changed = false; - if (instance.occluder != p_occluder) { Occluder *old_occluder = occluder_owner.get_or_null(instance.occluder); if (old_occluder) { @@ -547,7 +548,7 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_ 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.ptr(), buffer.camera_rays_tile_count, p_thread_pool); - buffer.sort_rays(-p_cam_transform.basis.get_axis(2), p_cam_orthogonal); + buffer.sort_rays(-p_cam_transform.basis.get_column(2), p_cam_orthogonal); buffer.update_mips(); } diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h index ea96df5ff6..8453c5341d 100644 --- a/modules/raycast/raycast_occlusion_cull.h +++ b/modules/raycast/raycast_occlusion_cull.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -115,7 +115,7 @@ private: struct Scenario { struct RaycastThreadData { - CameraRayTile *rays; + CameraRayTile *rays = nullptr; const uint32_t *masks; }; @@ -124,7 +124,7 @@ private: uint32_t vertex_count; Transform3D xform; const Vector3 *read; - Vector3 *write; + Vector3 *write = nullptr; }; Thread *commit_thread = nullptr; diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp index ed99e635e1..42de1d971d 100644 --- a/modules/raycast/register_types.cpp +++ b/modules/raycast/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,7 +36,11 @@ RaycastOcclusionCull *raycast_occlusion_cull = nullptr; -void register_raycast_types() { +void initialize_raycast_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #ifdef TOOLS_ENABLED LightmapRaycasterEmbree::make_default_raycaster(); StaticRaycasterEmbree::make_default_raycaster(); @@ -44,7 +48,11 @@ void register_raycast_types() { raycast_occlusion_cull = memnew(RaycastOcclusionCull); } -void unregister_raycast_types() { +void uninitialize_raycast_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + if (raycast_occlusion_cull) { memdelete(raycast_occlusion_cull); } diff --git a/modules/raycast/register_types.h b/modules/raycast/register_types.h index 789604a491..a917285390 100644 --- a/modules/raycast/register_types.h +++ b/modules/raycast/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -28,5 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -void register_raycast_types(); -void unregister_raycast_types(); +#include "modules/register_module_types.h" + +void initialize_raycast_module(ModuleInitializationLevel p_level); +void uninitialize_raycast_module(ModuleInitializationLevel p_level); diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster.cpp index 2ba65eebf8..9df6d5ff43 100644 --- a/modules/raycast/static_raycaster.cpp +++ b/modules/raycast/static_raycaster.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster.h index 6b13ecf690..cce19ba60d 100644 --- a/modules/raycast/static_raycaster.h +++ b/modules/raycast/static_raycaster.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index 2ae2e53b02..deabc5ccd3 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="RefCounted" version="4.0"> +<class name="RegEx" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <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 20680b41fd..530a541ae8 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="RefCounted" version="4.0"> +<class name="RegExMatch" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Contains the results of a [RegEx] search. </brief_description> diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 6bae12e7e6..ee1137b71f 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/regex/regex.h b/modules/regex/regex.h index 68fe2bc6e0..e7221f4070 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -71,7 +71,7 @@ public: class RegEx : public RefCounted { GDCLASS(RegEx, RefCounted); - void *general_ctx; + void *general_ctx = nullptr; void *code = nullptr; String pattern; diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp index 03957f88cf..2103c57f77 100644 --- a/modules/regex/register_types.cpp +++ b/modules/regex/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,10 +32,17 @@ #include "core/object/class_db.h" #include "regex.h" -void register_regex_types() { +void initialize_regex_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(RegExMatch); GDREGISTER_CLASS(RegEx); } -void unregister_regex_types() { +void uninitialize_regex_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h index fe94cde954..c3edf23562 100644 --- a/modules/regex/register_types.h +++ b/modules/regex/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef REGEX_REGISTER_TYPES_H #define REGEX_REGISTER_TYPES_H -void register_regex_types(); -void unregister_regex_types(); +#include "modules/register_module_types.h" + +void initialize_regex_module(ModuleInitializationLevel p_level); +void uninitialize_regex_module(ModuleInitializationLevel p_level); #endif // REGEX_REGISTER_TYPES_H diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h index c2d303b435..3f500e7b2f 100644 --- a/modules/regex/tests/test_regex.h +++ b/modules/regex/tests/test_regex.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/register_module_types.h b/modules/register_module_types.h index 2cff8c54c4..cfd1b355d4 100644 --- a/modules/register_module_types.h +++ b/modules/register_module_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,8 +31,16 @@ #ifndef REGISTER_MODULE_TYPES_H #define REGISTER_MODULE_TYPES_H -void preregister_module_types(); -void register_module_types(); -void unregister_module_types(); +#include "core/extension/gdnative_interface.h" + +enum ModuleInitializationLevel { + MODULE_INITIALIZATION_LEVEL_CORE = GDNATIVE_INITIALIZATION_CORE, + MODULE_INITIALIZATION_LEVEL_SERVERS = GDNATIVE_INITIALIZATION_SERVERS, + MODULE_INITIALIZATION_LEVEL_SCENE = GDNATIVE_INITIALIZATION_SCENE, + MODULE_INITIALIZATION_LEVEL_EDITOR = GDNATIVE_INITIALIZATION_EDITOR +}; + +void initialize_modules(ModuleInitializationLevel p_level); +void uninitialize_modules(ModuleInitializationLevel p_level); #endif // REGISTER_MODULE_TYPES_H diff --git a/modules/squish/image_decompress_squish.cpp b/modules/squish/image_decompress_squish.cpp index 1450b0fe88..3a810e5259 100644 --- a/modules/squish/image_decompress_squish.cpp +++ b/modules/squish/image_decompress_squish.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/squish/image_decompress_squish.h b/modules/squish/image_decompress_squish.h index fff5839ac4..f1382b2610 100644 --- a/modules/squish/image_decompress_squish.h +++ b/modules/squish/image_decompress_squish.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp index 51aab040e7..a80419e0eb 100644 --- a/modules/squish/register_types.cpp +++ b/modules/squish/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,8 +32,16 @@ #include "image_decompress_squish.h" -void register_squish_types() { +void initialize_squish_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + Image::_image_decompress_bc = image_decompress_squish; } -void unregister_squish_types() {} +void uninitialize_squish_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h index 0f87d64333..5e9a4dfd50 100644 --- a/modules/squish/register_types.h +++ b/modules/squish/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef SQUISH_REGISTER_TYPES_H #define SQUISH_REGISTER_TYPES_H -void register_squish_types(); -void unregister_squish_types(); +#include "modules/register_module_types.h" + +void initialize_squish_module(ModuleInitializationLevel p_level); +void uninitialize_squish_module(ModuleInitializationLevel p_level); #endif // SQUISH_REGISTER_TYPES_H diff --git a/modules/svg/SCsub b/modules/svg/SCsub index c7228a8d0b..93262f4f87 100644 --- a/modules/svg/SCsub +++ b/modules/svg/SCsub @@ -9,16 +9,67 @@ env_svg = env_modules.Clone() thirdparty_obj = [] -thirdparty_dir = "#thirdparty/nanosvg/" +thirdparty_dir = "#thirdparty/thorvg/" thirdparty_sources = [ - "nanosvg.cc", + "src/lib/tvgBezier.cpp", + "src/lib/tvgCanvas.cpp", + "src/lib/tvgFill.cpp", + "src/lib/tvgGlCanvas.cpp", + "src/lib/tvgInitializer.cpp", + "src/lib/tvgLinearGradient.cpp", + "src/lib/tvgLoader.cpp", + "src/lib/tvgLzw.cpp", + "src/lib/tvgPaint.cpp", + "src/lib/tvgPicture.cpp", + "src/lib/tvgRadialGradient.cpp", + "src/lib/tvgRender.cpp", + "src/lib/tvgSaver.cpp", + "src/lib/tvgScene.cpp", + "src/lib/tvgShape.cpp", + "src/lib/tvgSwCanvas.cpp", + "src/lib/tvgTaskScheduler.cpp", + "src/loaders/raw/tvgRawLoader.cpp", + "src/loaders/svg/tvgXmlParser.cpp", + "src/loaders/svg/tvgSvgUtil.cpp", + "src/loaders/svg/tvgSvgSceneBuilder.cpp", + "src/loaders/svg/tvgSvgPath.cpp", + "src/loaders/svg/tvgSvgLoader.cpp", + "src/loaders/svg/tvgSvgCssStyle.cpp", + "src/loaders/tvg/tvgTvgBinInterpreter.cpp", + "src/loaders/tvg/tvgTvgLoader.cpp", + "src/loaders/jpg/tvgJpgLoader.cpp", + "src/loaders/jpg/tvgJpgd.cpp", + "src/loaders/external_png/tvgPngLoader.cpp", + "src/lib/sw_engine/tvgSwFill.cpp", + "src/lib/sw_engine/tvgSwImage.cpp", + "src/lib/sw_engine/tvgSwMath.cpp", + "src/lib/sw_engine/tvgSwMemPool.cpp", + "src/lib/sw_engine/tvgSwRaster.cpp", + "src/lib/sw_engine/tvgSwRenderer.cpp", + "src/lib/sw_engine/tvgSwRle.cpp", + "src/lib/sw_engine/tvgSwShape.cpp", + "src/lib/sw_engine/tvgSwStroke.cpp", + "src/savers/tvg/tvgTvgSaver.cpp", ] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env_svg.Prepend(CPPPATH=[thirdparty_dir]) +env_svg.Prepend(CPPPATH=[thirdparty_dir + "inc"]) env_thirdparty = env_svg.Clone() env_thirdparty.disable_warnings() +env_thirdparty.Prepend( + CPPPATH=[ + thirdparty_dir + "src/lib", + thirdparty_dir + "src/lib/sw_engine", + thirdparty_dir + "src/loaders/raw", + thirdparty_dir + "src/loaders/svg", + thirdparty_dir + "src/loaders/jpg", + thirdparty_dir + "src/loaders/png", + thirdparty_dir + "src/loaders/tvg", + thirdparty_dir + "src/savers/tvg", + ] +) env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) env.modules_sources += thirdparty_obj diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 4911346b96..dcb1f1d744 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,132 +30,118 @@ #include "image_loader_svg.h" -#include <nanosvg.h> -#include <nanosvgrast.h> - -void SVGRasterizer::rasterize(NSVGimage *p_image, float p_tx, float p_ty, float p_scale, unsigned char *p_dst, int p_w, int p_h, int p_stride) { - nsvgRasterize(rasterizer, p_image, p_tx, p_ty, p_scale, p_dst, p_w, p_h, p_stride); -} - -SVGRasterizer::SVGRasterizer() { - rasterizer = nsvgCreateRasterizer(); -} - -SVGRasterizer::~SVGRasterizer() { - nsvgDeleteRasterizer(rasterizer); -} - -SVGRasterizer ImageLoaderSVG::rasterizer; - -inline void change_nsvg_paint_color(NSVGpaint *p_paint, const uint32_t p_old, const uint32_t p_new) { - if (p_paint->type == NSVG_PAINT_COLOR) { - if (p_paint->color << 8 == p_old << 8) { - p_paint->color = (p_paint->color & 0xFF000000) | (p_new & 0x00FFFFFF); - } - } - - if (p_paint->type == NSVG_PAINT_LINEAR_GRADIENT || p_paint->type == NSVG_PAINT_RADIAL_GRADIENT) { - for (int stop_index = 0; stop_index < p_paint->gradient->nstops; stop_index++) { - if (p_paint->gradient->stops[stop_index].color << 8 == p_old << 8) { - p_paint->gradient->stops[stop_index].color = p_new; +#include "core/os/memory.h" +#include "core/variant/variant.h" + +#include <thorvg.h> + +void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_string) { + // Replace colors in the SVG based on what is configured in `replace_colors`. + // Used to change the colors of editor icons based on the used theme. + // The strings being replaced are typically of the form: + // fill="#5abbef" + // But can also be 3-letter codes, include alpha, be "none" or a named color + // string ("blue"). So we convert to Godot Color to compare with `replace_colors`. + + const int prefix_len = p_prefix.length(); + int pos = r_string.find(p_prefix); + while (pos != -1) { + pos += prefix_len; // Skip prefix. + int end_pos = r_string.find("\"", pos); + ERR_FAIL_COND_MSG(end_pos == -1, vformat("Malformed SVG string after property \"%s\".", p_prefix)); + const String color_code = r_string.substr(pos, end_pos - pos); + if (color_code != "none" && !color_code.begins_with("url(")) { + const Color color = Color(color_code); // Handles both HTML codes and named colors. + if (replace_colors.has(color)) { + r_string = r_string.left(pos) + "#" + replace_colors[color].operator Color().to_html(false) + r_string.substr(end_pos); } } + // Search for other occurrences. + pos = r_string.find(p_prefix, pos); } } -void ImageLoaderSVG::_convert_colors(NSVGimage *p_svg_image) { - for (NSVGshape *shape = p_svg_image->shapes; shape != nullptr; shape = shape->next) { - for (int i = 0; i < replace_colors.old_colors.size(); i++) { - change_nsvg_paint_color(&(shape->stroke), replace_colors.old_colors[i], replace_colors.new_colors[i]); - change_nsvg_paint_color(&(shape->fill), replace_colors.old_colors[i], replace_colors.new_colors[i]); - } - } -} +void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color) { + ERR_FAIL_COND(Math::is_zero_approx(p_scale)); -void ImageLoaderSVG::set_convert_colors(Dictionary *p_replace_color) { - if (p_replace_color) { - Dictionary replace_color = *p_replace_color; - for (int i = 0; i < replace_color.keys().size(); i++) { - Variant o_c = replace_color.keys()[i]; - Variant n_c = replace_color[replace_color.keys()[i]]; - if (o_c.get_type() == Variant::COLOR && n_c.get_type() == Variant::COLOR) { - Color old_color = o_c; - Color new_color = n_c; - replace_colors.old_colors.push_back(old_color.to_abgr32()); - replace_colors.new_colors.push_back(new_color.to_abgr32()); - } - } - } else { - replace_colors.old_colors.clear(); - replace_colors.new_colors.clear(); + if (p_convert_color) { + _replace_color_property("stop-color=\"", p_string); + _replace_color_property("fill=\"", p_string); + _replace_color_property("stroke=\"", p_string); } -} -Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const Vector<uint8_t> *p_data, float p_scale, bool upsample, bool convert_colors) { - NSVGimage *svg_image; - const uint8_t *src_r = p_data->ptr(); - svg_image = nsvgParse((char *)src_r, "px", 96); - if (svg_image == nullptr) { - ERR_PRINT("SVG Corrupted"); - return ERR_FILE_CORRUPT; - } + std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen(); + PackedByteArray bytes = p_string.to_utf8_buffer(); - if (convert_colors) { - _convert_colors(svg_image); + tvg::Result result = picture->load((const char *)bytes.ptr(), bytes.size(), "svg", true); + if (result != tvg::Result::Success) { + return; } + float fw, fh; + picture->size(&fw, &fh); - const float upscale = upsample ? 2.0 : 1.0; - - const int w = (int)(svg_image->width * p_scale * upscale); - ERR_FAIL_COND_V_MSG(w > Image::MAX_WIDTH, ERR_PARAMETER_RANGE_ERROR, vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max width.", rtos(p_scale))); - - const int h = (int)(svg_image->height * p_scale * upscale); - ERR_FAIL_COND_V_MSG(h > Image::MAX_HEIGHT, ERR_PARAMETER_RANGE_ERROR, vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max height.", rtos(p_scale))); - - Vector<uint8_t> dst_image; - dst_image.resize(w * h * 4); + uint32_t width = MIN(fw * p_scale, 16 * 1024); + uint32_t height = MIN(fh * p_scale, 16 * 1024); + picture->size(width, height); - uint8_t *dw = dst_image.ptrw(); + std::unique_ptr<tvg::SwCanvas> sw_canvas = tvg::SwCanvas::gen(); + // Note: memalloc here, be sure to memfree before any return. + uint32_t *buffer = (uint32_t *)memalloc(sizeof(uint32_t) * width * height); - rasterizer.rasterize(svg_image, 0, 0, p_scale * upscale, (unsigned char *)dw, w, h, w * 4); - - p_image->create(w, h, false, Image::FORMAT_RGBA8, dst_image); - if (upsample) { - p_image->shrink_x2(); + tvg::Result res = sw_canvas->target(buffer, width, width, height, tvg::SwCanvas::ARGB8888_STRAIGHT); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); } - nsvgDelete(svg_image); + res = sw_canvas->push(std::move(picture)); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + } - return OK; -} + res = sw_canvas->draw(); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + } -Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, const char *p_svg_str, float p_scale, bool upsample, bool convert_colors) { - size_t str_len = strlen(p_svg_str); - Vector<uint8_t> src_data; - src_data.resize(str_len + 1); - uint8_t *src_w = src_data.ptrw(); - memcpy(src_w, p_svg_str, str_len + 1); + res = sw_canvas->sync(); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + } - return _create_image(p_image, &src_data, p_scale, upsample, convert_colors); -} + Vector<uint8_t> image; + image.resize(width * height * sizeof(uint32_t)); + + for (uint32_t y = 0; y < height; y++) { + for (uint32_t x = 0; x < width; x++) { + uint32_t n = buffer[y * width + x]; + const size_t offset = sizeof(uint32_t) * width * y + sizeof(uint32_t) * x; + image.write[offset + 0] = (n >> 16) & 0xff; + image.write[offset + 1] = (n >> 8) & 0xff; + image.write[offset + 2] = n & 0xff; + image.write[offset + 3] = (n >> 24) & 0xff; + } + } -Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - uint64_t size = f->get_length(); - Vector<uint8_t> src_image; - src_image.resize(size + 1); - uint8_t *src_w = src_image.ptrw(); - f->get_buffer(src_w, size); - src_w[size] = '\0'; + res = sw_canvas->clear(true); + memfree(buffer); - return _create_image(p_image, &src_image, p_scale, 1.0); + p_image->create(width, height, false, Image::FORMAT_RGBA8, image); } void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("svg"); - p_extensions->push_back("svgz"); } -ImageLoaderSVG::ImageLoaderSVG() { +Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) { + String svg = p_fileaccess->get_as_utf8_string(); + create_image_from_string(p_image, svg, p_scale, false, false); + ERR_FAIL_COND_V(p_image->is_empty(), FAILED); + if (p_force_linear) { + p_image->srgb_to_linear(); + } + return OK; } - -ImageLoaderSVG::ReplaceColors ImageLoaderSVG::replace_colors; diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index e64175b172..94c17fda43 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,42 +32,18 @@ #define IMAGE_LOADER_SVG_H #include "core/io/image_loader.h" -#include "core/string/ustring.h" - -/** - @author Daniel Ramirez <djrmuv@gmail.com> -*/ - -// Forward declare and include thirdparty headers in .cpp. -struct NSVGrasterizer; -struct NSVGimage; - -class SVGRasterizer { - NSVGrasterizer *rasterizer; - -public: - void rasterize(NSVGimage *p_image, float p_tx, float p_ty, float p_scale, unsigned char *p_dst, int p_w, int p_h, int p_stride); - - SVGRasterizer(); - ~SVGRasterizer(); -}; class ImageLoaderSVG : public ImageFormatLoader { - static struct ReplaceColors { - List<uint32_t> old_colors; - List<uint32_t> new_colors; - } replace_colors; - static SVGRasterizer rasterizer; - static void _convert_colors(NSVGimage *p_svg_image); - static Error _create_image(Ref<Image> p_image, const Vector<uint8_t> *p_data, float p_scale, bool upsample, bool convert_colors = false); + Dictionary replace_colors; + void _replace_color_property(const String &p_prefix, String &r_string); public: - static void set_convert_colors(Dictionary *p_replace_color = nullptr); - static Error create_image_from_string(Ref<Image> p_image, const char *p_svg_str, float p_scale, bool upsample, bool convert_colors = false); + // Called by the editor to handle theme icon colors. + void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; } + void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color); - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - ImageLoaderSVG(); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; }; -#endif +#endif // IMAGE_LOADER_SVG_H diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp index 1a611184d2..5b4d1d31ca 100644 --- a/modules/svg/register_types.cpp +++ b/modules/svg/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,13 +32,31 @@ #include "image_loader_svg.h" +#include <thorvg.h> + static ImageLoaderSVG *image_loader_svg = nullptr; -void register_svg_types() { +void initialize_svg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) { + return; + } image_loader_svg = memnew(ImageLoaderSVG); ImageLoader::add_image_format_loader(image_loader_svg); } -void unregister_svg_types() { +void uninitialize_svg_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + if (!image_loader_svg) { + return; + } memdelete(image_loader_svg); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/modules/svg/register_types.h b/modules/svg/register_types.h index 106ac9056f..66f3e94600 100644 --- a/modules/svg/register_types.h +++ b/modules/svg/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef SVG_REGISTER_TYPES_H #define SVG_REGISTER_TYPES_H -void register_svg_types(); -void unregister_svg_types(); +#include "modules/register_module_types.h" + +void initialize_svg_module(ModuleInitializationLevel p_level); +void uninitialize_svg_module(ModuleInitializationLevel p_level); #endif // SVG_REGISTER_TYPES_H diff --git a/modules/text_server_adv/.gitignore b/modules/text_server_adv/.gitignore new file mode 100644 index 0000000000..15cc38b59c --- /dev/null +++ b/modules/text_server_adv/.gitignore @@ -0,0 +1,2 @@ +# Godot-cpp headers +gdextension_build/godot-cpp diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index d6a96282f3..525d4d3efb 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -37,7 +37,7 @@ def make_icu_data(target, source, env): thirdparty_obj = [] freetype_enabled = env.module_check_dependencies("text_server_adv", ["freetype"], True) -msdngen_enabled = env.module_check_dependencies("text_server_adv", ["msdfgen"], True) +msdfgen_enabled = env.module_check_dependencies("text_server_adv", ["msdfgen"], True) if env["builtin_harfbuzz"]: env_harfbuzz = env_modules.Clone() @@ -49,6 +49,7 @@ if env["builtin_harfbuzz"]: "src/hb-aat-map.cc", "src/hb-blob.cc", "src/hb-buffer-serialize.cc", + "src/hb-buffer-verify.cc", "src/hb-buffer.cc", "src/hb-common.cc", #'src/hb-coretext.cc', @@ -62,7 +63,6 @@ if env["builtin_harfbuzz"]: #'src/hb-gobject-structs.cc', "src/hb-icu.cc", "src/hb-map.cc", - "src/hb-ms-feature-ranges.cc", "src/hb-number.cc", "src/hb-ot-cff1-table.cc", "src/hb-ot-cff2-table.cc", @@ -103,6 +103,7 @@ if env["builtin_harfbuzz"]: "src/hb-subset-cff2.cc", "src/hb-subset-input.cc", "src/hb-subset-plan.cc", + "src/hb-subset-repacker.cc", "src/hb-subset.cc", "src/hb-ucd.cc", "src/hb-unicode.cc", @@ -116,20 +117,25 @@ if env["builtin_harfbuzz"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - env_harfbuzz.Append( - CPPPATH=[ - "#thirdparty/harfbuzz/src", - "#thirdparty/icu4c/common/", - ] - ) + env_harfbuzz.Append(CPPPATH=["#thirdparty/harfbuzz/src"]) + + env_harfbuzz.Append(CCFLAGS=["-DHAVE_ICU"]) + if env["builtin_icu"]: + env_harfbuzz.Append(CPPPATH=["#thirdparty/icu4c/common/"]) + env_harfbuzz.Append(CCFLAGS=["-DU_HAVE_LIB_SUFFIX=1", "-DU_LIB_SUFFIX_C_NAME=_godot", "-DHAVE_ICU_BUILTIN"]) if freetype_enabled: env_harfbuzz.Append( - CPPPATH=[ - "#thirdparty/freetype/include", - "#thirdparty/graphite/include", + CCFLAGS=[ + "-DHAVE_FREETYPE", + "-DHAVE_GRAPHITE2", ] ) + if env["builtin_freetype"]: + env_harfbuzz.Append(CPPPATH=["#thirdparty/freetype/include"]) + if env["builtin_graphite"]: + env_harfbuzz.Append(CPPPATH=["#thirdparty/graphite/include"]) + env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"]) if env["platform"] == "android" or env["platform"] == "linuxbsd": env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"]) @@ -140,21 +146,7 @@ if env["builtin_harfbuzz"]: else: env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"]) - env_harfbuzz.Append( - CCFLAGS=[ - "-DHAVE_ICU_BUILTIN", - "-DHAVE_ICU", - ] - ) - - if freetype_enabled: - env_harfbuzz.Append( - CCFLAGS=[ - "-DHAVE_FREETYPE", - "-DHAVE_GRAPHITE2", - "-DGRAPHITE2_STATIC", - ] - ) + env_text_server_adv.Append(CPPPATH=["#thirdparty/harfbuzz/src"]) lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources) thirdparty_obj += lib @@ -455,6 +447,7 @@ if env["builtin_icu"]: if env_icu["tools"]: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) env_icu.Command("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name, make_icu_data) + env_text_server_adv.Append(CPPPATH=["#thirdparty/icu4c/"]) else: thirdparty_sources += ["icu_data/icudata_stub.cpp"] @@ -471,14 +464,23 @@ if env["builtin_icu"]: "-DUCONFIG_NO_FILE_IO", "-DUCONFIG_NO_TRANSLITERATION", "-DPKGDATA_MODE=static", + "-DU_ENABLE_DYLOAD=0", + "-DU_HAVE_LIB_SUFFIX=1", + "-DU_LIB_SUFFIX_C_NAME=_godot", "-DICU_DATA_NAME=" + icu_data_name, ] ) env_text_server_adv.Append( CXXFLAGS=[ + "-DU_HAVE_LIB_SUFFIX=1", + "-DU_LIB_SUFFIX_C_NAME=_godot", "-DICU_DATA_NAME=" + icu_data_name, ] ) + if env_text_server_adv["tools"]: + env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"]) + + env_text_server_adv.Append(CPPPATH=["#thirdparty/icu4c/common/"]) lib = env_icu.add_library("icu_builtin", thirdparty_sources) thirdparty_obj += lib @@ -501,30 +503,14 @@ if env["builtin_icu"]: module_obj = [] -if env_text_server_adv["tools"]: - env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"]) +if env["builtin_msdfgen"] and msdfgen_enabled: + env_text_server_adv.Append(CPPPATH=["#thirdparty/msdfgen"]) -env_text_server_adv.Append( - CPPPATH=[ - "#thirdparty/harfbuzz/src", - "#thirdparty/icu4c/common/", - ] -) +if env["builtin_freetype"] and freetype_enabled: + env_text_server_adv.Append(CPPPATH=["#thirdparty/freetype/include"]) -if msdngen_enabled: - env_text_server_adv.Append( - CPPPATH=[ - "#thirdparty/msdfgen", - ] - ) - -if freetype_enabled: - env_text_server_adv.Append( - CPPPATH=[ - "#thirdparty/freetype/include", - "#thirdparty/graphite/include", - ] - ) +if env["builtin_graphite"] and freetype_enabled: + env_text_server_adv.Append(CPPPATH=["#thirdparty/graphite/include"]) env_text_server_adv.add_source_files(module_obj, "*.cpp") env.modules_sources += module_obj diff --git a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml index eff4aa5fae..91dde65cb8 100644 --- a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml +++ b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TextServerAdvanced" inherits="TextServer" version="4.0"> +<class name="TextServerAdvanced" inherits="TextServerExtension" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Text Server using HarfBuzz, ICU and SIL Graphite to support BiDi, complex text layouts and contextual OpenType features. </brief_description> diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct new file mode 100644 index 0000000000..1c38398c88 --- /dev/null +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -0,0 +1,645 @@ +#!/usr/bin/env python +import atexit +import os +import sys +import methods +import time + +# For the reference: +# - CCFLAGS are compilation flags shared between C and C++ +# - CFLAGS are for C-specific compilation flags +# - CXXFLAGS are for C++-specific compilation flags +# - CPPFLAGS are for pre-processor flags +# - CPPDEFINES are for pre-processor defines +# - LINKFLAGS are for linking flags + +time_at_start = time.time() + +env = SConscript("./godot-cpp/SConstruct") +env.__class__.disable_warnings = methods.disable_warnings + +opts = Variables([], ARGUMENTS) +opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True)) +opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True)) +opts.Add(BoolVariable("graphite_enabled", "Use Graphite library (require FreeType)", True)) +opts.Add(BoolVariable("static_icu_data", "Use built-in ICU data", True)) +opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False)) + +opts.Update(env) + +if not env["verbose"]: + methods.no_verbose(sys, env) + +if env["platform"] == "windows" and not env["use_mingw"]: + env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. + +# MSDFGEN +if env["msdfgen_enabled"] and env["freetype_enabled"]: + env_msdfgen = env.Clone() + env_msdfgen.disable_warnings() + + thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/" + thirdparty_msdfgen_sources = [ + "core/Contour.cpp", + "core/EdgeHolder.cpp", + "core/MSDFErrorCorrection.cpp", + "core/Projection.cpp", + "core/Scanline.cpp", + "core/Shape.cpp", + "core/SignedDistance.cpp", + "core/Vector2.cpp", + "core/contour-combiners.cpp", + "core/edge-coloring.cpp", + "core/edge-segments.cpp", + "core/edge-selectors.cpp", + "core/equation-solver.cpp", + "core/msdf-error-correction.cpp", + "core/msdfgen.cpp", + "core/rasterization.cpp", + "core/render-sdf.cpp", + "core/sdf-error-estimation.cpp", + "core/shape-description.cpp", + ] + thirdparty_msdfgen_sources = [thirdparty_msdfgen_dir + file for file in thirdparty_msdfgen_sources] + + env_msdfgen.Append(CPPPATH=["../../../thirdparty/freetype/include", "../../../thirdparty/msdfgen"]) + env.Append(CPPPATH=["../../../thirdparty/msdfgen"]) + env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"]) + + lib = env_msdfgen.Library( + f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + thirdparty_msdfgen_sources, + ) + env.Append(LIBS=[lib]) + +# FreeType +if env["freetype_enabled"]: + env_freetype = env.Clone() + env_freetype.disable_warnings() + + thirdparty_freetype_dir = "../../../thirdparty/freetype/" + thirdparty_freetype_sources = [ + "src/autofit/autofit.c", + "src/base/ftbase.c", + "src/base/ftbbox.c", + "src/base/ftbdf.c", + "src/base/ftbitmap.c", + "src/base/ftcid.c", + "src/base/ftdebug.c", + "src/base/ftfstype.c", + "src/base/ftgasp.c", + "src/base/ftglyph.c", + "src/base/ftgxval.c", + "src/base/ftinit.c", + "src/base/ftmm.c", + "src/base/ftotval.c", + "src/base/ftpatent.c", + "src/base/ftpfr.c", + "src/base/ftstroke.c", + "src/base/ftsynth.c", + "src/base/ftsystem.c", + "src/base/fttype1.c", + "src/base/ftwinfnt.c", + "src/bdf/bdf.c", + "src/bzip2/ftbzip2.c", + "src/cache/ftcache.c", + "src/cff/cff.c", + "src/cid/type1cid.c", + "src/gxvalid/gxvalid.c", + "src/gzip/ftgzip.c", + "src/lzw/ftlzw.c", + "src/otvalid/otvalid.c", + "src/pcf/pcf.c", + "src/pfr/pfr.c", + "src/psaux/psaux.c", + "src/pshinter/pshinter.c", + "src/psnames/psnames.c", + "src/raster/raster.c", + "src/sdf/sdf.c", + "src/smooth/smooth.c", + "src/truetype/truetype.c", + "src/type1/type1.c", + "src/type42/type42.c", + "src/winfonts/winfnt.c", + "src/sfnt/sfnt.c", + ] + thirdparty_freetype_sources = [thirdparty_freetype_dir + file for file in thirdparty_freetype_sources] + + thirdparty_png_dir = "../../../thirdparty/libpng/" + thirdparty_png_sources = [ + "png.c", + "pngerror.c", + "pngget.c", + "pngmem.c", + "pngpread.c", + "pngread.c", + "pngrio.c", + "pngrtran.c", + "pngrutil.c", + "pngset.c", + "pngtrans.c", + "pngwio.c", + "pngwrite.c", + "pngwtran.c", + "pngwutil.c", + ] + thirdparty_freetype_sources += [thirdparty_png_dir + file for file in thirdparty_png_sources] + + thirdparty_zlib_dir = "../../../thirdparty/zlib/" + thirdparty_zlib_sources = [ + "adler32.c", + "compress.c", + "crc32.c", + "deflate.c", + "infback.c", + "inffast.c", + "inflate.c", + "inftrees.c", + "trees.c", + "uncompr.c", + "zutil.c", + ] + thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources] + + env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir]) + env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"]) + + env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)]) + if env["target"] == "debug": + env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) + + env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) + + lib = env_freetype.Library( + f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + thirdparty_freetype_sources, + ) + env.Append(LIBS=[lib]) + +# HarfBuzz +env_harfbuzz = env.Clone() +env_harfbuzz.disable_warnings() + +thirdparty_harfbuzz_dir = "../../../thirdparty/harfbuzz/" +thirdparty_harfbuzz_sources = [ + "src/hb-aat-layout.cc", + "src/hb-aat-map.cc", + "src/hb-blob.cc", + "src/hb-buffer-serialize.cc", + "src/hb-buffer-verify.cc", + "src/hb-buffer.cc", + "src/hb-common.cc", + #'src/hb-coretext.cc', + #'src/hb-directwrite.cc', + "src/hb-draw.cc", + "src/hb-face.cc", + "src/hb-fallback-shape.cc", + "src/hb-font.cc", + #'src/hb-gdi.cc', + #'src/hb-glib.cc', + #'src/hb-gobject-structs.cc', + "src/hb-icu.cc", + "src/hb-map.cc", + "src/hb-number.cc", + "src/hb-ot-cff1-table.cc", + "src/hb-ot-cff2-table.cc", + "src/hb-ot-color.cc", + "src/hb-ot-face.cc", + "src/hb-ot-font.cc", + "src/hb-ot-layout.cc", + "src/hb-ot-map.cc", + "src/hb-ot-math.cc", + "src/hb-ot-meta.cc", + "src/hb-ot-metrics.cc", + "src/hb-ot-name.cc", + "src/hb-ot-shape-complex-arabic.cc", + "src/hb-ot-shape-complex-default.cc", + "src/hb-ot-shape-complex-hangul.cc", + "src/hb-ot-shape-complex-hebrew.cc", + "src/hb-ot-shape-complex-indic-table.cc", + "src/hb-ot-shape-complex-indic.cc", + "src/hb-ot-shape-complex-khmer.cc", + "src/hb-ot-shape-complex-myanmar.cc", + "src/hb-ot-shape-complex-syllabic.cc", + "src/hb-ot-shape-complex-thai.cc", + "src/hb-ot-shape-complex-use.cc", + "src/hb-ot-shape-complex-vowel-constraints.cc", + "src/hb-ot-shape-fallback.cc", + "src/hb-ot-shape-normalize.cc", + "src/hb-ot-shape.cc", + "src/hb-ot-tag.cc", + "src/hb-ot-var.cc", + "src/hb-set.cc", + "src/hb-shape-plan.cc", + "src/hb-shape.cc", + "src/hb-shaper.cc", + "src/hb-static.cc", + "src/hb-style.cc", + "src/hb-subset-cff-common.cc", + "src/hb-subset-cff1.cc", + "src/hb-subset-cff2.cc", + "src/hb-subset-input.cc", + "src/hb-subset-plan.cc", + "src/hb-subset.cc", + "src/hb-ucd.cc", + "src/hb-unicode.cc", + #'src/hb-uniscribe.cc' +] + +if env["freetype_enabled"]: + thirdparty_harfbuzz_sources += [ + "src/hb-ft.cc", + "src/hb-graphite2.cc", + ] +thirdparty_harfbuzz_sources = [thirdparty_harfbuzz_dir + file for file in thirdparty_harfbuzz_sources] + +env_harfbuzz.Append( + CPPPATH=[ + "../../../thirdparty/harfbuzz/src", + "../../../thirdparty/icu4c/common/", + ] +) + +if env["freetype_enabled"]: + env_harfbuzz.Append( + CPPPATH=[ + "../../../thirdparty/freetype/include", + "../../../thirdparty/graphite/include", + ] + ) + +if env["platform"] == "android" or env["platform"] == "linuxbsd": + env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"]) + +env_harfbuzz.Append( + CCFLAGS=[ + "-DU_HAVE_LIB_SUFFIX=1", + "-DU_LIB_SUFFIX_C_NAME=_godot", + "-DHAVE_ICU_BUILTIN", + "-DHAVE_ICU", + ] +) + +if env["freetype_enabled"]: + env_harfbuzz.Append( + CCFLAGS=[ + "-DHAVE_FREETYPE", + "-DHAVE_GRAPHITE2", + "-DGRAPHITE2_STATIC", + ] + ) + +env.Append(CPPPATH=["../../../thirdparty/harfbuzz/src"]) + +lib = env_harfbuzz.Library( + f'harfbuzz_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + thirdparty_harfbuzz_sources, +) +env.Prepend(LIBS=[lib]) + +# Graphite +if env["graphite_enabled"] and env["freetype_enabled"]: + env_graphite = env.Clone() + env_graphite.disable_warnings() + + thirdparty_graphite_dir = "../../../thirdparty/graphite/" + thirdparty_graphite_sources = [ + "src/gr_char_info.cpp", + "src/gr_face.cpp", + "src/gr_features.cpp", + "src/gr_font.cpp", + "src/gr_logging.cpp", + "src/gr_segment.cpp", + "src/gr_slot.cpp", + "src/CmapCache.cpp", + "src/Code.cpp", + "src/Collider.cpp", + "src/Decompressor.cpp", + "src/Face.cpp", + #'src/FileFace.cpp', + "src/FeatureMap.cpp", + "src/Font.cpp", + "src/GlyphCache.cpp", + "src/GlyphFace.cpp", + "src/Intervals.cpp", + "src/Justifier.cpp", + "src/NameTable.cpp", + "src/Pass.cpp", + "src/Position.cpp", + "src/Segment.cpp", + "src/Silf.cpp", + "src/Slot.cpp", + "src/Sparse.cpp", + "src/TtfUtil.cpp", + "src/UtfCodec.cpp", + "src/FileFace.cpp", + "src/json.cpp", + ] + if env["platform"] != "windows" or env["use_mingw"]: + thirdparty_graphite_sources += ["src/direct_machine.cpp"] + else: + thirdparty_graphite_sources += ["src/call_machine.cpp"] + + thirdparty_graphite_sources = [thirdparty_graphite_dir + file for file in thirdparty_graphite_sources] + + env_graphite.Append(CPPPATH=["../../../thirdparty/graphite/src", "../../../thirdparty/graphite/include"]) + env_graphite.Append( + CCFLAGS=[ + "-DGRAPHITE2_STATIC", + "-DGRAPHITE2_NTRACING", + "-DGRAPHITE2_NFILEFACE", + ] + ) + + lib = env_graphite.Library( + f'graphite_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + thirdparty_graphite_sources, + ) + env.Append(LIBS=[lib]) + +# ICU +env_icu = env.Clone() +env_icu.disable_warnings() + +thirdparty_icu_dir = "../../../thirdparty/icu4c/" +thirdparty_icu_sources = [ + "common/appendable.cpp", + "common/bmpset.cpp", + "common/brkeng.cpp", + "common/brkiter.cpp", + "common/bytesinkutil.cpp", + "common/bytestream.cpp", + "common/bytestrie.cpp", + "common/bytestriebuilder.cpp", + "common/bytestrieiterator.cpp", + "common/caniter.cpp", + "common/characterproperties.cpp", + "common/chariter.cpp", + "common/charstr.cpp", + "common/cmemory.cpp", + "common/cstr.cpp", + "common/cstring.cpp", + "common/cwchar.cpp", + "common/dictbe.cpp", + "common/dictionarydata.cpp", + "common/dtintrv.cpp", + "common/edits.cpp", + "common/emojiprops.cpp", + "common/errorcode.cpp", + "common/filteredbrk.cpp", + "common/filterednormalizer2.cpp", + "common/icudataver.cpp", + "common/icuplug.cpp", + "common/loadednormalizer2impl.cpp", + "common/localebuilder.cpp", + "common/localematcher.cpp", + "common/localeprioritylist.cpp", + "common/locavailable.cpp", + "common/locbased.cpp", + "common/locdispnames.cpp", + "common/locdistance.cpp", + "common/locdspnm.cpp", + "common/locid.cpp", + "common/loclikely.cpp", + "common/loclikelysubtags.cpp", + "common/locmap.cpp", + "common/locresdata.cpp", + "common/locutil.cpp", + "common/lsr.cpp", + "common/lstmbe.cpp", + "common/messagepattern.cpp", + "common/normalizer2.cpp", + "common/normalizer2impl.cpp", + "common/normlzr.cpp", + "common/parsepos.cpp", + "common/patternprops.cpp", + "common/pluralmap.cpp", + "common/propname.cpp", + "common/propsvec.cpp", + "common/punycode.cpp", + "common/putil.cpp", + "common/rbbi.cpp", + "common/rbbi_cache.cpp", + "common/rbbidata.cpp", + "common/rbbinode.cpp", + "common/rbbirb.cpp", + "common/rbbiscan.cpp", + "common/rbbisetb.cpp", + "common/rbbistbl.cpp", + "common/rbbitblb.cpp", + "common/resbund.cpp", + "common/resbund_cnv.cpp", + "common/resource.cpp", + "common/restrace.cpp", + "common/ruleiter.cpp", + "common/schriter.cpp", + "common/serv.cpp", + "common/servlk.cpp", + "common/servlkf.cpp", + "common/servls.cpp", + "common/servnotf.cpp", + "common/servrbf.cpp", + "common/servslkf.cpp", + "common/sharedobject.cpp", + "common/simpleformatter.cpp", + "common/static_unicode_sets.cpp", + "common/stringpiece.cpp", + "common/stringtriebuilder.cpp", + "common/uarrsort.cpp", + "common/ubidi.cpp", + "common/ubidi_props.cpp", + "common/ubidiln.cpp", + "common/ubiditransform.cpp", + "common/ubidiwrt.cpp", + "common/ubrk.cpp", + "common/ucase.cpp", + "common/ucasemap.cpp", + "common/ucasemap_titlecase_brkiter.cpp", + "common/ucat.cpp", + "common/uchar.cpp", + "common/ucharstrie.cpp", + "common/ucharstriebuilder.cpp", + "common/ucharstrieiterator.cpp", + "common/uchriter.cpp", + "common/ucln_cmn.cpp", + "common/ucmndata.cpp", + "common/ucnv.cpp", + "common/ucnv2022.cpp", + "common/ucnv_bld.cpp", + "common/ucnv_cb.cpp", + "common/ucnv_cnv.cpp", + "common/ucnv_ct.cpp", + "common/ucnv_err.cpp", + "common/ucnv_ext.cpp", + "common/ucnv_io.cpp", + "common/ucnv_lmb.cpp", + "common/ucnv_set.cpp", + "common/ucnv_u16.cpp", + "common/ucnv_u32.cpp", + "common/ucnv_u7.cpp", + "common/ucnv_u8.cpp", + "common/ucnvbocu.cpp", + "common/ucnvdisp.cpp", + "common/ucnvhz.cpp", + "common/ucnvisci.cpp", + "common/ucnvlat1.cpp", + "common/ucnvmbcs.cpp", + "common/ucnvscsu.cpp", + "common/ucnvsel.cpp", + "common/ucol_swp.cpp", + "common/ucptrie.cpp", + "common/ucurr.cpp", + "common/udata.cpp", + "common/udatamem.cpp", + "common/udataswp.cpp", + "common/uenum.cpp", + "common/uhash.cpp", + "common/uhash_us.cpp", + "common/uidna.cpp", + "common/uinit.cpp", + "common/uinvchar.cpp", + "common/uiter.cpp", + "common/ulist.cpp", + "common/uloc.cpp", + "common/uloc_keytype.cpp", + "common/uloc_tag.cpp", + "common/umapfile.cpp", + "common/umath.cpp", + "common/umutablecptrie.cpp", + "common/umutex.cpp", + "common/unames.cpp", + "common/unifiedcache.cpp", + "common/unifilt.cpp", + "common/unifunct.cpp", + "common/uniset.cpp", + "common/uniset_closure.cpp", + "common/uniset_props.cpp", + "common/unisetspan.cpp", + "common/unistr.cpp", + "common/unistr_case.cpp", + "common/unistr_case_locale.cpp", + "common/unistr_cnv.cpp", + "common/unistr_props.cpp", + "common/unistr_titlecase_brkiter.cpp", + "common/unorm.cpp", + "common/unormcmp.cpp", + "common/uobject.cpp", + "common/uprops.cpp", + "common/ures_cnv.cpp", + "common/uresbund.cpp", + "common/uresdata.cpp", + "common/usc_impl.cpp", + "common/uscript.cpp", + "common/uscript_props.cpp", + "common/uset.cpp", + "common/uset_props.cpp", + "common/usetiter.cpp", + # "common/ushape.cpp", + "common/usprep.cpp", + "common/ustack.cpp", + "common/ustr_cnv.cpp", + "common/ustr_titlecase_brkiter.cpp", + "common/ustr_wcs.cpp", + "common/ustrcase.cpp", + "common/ustrcase_locale.cpp", + "common/ustrenum.cpp", + "common/ustrfmt.cpp", + "common/ustring.cpp", + "common/ustrtrns.cpp", + "common/utext.cpp", + "common/utf_impl.cpp", + "common/util.cpp", + "common/util_props.cpp", + "common/utrace.cpp", + "common/utrie.cpp", + "common/utrie2.cpp", + "common/utrie2_builder.cpp", + "common/utrie_swap.cpp", + "common/uts46.cpp", + "common/utypes.cpp", + "common/uvector.cpp", + "common/uvectr32.cpp", + "common/uvectr64.cpp", + "common/wintz.cpp", +] +thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources] + +icu_data_name = "icudt70l.dat" + +if env["static_icu_data"]: + env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name) + env_icu.Command( + "../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name, methods.make_icu_data + ) + env.Append(CXXFLAGS=["-DICU_STATIC_DATA"]) + env.Append(CPPPATH=["../../../thirdparty/icu4c/"]) +else: + thirdparty_sources += ["../icu_data/icudata_stub.cpp"] + +env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/"]) +env_icu.Append( + CXXFLAGS=[ + "-DU_STATIC_IMPLEMENTATION", + "-DU_COMMON_IMPLEMENTATION", + "-DUCONFIG_NO_COLLATION", + "-DUCONFIG_NO_CONVERSION", + "-DUCONFIG_NO_FORMATTING", + "-DUCONFIG_NO_SERVICE", + "-DUCONFIG_NO_IDNA", + "-DUCONFIG_NO_FILE_IO", + "-DUCONFIG_NO_TRANSLITERATION", + "-DPKGDATA_MODE=static", + "-DU_ENABLE_DYLOAD=0", + "-DU_HAVE_LIB_SUFFIX=1", + "-DU_LIB_SUFFIX_C_NAME=_godot", + "-DICU_DATA_NAME=" + icu_data_name, + ] +) +env.Append( + CXXFLAGS=[ + "-DU_HAVE_LIB_SUFFIX=1", + "-DU_LIB_SUFFIX_C_NAME=_godot", + "-DICU_DATA_NAME=" + icu_data_name, + ] +) +env.Append(CPPPATH=["../../../thirdparty/icu4c/common/"]) + +if env["platform"] == "windows": + env.Append(LIBS=["advapi32"]) + +lib = env_icu.Library( + f'icu_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources +) +env.Append(LIBS=[lib]) + +env.Append(CPPDEFINES=["GDEXTENSION"]) +env.Append(CPPPATH=["../"]) +sources = Glob("../*.cpp") + +if env["platform"] == "osx": + methods.write_osx_plist( + f'./bin/libtextserver_advanced.osx.{env["target"]}.framework', + f'libtextserver_advanced.osx.{env["target"]}', + "org.godotengine.textserver_advanced", + "ICU / HarfBuzz / Graphite Text Server", + ) + library = env.SharedLibrary( + f'./bin/libtextserver_advanced.osx.{env["target"]}.framework/libtextserver_advanced.osx.{env["target"]}', + source=sources, + ) +else: + library = env.SharedLibrary( + f'./bin/libtextserver_advanced.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}', + source=sources, + ) + +Default(library) + + +def print_elapsed_time(): + elapsed_time_sec = round(time.time() - time_at_start, 3) + time_ms = round((elapsed_time_sec % 1) * 1000) + print("[Time elapsed: {}.{:03}]".format(time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), time_ms)) + + +atexit.register(print_elapsed_time) diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py new file mode 100644 index 0000000000..d404f2851e --- /dev/null +++ b/modules/text_server_adv/gdextension_build/methods.py @@ -0,0 +1,130 @@ +import os +import sys + + +def no_verbose(sys, env): + colors = {} + + # Colors are disabled in non-TTY environments such as pipes. This means + # that if output is redirected to a file, it will not contain color codes + if sys.stdout.isatty(): + colors["blue"] = "\033[0;94m" + colors["bold_blue"] = "\033[1;94m" + colors["reset"] = "\033[0m" + else: + colors["blue"] = "" + colors["bold_blue"] = "" + colors["reset"] = "" + + # There is a space before "..." to ensure that source file names can be + # Ctrl + clicked in the VS Code terminal. + compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + link_program_message = "{}Linking Program {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + + env.Append(CXXCOMSTR=[compile_source_message]) + env.Append(CCCOMSTR=[compile_source_message]) + env.Append(SHCCCOMSTR=[compile_shared_source_message]) + env.Append(SHCXXCOMSTR=[compile_shared_source_message]) + env.Append(ARCOMSTR=[link_library_message]) + env.Append(RANLIBCOMSTR=[ranlib_library_message]) + env.Append(SHLINKCOMSTR=[link_shared_library_message]) + env.Append(LINKCOMSTR=[link_program_message]) + env.Append(JARCOMSTR=[java_library_message]) + env.Append(JAVACCOMSTR=[java_compile_source_message]) + + +def disable_warnings(self): + # 'self' is the environment + if self["platform"] == "windows" and not self["use_mingw"]: + # We have to remove existing warning level defines before appending /w, + # otherwise we get: "warning D9025 : overriding '/W3' with '/w'" + warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"] + self.Append(CCFLAGS=["/w"]) + self.Append(CFLAGS=["/w"]) + self.Append(CXXFLAGS=["/w"]) + self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags] + self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags] + self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags] + else: + self.Append(CCFLAGS=["-w"]) + self.Append(CFLAGS=["-w"]) + self.Append(CXXFLAGS=["-w"]) + + +def make_icu_data(target, source, env): + dst = target[0].srcnode().abspath + g = open(dst, "w", encoding="utf-8") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n") + g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n") + g.write("#ifndef _ICU_DATA_H\n") + g.write("#define _ICU_DATA_H\n") + g.write('#include "unicode/utypes.h"\n') + g.write('#include "unicode/udata.h"\n') + g.write('#include "unicode/uversion.h"\n') + + f = open(source[0].srcnode().abspath, "rb") + buf = f.read() + + g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n") + g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n') + for i in range(len(buf)): + g.write("\t" + str(buf[i]) + ",\n") + + g.write("};\n") + g.write("#endif") + + +def write_osx_plist(target, binary_name, identifier, name): + os.makedirs(f"{target}/Resourece/", exist_ok=True) + f = open(f"{target}/Resourece/Info.plist", "w") + + f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n') + f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n') + f.write(f'<plist version="1.0">\n') + f.write(f"<dict>\n") + f.write(f"\t<key>CFBundleExecutable</key>\n") + f.write(f"\t<string>{binary_name}</string>\n") + f.write(f"\t<key>CFBundleIdentifier</key>\n") + f.write(f"\t<string>{identifier}</string>\n") + f.write(f"\t<key>CFBundleInfoDictionaryVersion</key>\n") + f.write(f"\t<string>6.0</string>\n") + f.write(f"\t<key>CFBundleName</key>\n") + f.write(f"\t<string>{name}</string>\n") + f.write(f"\t<key>CFBundlePackageType</key>\n") + f.write(f"\t<string>FMWK</string>\n") + f.write(f"\t<key>CFBundleShortVersionString</key>\n") + f.write(f"\t<string>1.0.0</string>\n") + f.write(f"\t<key>CFBundleSupportedPlatforms</key>\n") + f.write(f"\t<array>\n") + f.write(f"\t\t<string>MacOSX</string>\n") + f.write(f"\t</array>\n") + f.write(f"\t<key>CFBundleVersion</key>\n") + f.write(f"\t<string>1.0.0</string>\n") + f.write(f"\t<key>LSMinimumSystemVersion</key>\n") + f.write(f"\t<string>10.14</string>\n") + f.write(f"</dict>\n") + f.write(f"</plist>\n") diff --git a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension new file mode 100644 index 0000000000..5956476a5e --- /dev/null +++ b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension @@ -0,0 +1,12 @@ +[configuration] + +entry_symbol = "textserver_advanced_init" + +[libraries] + +linux.64.debug = "bin/libtextserver_advanced.linux.debug.64.so" +linux.64.release = "bin/libtextserver_advanced.linux.release.64.so" +windows.64.debug = "bin/libtextserver_advanced.windows.debug.64.dll" +windows.64.release = "bin/libtextserver_advanced.windows.release.64.dll" +macos.debug = "bin/libtextserver_advanced.osx.debug.framework" +macos.release = "bin/libtextserver_advanced.osx.release.framework" diff --git a/modules/text_server_adv/icu_data/icudata_stub.cpp b/modules/text_server_adv/icu_data/icudata_stub.cpp index 187001f33a..47dfa5ce26 100644 --- a/modules/text_server_adv/icu_data/icudata_stub.cpp +++ b/modules/text_server_adv/icu_data/icudata_stub.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp index b711d1561f..6a26584506 100644 --- a/modules/text_server_adv/register_types.cpp +++ b/modules/text_server_adv/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,17 +32,46 @@ #include "text_server_adv.h" -void preregister_text_server_adv_types() { +void initialize_text_server_adv_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } + GDREGISTER_CLASS(TextServerAdvanced); - if (TextServerManager::get_singleton()) { + TextServerManager *tsman = TextServerManager::get_singleton(); + if (tsman) { Ref<TextServerAdvanced> ts; ts.instantiate(); - TextServerManager::get_singleton()->add_interface(ts); + tsman->add_interface(ts); } } -void register_text_server_adv_types() { +void uninitialize_text_server_adv_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } } -void unregister_text_server_adv_types() { +#ifdef GDEXTENSION + +#include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/defs.hpp> +#include <godot_cpp/core/memory.hpp> + +using namespace godot; + +extern "C" { + +GDNativeBool GDN_EXPORT textserver_advanced_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) { + GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); + + init_obj.register_initializer(&initialize_text_server_adv_module); + init_obj.register_terminator(&uninitialize_text_server_adv_module); + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SERVERS); + + return init_obj.init(); } + +} // ! extern "C" + +#endif // ! GDEXTENSION diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h index ddd1190f40..dfe20c860c 100644 --- a/modules/text_server_adv/register_types.h +++ b/modules/text_server_adv/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,10 +31,14 @@ #ifndef TEXT_SERVER_ADV_REGISTER_TYPES_H #define TEXT_SERVER_ADV_REGISTER_TYPES_H -#define MODULE_TEXT_SERVER_ADV_HAS_PREREGISTER +#ifdef GDEXTENSION +#include <godot_cpp/core/class_db.hpp> +using namespace godot; +#else +#include "modules/register_module_types.h" +#endif -void preregister_text_server_adv_types(); -void register_text_server_adv_types(); -void unregister_text_server_adv_types(); +void initialize_text_server_adv_module(ModuleInitializationLevel p_level); +void uninitialize_text_server_adv_module(ModuleInitializationLevel p_level); #endif // TEXT_SERVER_ADV_REGISTER_TYPES_H diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index d1e849def8..3331254b20 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -51,7 +51,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length } int paren_size = PAREN_STACK_DEPTH; - ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry)); + ParenStackEntry *paren_stack = static_cast<ParenStackEntry *>(memalloc(paren_size * sizeof(ParenStackEntry))); int script_start; int script_end = p_start; @@ -77,12 +77,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length if (unlikely(paren_sp >= paren_size)) { // If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text. paren_size += PAREN_STACK_DEPTH; - paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry)); + paren_stack = static_cast<ParenStackEntry *>(memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry))); } paren_stack[paren_sp].pair_index = ch; paren_stack[paren_sp].script_code = script_code; } else if (paren_sp >= 0) { - // If it's a close character, find the matching open on the stack, and use that script code. Any non-matching open characters above it on the stack will be poped. + // If it's a close character, find the matching open on the stack, and use that script code. Any non-matching open characters above it on the stack will be popped. UChar32 paired_ch = u_getBidiPairedBracket(ch); while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) { paren_sp -= 1; diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h index 5efd40f7c4..2bd045b91a 100644 --- a/modules/text_server_adv/script_iterator.h +++ b/modules/text_server_adv/script_iterator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,22 @@ #ifndef SCRIPT_ITERATOR_H #define SCRIPT_ITERATOR_H -#include "servers/text_server.h" +#ifdef GDEXTENSION + +// Headers for building as GDExtension plug-in. +#include <godot_cpp/godot.hpp> +#include <godot_cpp/templates/vector.hpp> +#include <godot_cpp/variant/string.hpp> + +using namespace godot; + +#else + +// Headers for building as built-in module. +#include "core/string/ustring.h" +#include "core/templates/vector.h" + +#endif #include <unicode/uchar.h> #include <unicode/uloc.h> diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index cfab021e24..07421b7275 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,15 +30,37 @@ #include "text_server_adv.h" +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/classes/file.hpp> +#include <godot_cpp/classes/rendering_server.hpp> +#include <godot_cpp/classes/translation_server.hpp> +#include <godot_cpp/core/error_macros.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + +#include "core/core_bind.h" #include "core/error/error_macros.h" #include "core/string/print_string.h" #include "core/string/translation.h" +#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. + +using namespace core_bind; + +#endif + +// Built-in ICU data. + #ifdef ICU_STATIC_DATA -#include "thirdparty/icu4c/icudata.gen.h" +#include "icudata.gen.h" #endif -#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. +// Thirdparty headers. #ifdef MODULE_MSDFGEN_ENABLED #include "core/ShapeDistanceFinder.h" @@ -67,20 +89,20 @@ TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerA } void TextServerAdvanced::_bmp_font_destroy(void *p_data) { - bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data); + bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data); memdelete(bm_font); } hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; } if (!bm_font->face->glyph_map.has(p_unicode)) { - if (bm_font->face->glyph_map.has(0xF000u + p_unicode)) { - *r_glyph = 0xF000u + p_unicode; + if (bm_font->face->glyph_map.has(0xf000u + p_unicode)) { + *r_glyph = 0xf000u + p_unicode; return true; } else { return false; @@ -92,7 +114,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_ } hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -106,7 +128,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, vo } hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -120,7 +142,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, vo } hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -134,7 +156,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, vo } hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -151,7 +173,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p } hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -170,7 +192,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_ } hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -303,40 +325,54 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) { return (prop != U_JT_RIGHT_JOINING) && (prop != U_JT_NON_JOINING) ? !is_ligature(p_pchr, p_chr) : false; } -_FORCE_INLINE_ bool is_control(char32_t p_char) { - return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009F); -} - -_FORCE_INLINE_ bool is_whitespace(char32_t p_char) { - return (p_char == 0x0020) || (p_char == 0x00A0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085); -} - -_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"; -uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE; - bool TextServerAdvanced::has_feature(Feature p_feature) const { - return (interface_features & p_feature) == p_feature; + switch (p_feature) { + case FEATURE_SIMPLE_LAYOUT: + case FEATURE_BIDI_LAYOUT: + case FEATURE_VERTICAL_LAYOUT: + case FEATURE_SHAPING: + case FEATURE_KASHIDA_JUSTIFICATION: + case FEATURE_BREAK_ITERATORS: + case FEATURE_FONT_BITMAP: +#ifdef MODULE_FREETYPE_ENABLED + case FEATURE_FONT_DYNAMIC: +#endif +#ifdef MODULE_MSDFGEN_ENABLED + case FEATURE_FONT_MSDF: +#endif + case FEATURE_FONT_VARIABLE: + case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION: + case FEATURE_USE_SUPPORT_DATA: + return true; + default: { + } + } + return false; } String TextServerAdvanced::get_name() const { - return interface_name; +#ifdef GDEXTENSION + return "ICU / HarfBuzz / Graphite (GDExtension)"; +#else + return "ICU / HarfBuzz / Graphite (Built-in)"; +#endif } -uint32_t TextServerAdvanced::get_features() const { +int64_t TextServerAdvanced::get_features() const { + int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA; +#ifdef MODULE_FREETYPE_ENABLED + interface_features |= FEATURE_FONT_DYNAMIC; +#endif +#ifdef MODULE_MSDFGEN_ENABLED + interface_features |= FEATURE_FONT_MSDF; +#endif + return interface_features; } -void TextServerAdvanced::free(RID p_rid) { +void TextServerAdvanced::free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontDataAdvanced *fd = font_owner.get_or_null(p_rid); @@ -349,7 +385,7 @@ void TextServerAdvanced::free(RID p_rid) { } } -bool TextServerAdvanced::has(RID p_rid) { +bool TextServerAdvanced::has(const RID &p_rid) { _THREAD_SAFE_METHOD_ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid); } @@ -358,43 +394,35 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { _THREAD_SAFE_METHOD_ #ifdef ICU_STATIC_DATA - if (icu_data == nullptr) { + if (!icu_data_loaded) { UErrorCode err = U_ZERO_ERROR; u_init(&err); // Do not check for errors, since we only load part of the data. - icu_data = (uint8_t *)&U_ICUDATA_ENTRY_POINT; + icu_data_loaded = true; } #else - if (icu_data == nullptr) { + if (!icu_data_loaded) { String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename; - FileAccess *f = FileAccess::open(filename, FileAccess::READ); - if (!f) { + Ref<File> f; + f.instantiate(); + if (f->open(filename, File::READ) != OK) { return false; } - - UErrorCode err = U_ZERO_ERROR; - - // ICU data found. uint64_t len = f->get_length(); - icu_data = (uint8_t *)memalloc(len); - f->get_buffer(icu_data, len); - f->close(); - memdelete(f); + PackedByteArray icu_data = f->get_buffer(len); - udata_setCommonData(icu_data, &err); + UErrorCode err = U_ZERO_ERROR; + udata_setCommonData(icu_data.ptr(), &err); if (U_FAILURE(err)) { - memfree(icu_data); - icu_data = nullptr; ERR_FAIL_V_MSG(false, u_errorName(err)); } err = U_ZERO_ERROR; u_init(&err); if (U_FAILURE(err)) { - memfree(icu_data); - icu_data = nullptr; ERR_FAIL_V_MSG(false, u_errorName(err)); } + icu_data_loaded = true; } #endif return true; @@ -421,15 +449,19 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { #ifdef ICU_STATIC_DATA // Store data to the res file if it's available. - FileAccess *f = FileAccess::open(p_filename, FileAccess::WRITE); - if (!f) { + + Ref<File> f; + f.instantiate(); + if (f->open(p_filename, File::WRITE) != OK) { return false; } - f->store_buffer(U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); - f->close(); - memdelete(f); - return true; + PackedByteArray icu_data; + icu_data.resize(U_ICUDATA_SIZE); + memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); + f->store_buffer(icu_data); + + return true; #else return false; #endif @@ -444,256 +476,262 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const { } } +_FORCE_INLINE_ void TextServerAdvanced::_insert_feature(const StringName &p_name, int32_t p_tag) { + feature_sets.insert(p_name, p_tag); + feature_sets_inv.insert(p_tag, p_name); +} + void TextServerAdvanced::_insert_feature_sets() { // Registered OpenType feature tags. - feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't')); - feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f')); - feature_sets.insert("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm')); - feature_sets.insert("above_base_substitutions", HB_TAG('a', 'b', 'v', 's')); - feature_sets.insert("alternative_fractions", HB_TAG('a', 'f', 'r', 'c')); - feature_sets.insert("akhands", HB_TAG('a', 'k', 'h', 'n')); - feature_sets.insert("below_base_forms", HB_TAG('b', 'l', 'w', 'f')); - feature_sets.insert("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm')); - feature_sets.insert("below_base_substitutions", HB_TAG('b', 'l', 'w', 's')); - feature_sets.insert("contextual_alternates", HB_TAG('c', 'a', 'l', 't')); - feature_sets.insert("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e')); - feature_sets.insert("glyph_composition", HB_TAG('c', 'c', 'm', 'p')); - feature_sets.insert("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r')); - feature_sets.insert("conjunct_forms", HB_TAG('c', 'j', 'c', 't')); - feature_sets.insert("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g')); - feature_sets.insert("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't')); - feature_sets.insert("capital_spacing", HB_TAG('c', 'p', 's', 'p')); - feature_sets.insert("contextual_swash", HB_TAG('c', 's', 'w', 'h')); - feature_sets.insert("cursive_positioning", HB_TAG('c', 'u', 'r', 's')); - feature_sets.insert("character_variant_01", HB_TAG('c', 'v', '0', '1')); - feature_sets.insert("character_variant_02", HB_TAG('c', 'v', '0', '2')); - feature_sets.insert("character_variant_03", HB_TAG('c', 'v', '0', '3')); - feature_sets.insert("character_variant_04", HB_TAG('c', 'v', '0', '4')); - feature_sets.insert("character_variant_05", HB_TAG('c', 'v', '0', '5')); - feature_sets.insert("character_variant_06", HB_TAG('c', 'v', '0', '6')); - feature_sets.insert("character_variant_07", HB_TAG('c', 'v', '0', '7')); - feature_sets.insert("character_variant_08", HB_TAG('c', 'v', '0', '8')); - feature_sets.insert("character_variant_09", HB_TAG('c', 'v', '0', '9')); - feature_sets.insert("character_variant_10", HB_TAG('c', 'v', '1', '0')); - feature_sets.insert("character_variant_11", HB_TAG('c', 'v', '1', '1')); - feature_sets.insert("character_variant_12", HB_TAG('c', 'v', '1', '2')); - feature_sets.insert("character_variant_13", HB_TAG('c', 'v', '1', '3')); - feature_sets.insert("character_variant_14", HB_TAG('c', 'v', '1', '4')); - feature_sets.insert("character_variant_15", HB_TAG('c', 'v', '1', '5')); - feature_sets.insert("character_variant_16", HB_TAG('c', 'v', '1', '6')); - feature_sets.insert("character_variant_17", HB_TAG('c', 'v', '1', '7')); - feature_sets.insert("character_variant_18", HB_TAG('c', 'v', '1', '8')); - feature_sets.insert("character_variant_19", HB_TAG('c', 'v', '1', '9')); - feature_sets.insert("character_variant_20", HB_TAG('c', 'v', '2', '0')); - feature_sets.insert("character_variant_21", HB_TAG('c', 'v', '2', '1')); - feature_sets.insert("character_variant_22", HB_TAG('c', 'v', '2', '2')); - feature_sets.insert("character_variant_23", HB_TAG('c', 'v', '2', '3')); - feature_sets.insert("character_variant_24", HB_TAG('c', 'v', '2', '4')); - feature_sets.insert("character_variant_25", HB_TAG('c', 'v', '2', '5')); - feature_sets.insert("character_variant_26", HB_TAG('c', 'v', '2', '6')); - feature_sets.insert("character_variant_27", HB_TAG('c', 'v', '2', '7')); - feature_sets.insert("character_variant_28", HB_TAG('c', 'v', '2', '8')); - feature_sets.insert("character_variant_29", HB_TAG('c', 'v', '2', '9')); - feature_sets.insert("character_variant_30", HB_TAG('c', 'v', '3', '0')); - feature_sets.insert("character_variant_31", HB_TAG('c', 'v', '3', '1')); - feature_sets.insert("character_variant_32", HB_TAG('c', 'v', '3', '2')); - feature_sets.insert("character_variant_33", HB_TAG('c', 'v', '3', '3')); - feature_sets.insert("character_variant_34", HB_TAG('c', 'v', '3', '4')); - feature_sets.insert("character_variant_35", HB_TAG('c', 'v', '3', '5')); - feature_sets.insert("character_variant_36", HB_TAG('c', 'v', '3', '6')); - feature_sets.insert("character_variant_37", HB_TAG('c', 'v', '3', '7')); - feature_sets.insert("character_variant_38", HB_TAG('c', 'v', '3', '8')); - feature_sets.insert("character_variant_39", HB_TAG('c', 'v', '3', '9')); - feature_sets.insert("character_variant_40", HB_TAG('c', 'v', '4', '0')); - feature_sets.insert("character_variant_41", HB_TAG('c', 'v', '4', '1')); - feature_sets.insert("character_variant_42", HB_TAG('c', 'v', '4', '2')); - feature_sets.insert("character_variant_43", HB_TAG('c', 'v', '4', '3')); - feature_sets.insert("character_variant_44", HB_TAG('c', 'v', '4', '4')); - feature_sets.insert("character_variant_45", HB_TAG('c', 'v', '4', '5')); - feature_sets.insert("character_variant_46", HB_TAG('c', 'v', '4', '6')); - feature_sets.insert("character_variant_47", HB_TAG('c', 'v', '4', '7')); - feature_sets.insert("character_variant_48", HB_TAG('c', 'v', '4', '8')); - feature_sets.insert("character_variant_49", HB_TAG('c', 'v', '4', '9')); - feature_sets.insert("character_variant_50", HB_TAG('c', 'v', '5', '0')); - feature_sets.insert("character_variant_51", HB_TAG('c', 'v', '5', '1')); - feature_sets.insert("character_variant_52", HB_TAG('c', 'v', '5', '2')); - feature_sets.insert("character_variant_53", HB_TAG('c', 'v', '5', '3')); - feature_sets.insert("character_variant_54", HB_TAG('c', 'v', '5', '4')); - feature_sets.insert("character_variant_55", HB_TAG('c', 'v', '5', '5')); - feature_sets.insert("character_variant_56", HB_TAG('c', 'v', '5', '6')); - feature_sets.insert("character_variant_57", HB_TAG('c', 'v', '5', '7')); - feature_sets.insert("character_variant_58", HB_TAG('c', 'v', '5', '8')); - feature_sets.insert("character_variant_59", HB_TAG('c', 'v', '5', '9')); - feature_sets.insert("character_variant_60", HB_TAG('c', 'v', '6', '0')); - feature_sets.insert("character_variant_61", HB_TAG('c', 'v', '6', '1')); - feature_sets.insert("character_variant_62", HB_TAG('c', 'v', '6', '2')); - feature_sets.insert("character_variant_63", HB_TAG('c', 'v', '6', '3')); - feature_sets.insert("character_variant_64", HB_TAG('c', 'v', '6', '4')); - feature_sets.insert("character_variant_65", HB_TAG('c', 'v', '6', '5')); - feature_sets.insert("character_variant_66", HB_TAG('c', 'v', '6', '6')); - feature_sets.insert("character_variant_67", HB_TAG('c', 'v', '6', '7')); - feature_sets.insert("character_variant_68", HB_TAG('c', 'v', '6', '8')); - feature_sets.insert("character_variant_69", HB_TAG('c', 'v', '6', '9')); - feature_sets.insert("character_variant_70", HB_TAG('c', 'v', '7', '0')); - feature_sets.insert("character_variant_71", HB_TAG('c', 'v', '7', '1')); - feature_sets.insert("character_variant_72", HB_TAG('c', 'v', '7', '2')); - feature_sets.insert("character_variant_73", HB_TAG('c', 'v', '7', '3')); - feature_sets.insert("character_variant_74", HB_TAG('c', 'v', '7', '4')); - feature_sets.insert("character_variant_75", HB_TAG('c', 'v', '7', '5')); - feature_sets.insert("character_variant_76", HB_TAG('c', 'v', '7', '6')); - feature_sets.insert("character_variant_77", HB_TAG('c', 'v', '7', '7')); - feature_sets.insert("character_variant_78", HB_TAG('c', 'v', '7', '8')); - feature_sets.insert("character_variant_79", HB_TAG('c', 'v', '7', '9')); - feature_sets.insert("character_variant_80", HB_TAG('c', 'v', '8', '0')); - feature_sets.insert("character_variant_81", HB_TAG('c', 'v', '8', '1')); - feature_sets.insert("character_variant_82", HB_TAG('c', 'v', '8', '2')); - feature_sets.insert("character_variant_83", HB_TAG('c', 'v', '8', '3')); - feature_sets.insert("character_variant_84", HB_TAG('c', 'v', '8', '4')); - feature_sets.insert("character_variant_85", HB_TAG('c', 'v', '8', '5')); - feature_sets.insert("character_variant_86", HB_TAG('c', 'v', '8', '6')); - feature_sets.insert("character_variant_87", HB_TAG('c', 'v', '8', '7')); - feature_sets.insert("character_variant_88", HB_TAG('c', 'v', '8', '8')); - feature_sets.insert("character_variant_89", HB_TAG('c', 'v', '8', '9')); - feature_sets.insert("character_variant_90", HB_TAG('c', 'v', '9', '0')); - feature_sets.insert("character_variant_91", HB_TAG('c', 'v', '9', '1')); - feature_sets.insert("character_variant_92", HB_TAG('c', 'v', '9', '2')); - feature_sets.insert("character_variant_93", HB_TAG('c', 'v', '9', '3')); - feature_sets.insert("character_variant_94", HB_TAG('c', 'v', '9', '4')); - feature_sets.insert("character_variant_95", HB_TAG('c', 'v', '9', '5')); - feature_sets.insert("character_variant_96", HB_TAG('c', 'v', '9', '6')); - feature_sets.insert("character_variant_97", HB_TAG('c', 'v', '9', '7')); - feature_sets.insert("character_variant_98", HB_TAG('c', 'v', '9', '8')); - feature_sets.insert("character_variant_99", HB_TAG('c', 'v', '9', '9')); - feature_sets.insert("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c')); - feature_sets.insert("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c')); - feature_sets.insert("distances", HB_TAG('d', 'i', 's', 't')); - feature_sets.insert("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g')); - feature_sets.insert("denominators", HB_TAG('d', 'n', 'o', 'm')); - feature_sets.insert("dotless_forms", HB_TAG('d', 't', 'l', 's')); - feature_sets.insert("expert_forms", HB_TAG('e', 'x', 'p', 't')); - feature_sets.insert("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't')); - feature_sets.insert("terminal_forms_2", HB_TAG('f', 'i', 'n', '2')); - feature_sets.insert("terminal_forms_3", HB_TAG('f', 'i', 'n', '3')); - feature_sets.insert("terminal_forms", HB_TAG('f', 'i', 'n', 'a')); - feature_sets.insert("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c')); - feature_sets.insert("fractions", HB_TAG('f', 'r', 'a', 'c')); - feature_sets.insert("full_widths", HB_TAG('f', 'w', 'i', 'd')); - feature_sets.insert("half_forms", HB_TAG('h', 'a', 'l', 'f')); - feature_sets.insert("halant_forms", HB_TAG('h', 'a', 'l', 'n')); - feature_sets.insert("alternate_half_widths", HB_TAG('h', 'a', 'l', 't')); - feature_sets.insert("historical_forms", HB_TAG('h', 'i', 's', 't')); - feature_sets.insert("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a')); - feature_sets.insert("historical_ligatures", HB_TAG('h', 'l', 'i', 'g')); - feature_sets.insert("hangul", HB_TAG('h', 'n', 'g', 'l')); - feature_sets.insert("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o')); - feature_sets.insert("half_widths", HB_TAG('h', 'w', 'i', 'd')); - feature_sets.insert("initial_forms", HB_TAG('i', 'n', 'i', 't')); - feature_sets.insert("isolated_forms", HB_TAG('i', 's', 'o', 'l')); - feature_sets.insert("italics", HB_TAG('i', 't', 'a', 'l')); - feature_sets.insert("justification_alternates", HB_TAG('j', 'a', 'l', 't')); - feature_sets.insert("jis78_forms", HB_TAG('j', 'p', '7', '8')); - feature_sets.insert("jis83_forms", HB_TAG('j', 'p', '8', '3')); - feature_sets.insert("jis90_forms", HB_TAG('j', 'p', '9', '0')); - feature_sets.insert("jis2004_forms", HB_TAG('j', 'p', '0', '4')); - feature_sets.insert("kerning", HB_TAG('k', 'e', 'r', 'n')); - feature_sets.insert("left_bounds", HB_TAG('l', 'f', 'b', 'd')); - feature_sets.insert("standard_ligatures", HB_TAG('l', 'i', 'g', 'a')); - feature_sets.insert("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o')); - feature_sets.insert("lining_figures", HB_TAG('l', 'n', 'u', 'm')); - feature_sets.insert("localized_forms", HB_TAG('l', 'o', 'c', 'l')); - feature_sets.insert("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a')); - feature_sets.insert("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm')); - feature_sets.insert("mark_positioning", HB_TAG('m', 'a', 'r', 'k')); - feature_sets.insert("medial_forms_2", HB_TAG('m', 'e', 'd', '2')); - feature_sets.insert("medial_forms", HB_TAG('m', 'e', 'd', 'i')); - feature_sets.insert("mathematical_greek", HB_TAG('m', 'g', 'r', 'k')); - feature_sets.insert("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k')); - feature_sets.insert("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't')); - feature_sets.insert("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't')); - feature_sets.insert("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k')); - feature_sets.insert("nukta_forms", HB_TAG('n', 'u', 'k', 't')); - feature_sets.insert("numerators", HB_TAG('n', 'u', 'm', 'r')); - feature_sets.insert("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm')); - feature_sets.insert("optical_bounds", HB_TAG('o', 'p', 'b', 'd')); - feature_sets.insert("ordinals", HB_TAG('o', 'r', 'd', 'n')); - feature_sets.insert("ornaments", HB_TAG('o', 'r', 'n', 'm')); - feature_sets.insert("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't')); - feature_sets.insert("petite_capitals", HB_TAG('p', 'c', 'a', 'p')); - feature_sets.insert("proportional_kana", HB_TAG('p', 'k', 'n', 'a')); - feature_sets.insert("proportional_figures", HB_TAG('p', 'n', 'u', 'm')); - feature_sets.insert("pre_base_forms", HB_TAG('p', 'r', 'e', 'f')); - feature_sets.insert("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's')); - feature_sets.insert("post_base_forms", HB_TAG('p', 's', 't', 'f')); - feature_sets.insert("post_base_substitutions", HB_TAG('p', 's', 't', 's')); - feature_sets.insert("proportional_widths", HB_TAG('p', 'w', 'i', 'd')); - feature_sets.insert("quarter_widths", HB_TAG('q', 'w', 'i', 'd')); - feature_sets.insert("randomize", HB_TAG('r', 'a', 'n', 'd')); - feature_sets.insert("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't')); - feature_sets.insert("rakar_forms", HB_TAG('r', 'k', 'r', 'f')); - feature_sets.insert("required_ligatures", HB_TAG('r', 'l', 'i', 'g')); - feature_sets.insert("reph_forms", HB_TAG('r', 'p', 'h', 'f')); - feature_sets.insert("right_bounds", HB_TAG('r', 't', 'b', 'd')); - feature_sets.insert("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a')); - feature_sets.insert("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm')); - feature_sets.insert("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y')); - feature_sets.insert("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n')); - feature_sets.insert("stylistic_alternates", HB_TAG('s', 'a', 'l', 't')); - feature_sets.insert("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f')); - feature_sets.insert("optical_size", HB_TAG('s', 'i', 'z', 'e')); - feature_sets.insert("small_capitals", HB_TAG('s', 'm', 'c', 'p')); - feature_sets.insert("simplified_forms", HB_TAG('s', 'm', 'p', 'l')); - feature_sets.insert("stylistic_set_01", HB_TAG('s', 's', '0', '1')); - feature_sets.insert("stylistic_set_02", HB_TAG('s', 's', '0', '2')); - feature_sets.insert("stylistic_set_03", HB_TAG('s', 's', '0', '3')); - feature_sets.insert("stylistic_set_04", HB_TAG('s', 's', '0', '4')); - feature_sets.insert("stylistic_set_05", HB_TAG('s', 's', '0', '5')); - feature_sets.insert("stylistic_set_06", HB_TAG('s', 's', '0', '6')); - feature_sets.insert("stylistic_set_07", HB_TAG('s', 's', '0', '7')); - feature_sets.insert("stylistic_set_08", HB_TAG('s', 's', '0', '8')); - feature_sets.insert("stylistic_set_09", HB_TAG('s', 's', '0', '9')); - feature_sets.insert("stylistic_set_10", HB_TAG('s', 's', '1', '0')); - feature_sets.insert("stylistic_set_11", HB_TAG('s', 's', '1', '1')); - feature_sets.insert("stylistic_set_12", HB_TAG('s', 's', '1', '2')); - feature_sets.insert("stylistic_set_13", HB_TAG('s', 's', '1', '3')); - feature_sets.insert("stylistic_set_14", HB_TAG('s', 's', '1', '4')); - feature_sets.insert("stylistic_set_15", HB_TAG('s', 's', '1', '5')); - feature_sets.insert("stylistic_set_16", HB_TAG('s', 's', '1', '6')); - feature_sets.insert("stylistic_set_17", HB_TAG('s', 's', '1', '7')); - feature_sets.insert("stylistic_set_18", HB_TAG('s', 's', '1', '8')); - feature_sets.insert("stylistic_set_19", HB_TAG('s', 's', '1', '9')); - feature_sets.insert("stylistic_set_20", HB_TAG('s', 's', '2', '0')); - feature_sets.insert("math_script_style_alternates", HB_TAG('s', 's', 't', 'y')); - feature_sets.insert("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h')); - feature_sets.insert("subscript", HB_TAG('s', 'u', 'b', 's')); - feature_sets.insert("superscript", HB_TAG('s', 'u', 'p', 's')); - feature_sets.insert("swash", HB_TAG('s', 'w', 's', 'h')); - feature_sets.insert("titling", HB_TAG('t', 'i', 't', 'l')); - feature_sets.insert("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o')); - feature_sets.insert("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm')); - feature_sets.insert("tabular_figures", HB_TAG('t', 'n', 'u', 'm')); - feature_sets.insert("traditional_forms", HB_TAG('t', 'r', 'a', 'd')); - feature_sets.insert("third_widths", HB_TAG('t', 'w', 'i', 'd')); - feature_sets.insert("unicase", HB_TAG('u', 'n', 'i', 'c')); - feature_sets.insert("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't')); - feature_sets.insert("vattu_variants", HB_TAG('v', 'a', 't', 'u')); - feature_sets.insert("vertical_writing", HB_TAG('v', 'e', 'r', 't')); - feature_sets.insert("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l')); - feature_sets.insert("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o')); - feature_sets.insert("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a')); - feature_sets.insert("vertical_kerning", HB_TAG('v', 'k', 'r', 'n')); - feature_sets.insert("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l')); - feature_sets.insert("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2')); - feature_sets.insert("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r')); - feature_sets.insert("slashed_zero", HB_TAG('z', 'e', 'r', 'o')); + _insert_feature("access_all_alternates", HB_TAG('a', 'a', 'l', 't')); + _insert_feature("above_base_forms", HB_TAG('a', 'b', 'v', 'f')); + _insert_feature("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm')); + _insert_feature("above_base_substitutions", HB_TAG('a', 'b', 'v', 's')); + _insert_feature("alternative_fractions", HB_TAG('a', 'f', 'r', 'c')); + _insert_feature("akhands", HB_TAG('a', 'k', 'h', 'n')); + _insert_feature("below_base_forms", HB_TAG('b', 'l', 'w', 'f')); + _insert_feature("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm')); + _insert_feature("below_base_substitutions", HB_TAG('b', 'l', 'w', 's')); + _insert_feature("contextual_alternates", HB_TAG('c', 'a', 'l', 't')); + _insert_feature("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e')); + _insert_feature("glyph_composition", HB_TAG('c', 'c', 'm', 'p')); + _insert_feature("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r')); + _insert_feature("conjunct_forms", HB_TAG('c', 'j', 'c', 't')); + _insert_feature("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g')); + _insert_feature("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't')); + _insert_feature("capital_spacing", HB_TAG('c', 'p', 's', 'p')); + _insert_feature("contextual_swash", HB_TAG('c', 's', 'w', 'h')); + _insert_feature("cursive_positioning", HB_TAG('c', 'u', 'r', 's')); + _insert_feature("character_variant_01", HB_TAG('c', 'v', '0', '1')); + _insert_feature("character_variant_02", HB_TAG('c', 'v', '0', '2')); + _insert_feature("character_variant_03", HB_TAG('c', 'v', '0', '3')); + _insert_feature("character_variant_04", HB_TAG('c', 'v', '0', '4')); + _insert_feature("character_variant_05", HB_TAG('c', 'v', '0', '5')); + _insert_feature("character_variant_06", HB_TAG('c', 'v', '0', '6')); + _insert_feature("character_variant_07", HB_TAG('c', 'v', '0', '7')); + _insert_feature("character_variant_08", HB_TAG('c', 'v', '0', '8')); + _insert_feature("character_variant_09", HB_TAG('c', 'v', '0', '9')); + _insert_feature("character_variant_10", HB_TAG('c', 'v', '1', '0')); + _insert_feature("character_variant_11", HB_TAG('c', 'v', '1', '1')); + _insert_feature("character_variant_12", HB_TAG('c', 'v', '1', '2')); + _insert_feature("character_variant_13", HB_TAG('c', 'v', '1', '3')); + _insert_feature("character_variant_14", HB_TAG('c', 'v', '1', '4')); + _insert_feature("character_variant_15", HB_TAG('c', 'v', '1', '5')); + _insert_feature("character_variant_16", HB_TAG('c', 'v', '1', '6')); + _insert_feature("character_variant_17", HB_TAG('c', 'v', '1', '7')); + _insert_feature("character_variant_18", HB_TAG('c', 'v', '1', '8')); + _insert_feature("character_variant_19", HB_TAG('c', 'v', '1', '9')); + _insert_feature("character_variant_20", HB_TAG('c', 'v', '2', '0')); + _insert_feature("character_variant_21", HB_TAG('c', 'v', '2', '1')); + _insert_feature("character_variant_22", HB_TAG('c', 'v', '2', '2')); + _insert_feature("character_variant_23", HB_TAG('c', 'v', '2', '3')); + _insert_feature("character_variant_24", HB_TAG('c', 'v', '2', '4')); + _insert_feature("character_variant_25", HB_TAG('c', 'v', '2', '5')); + _insert_feature("character_variant_26", HB_TAG('c', 'v', '2', '6')); + _insert_feature("character_variant_27", HB_TAG('c', 'v', '2', '7')); + _insert_feature("character_variant_28", HB_TAG('c', 'v', '2', '8')); + _insert_feature("character_variant_29", HB_TAG('c', 'v', '2', '9')); + _insert_feature("character_variant_30", HB_TAG('c', 'v', '3', '0')); + _insert_feature("character_variant_31", HB_TAG('c', 'v', '3', '1')); + _insert_feature("character_variant_32", HB_TAG('c', 'v', '3', '2')); + _insert_feature("character_variant_33", HB_TAG('c', 'v', '3', '3')); + _insert_feature("character_variant_34", HB_TAG('c', 'v', '3', '4')); + _insert_feature("character_variant_35", HB_TAG('c', 'v', '3', '5')); + _insert_feature("character_variant_36", HB_TAG('c', 'v', '3', '6')); + _insert_feature("character_variant_37", HB_TAG('c', 'v', '3', '7')); + _insert_feature("character_variant_38", HB_TAG('c', 'v', '3', '8')); + _insert_feature("character_variant_39", HB_TAG('c', 'v', '3', '9')); + _insert_feature("character_variant_40", HB_TAG('c', 'v', '4', '0')); + _insert_feature("character_variant_41", HB_TAG('c', 'v', '4', '1')); + _insert_feature("character_variant_42", HB_TAG('c', 'v', '4', '2')); + _insert_feature("character_variant_43", HB_TAG('c', 'v', '4', '3')); + _insert_feature("character_variant_44", HB_TAG('c', 'v', '4', '4')); + _insert_feature("character_variant_45", HB_TAG('c', 'v', '4', '5')); + _insert_feature("character_variant_46", HB_TAG('c', 'v', '4', '6')); + _insert_feature("character_variant_47", HB_TAG('c', 'v', '4', '7')); + _insert_feature("character_variant_48", HB_TAG('c', 'v', '4', '8')); + _insert_feature("character_variant_49", HB_TAG('c', 'v', '4', '9')); + _insert_feature("character_variant_50", HB_TAG('c', 'v', '5', '0')); + _insert_feature("character_variant_51", HB_TAG('c', 'v', '5', '1')); + _insert_feature("character_variant_52", HB_TAG('c', 'v', '5', '2')); + _insert_feature("character_variant_53", HB_TAG('c', 'v', '5', '3')); + _insert_feature("character_variant_54", HB_TAG('c', 'v', '5', '4')); + _insert_feature("character_variant_55", HB_TAG('c', 'v', '5', '5')); + _insert_feature("character_variant_56", HB_TAG('c', 'v', '5', '6')); + _insert_feature("character_variant_57", HB_TAG('c', 'v', '5', '7')); + _insert_feature("character_variant_58", HB_TAG('c', 'v', '5', '8')); + _insert_feature("character_variant_59", HB_TAG('c', 'v', '5', '9')); + _insert_feature("character_variant_60", HB_TAG('c', 'v', '6', '0')); + _insert_feature("character_variant_61", HB_TAG('c', 'v', '6', '1')); + _insert_feature("character_variant_62", HB_TAG('c', 'v', '6', '2')); + _insert_feature("character_variant_63", HB_TAG('c', 'v', '6', '3')); + _insert_feature("character_variant_64", HB_TAG('c', 'v', '6', '4')); + _insert_feature("character_variant_65", HB_TAG('c', 'v', '6', '5')); + _insert_feature("character_variant_66", HB_TAG('c', 'v', '6', '6')); + _insert_feature("character_variant_67", HB_TAG('c', 'v', '6', '7')); + _insert_feature("character_variant_68", HB_TAG('c', 'v', '6', '8')); + _insert_feature("character_variant_69", HB_TAG('c', 'v', '6', '9')); + _insert_feature("character_variant_70", HB_TAG('c', 'v', '7', '0')); + _insert_feature("character_variant_71", HB_TAG('c', 'v', '7', '1')); + _insert_feature("character_variant_72", HB_TAG('c', 'v', '7', '2')); + _insert_feature("character_variant_73", HB_TAG('c', 'v', '7', '3')); + _insert_feature("character_variant_74", HB_TAG('c', 'v', '7', '4')); + _insert_feature("character_variant_75", HB_TAG('c', 'v', '7', '5')); + _insert_feature("character_variant_76", HB_TAG('c', 'v', '7', '6')); + _insert_feature("character_variant_77", HB_TAG('c', 'v', '7', '7')); + _insert_feature("character_variant_78", HB_TAG('c', 'v', '7', '8')); + _insert_feature("character_variant_79", HB_TAG('c', 'v', '7', '9')); + _insert_feature("character_variant_80", HB_TAG('c', 'v', '8', '0')); + _insert_feature("character_variant_81", HB_TAG('c', 'v', '8', '1')); + _insert_feature("character_variant_82", HB_TAG('c', 'v', '8', '2')); + _insert_feature("character_variant_83", HB_TAG('c', 'v', '8', '3')); + _insert_feature("character_variant_84", HB_TAG('c', 'v', '8', '4')); + _insert_feature("character_variant_85", HB_TAG('c', 'v', '8', '5')); + _insert_feature("character_variant_86", HB_TAG('c', 'v', '8', '6')); + _insert_feature("character_variant_87", HB_TAG('c', 'v', '8', '7')); + _insert_feature("character_variant_88", HB_TAG('c', 'v', '8', '8')); + _insert_feature("character_variant_89", HB_TAG('c', 'v', '8', '9')); + _insert_feature("character_variant_90", HB_TAG('c', 'v', '9', '0')); + _insert_feature("character_variant_91", HB_TAG('c', 'v', '9', '1')); + _insert_feature("character_variant_92", HB_TAG('c', 'v', '9', '2')); + _insert_feature("character_variant_93", HB_TAG('c', 'v', '9', '3')); + _insert_feature("character_variant_94", HB_TAG('c', 'v', '9', '4')); + _insert_feature("character_variant_95", HB_TAG('c', 'v', '9', '5')); + _insert_feature("character_variant_96", HB_TAG('c', 'v', '9', '6')); + _insert_feature("character_variant_97", HB_TAG('c', 'v', '9', '7')); + _insert_feature("character_variant_98", HB_TAG('c', 'v', '9', '8')); + _insert_feature("character_variant_99", HB_TAG('c', 'v', '9', '9')); + _insert_feature("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c')); + _insert_feature("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c')); + _insert_feature("distances", HB_TAG('d', 'i', 's', 't')); + _insert_feature("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g')); + _insert_feature("denominators", HB_TAG('d', 'n', 'o', 'm')); + _insert_feature("dotless_forms", HB_TAG('d', 't', 'l', 's')); + _insert_feature("expert_forms", HB_TAG('e', 'x', 'p', 't')); + _insert_feature("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't')); + _insert_feature("terminal_forms_2", HB_TAG('f', 'i', 'n', '2')); + _insert_feature("terminal_forms_3", HB_TAG('f', 'i', 'n', '3')); + _insert_feature("terminal_forms", HB_TAG('f', 'i', 'n', 'a')); + _insert_feature("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c')); + _insert_feature("fractions", HB_TAG('f', 'r', 'a', 'c')); + _insert_feature("full_widths", HB_TAG('f', 'w', 'i', 'd')); + _insert_feature("half_forms", HB_TAG('h', 'a', 'l', 'f')); + _insert_feature("halant_forms", HB_TAG('h', 'a', 'l', 'n')); + _insert_feature("alternate_half_widths", HB_TAG('h', 'a', 'l', 't')); + _insert_feature("historical_forms", HB_TAG('h', 'i', 's', 't')); + _insert_feature("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a')); + _insert_feature("historical_ligatures", HB_TAG('h', 'l', 'i', 'g')); + _insert_feature("hangul", HB_TAG('h', 'n', 'g', 'l')); + _insert_feature("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o')); + _insert_feature("half_widths", HB_TAG('h', 'w', 'i', 'd')); + _insert_feature("initial_forms", HB_TAG('i', 'n', 'i', 't')); + _insert_feature("isolated_forms", HB_TAG('i', 's', 'o', 'l')); + _insert_feature("italics", HB_TAG('i', 't', 'a', 'l')); + _insert_feature("justification_alternates", HB_TAG('j', 'a', 'l', 't')); + _insert_feature("jis78_forms", HB_TAG('j', 'p', '7', '8')); + _insert_feature("jis83_forms", HB_TAG('j', 'p', '8', '3')); + _insert_feature("jis90_forms", HB_TAG('j', 'p', '9', '0')); + _insert_feature("jis2004_forms", HB_TAG('j', 'p', '0', '4')); + _insert_feature("kerning", HB_TAG('k', 'e', 'r', 'n')); + _insert_feature("left_bounds", HB_TAG('l', 'f', 'b', 'd')); + _insert_feature("standard_ligatures", HB_TAG('l', 'i', 'g', 'a')); + _insert_feature("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o')); + _insert_feature("lining_figures", HB_TAG('l', 'n', 'u', 'm')); + _insert_feature("localized_forms", HB_TAG('l', 'o', 'c', 'l')); + _insert_feature("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a')); + _insert_feature("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm')); + _insert_feature("mark_positioning", HB_TAG('m', 'a', 'r', 'k')); + _insert_feature("medial_forms_2", HB_TAG('m', 'e', 'd', '2')); + _insert_feature("medial_forms", HB_TAG('m', 'e', 'd', 'i')); + _insert_feature("mathematical_greek", HB_TAG('m', 'g', 'r', 'k')); + _insert_feature("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k')); + _insert_feature("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't')); + _insert_feature("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't')); + _insert_feature("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k')); + _insert_feature("nukta_forms", HB_TAG('n', 'u', 'k', 't')); + _insert_feature("numerators", HB_TAG('n', 'u', 'm', 'r')); + _insert_feature("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm')); + _insert_feature("optical_bounds", HB_TAG('o', 'p', 'b', 'd')); + _insert_feature("ordinals", HB_TAG('o', 'r', 'd', 'n')); + _insert_feature("ornaments", HB_TAG('o', 'r', 'n', 'm')); + _insert_feature("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't')); + _insert_feature("petite_capitals", HB_TAG('p', 'c', 'a', 'p')); + _insert_feature("proportional_kana", HB_TAG('p', 'k', 'n', 'a')); + _insert_feature("proportional_figures", HB_TAG('p', 'n', 'u', 'm')); + _insert_feature("pre_base_forms", HB_TAG('p', 'r', 'e', 'f')); + _insert_feature("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's')); + _insert_feature("post_base_forms", HB_TAG('p', 's', 't', 'f')); + _insert_feature("post_base_substitutions", HB_TAG('p', 's', 't', 's')); + _insert_feature("proportional_widths", HB_TAG('p', 'w', 'i', 'd')); + _insert_feature("quarter_widths", HB_TAG('q', 'w', 'i', 'd')); + _insert_feature("randomize", HB_TAG('r', 'a', 'n', 'd')); + _insert_feature("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't')); + _insert_feature("rakar_forms", HB_TAG('r', 'k', 'r', 'f')); + _insert_feature("required_ligatures", HB_TAG('r', 'l', 'i', 'g')); + _insert_feature("reph_forms", HB_TAG('r', 'p', 'h', 'f')); + _insert_feature("right_bounds", HB_TAG('r', 't', 'b', 'd')); + _insert_feature("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a')); + _insert_feature("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm')); + _insert_feature("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y')); + _insert_feature("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n')); + _insert_feature("stylistic_alternates", HB_TAG('s', 'a', 'l', 't')); + _insert_feature("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f')); + _insert_feature("optical_size", HB_TAG('s', 'i', 'z', 'e')); + _insert_feature("small_capitals", HB_TAG('s', 'm', 'c', 'p')); + _insert_feature("simplified_forms", HB_TAG('s', 'm', 'p', 'l')); + _insert_feature("stylistic_set_01", HB_TAG('s', 's', '0', '1')); + _insert_feature("stylistic_set_02", HB_TAG('s', 's', '0', '2')); + _insert_feature("stylistic_set_03", HB_TAG('s', 's', '0', '3')); + _insert_feature("stylistic_set_04", HB_TAG('s', 's', '0', '4')); + _insert_feature("stylistic_set_05", HB_TAG('s', 's', '0', '5')); + _insert_feature("stylistic_set_06", HB_TAG('s', 's', '0', '6')); + _insert_feature("stylistic_set_07", HB_TAG('s', 's', '0', '7')); + _insert_feature("stylistic_set_08", HB_TAG('s', 's', '0', '8')); + _insert_feature("stylistic_set_09", HB_TAG('s', 's', '0', '9')); + _insert_feature("stylistic_set_10", HB_TAG('s', 's', '1', '0')); + _insert_feature("stylistic_set_11", HB_TAG('s', 's', '1', '1')); + _insert_feature("stylistic_set_12", HB_TAG('s', 's', '1', '2')); + _insert_feature("stylistic_set_13", HB_TAG('s', 's', '1', '3')); + _insert_feature("stylistic_set_14", HB_TAG('s', 's', '1', '4')); + _insert_feature("stylistic_set_15", HB_TAG('s', 's', '1', '5')); + _insert_feature("stylistic_set_16", HB_TAG('s', 's', '1', '6')); + _insert_feature("stylistic_set_17", HB_TAG('s', 's', '1', '7')); + _insert_feature("stylistic_set_18", HB_TAG('s', 's', '1', '8')); + _insert_feature("stylistic_set_19", HB_TAG('s', 's', '1', '9')); + _insert_feature("stylistic_set_20", HB_TAG('s', 's', '2', '0')); + _insert_feature("math_script_style_alternates", HB_TAG('s', 's', 't', 'y')); + _insert_feature("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h')); + _insert_feature("subscript", HB_TAG('s', 'u', 'b', 's')); + _insert_feature("superscript", HB_TAG('s', 'u', 'p', 's')); + _insert_feature("swash", HB_TAG('s', 'w', 's', 'h')); + _insert_feature("titling", HB_TAG('t', 'i', 't', 'l')); + _insert_feature("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o')); + _insert_feature("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm')); + _insert_feature("tabular_figures", HB_TAG('t', 'n', 'u', 'm')); + _insert_feature("traditional_forms", HB_TAG('t', 'r', 'a', 'd')); + _insert_feature("third_widths", HB_TAG('t', 'w', 'i', 'd')); + _insert_feature("unicase", HB_TAG('u', 'n', 'i', 'c')); + _insert_feature("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't')); + _insert_feature("vattu_variants", HB_TAG('v', 'a', 't', 'u')); + _insert_feature("vertical_writing", HB_TAG('v', 'e', 'r', 't')); + _insert_feature("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l')); + _insert_feature("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o')); + _insert_feature("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a')); + _insert_feature("vertical_kerning", HB_TAG('v', 'k', 'r', 'n')); + _insert_feature("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l')); + _insert_feature("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2')); + _insert_feature("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r')); + _insert_feature("slashed_zero", HB_TAG('z', 'e', 'r', 'o')); + // Registered OpenType variation tag. - feature_sets.insert("italic", HB_TAG('i', 't', 'a', 'l')); - feature_sets.insert("optical_size", HB_TAG('o', 'p', 's', 'z')); - feature_sets.insert("slant", HB_TAG('s', 'l', 'n', 't')); - feature_sets.insert("width", HB_TAG('w', 'd', 't', 'h')); - feature_sets.insert("weight", HB_TAG('w', 'g', 'h', 't')); + _insert_feature("italic", HB_TAG('i', 't', 'a', 'l')); + _insert_feature("optical_size", HB_TAG('o', 'p', 's', 'z')); + _insert_feature("slant", HB_TAG('s', 'l', 'n', 't')); + _insert_feature("width", HB_TAG('w', 'd', 't', 'h')); + _insert_feature("weight", HB_TAG('w', 'g', 'h', 't')); } -int32_t TextServerAdvanced::name_to_tag(const String &p_name) const { +int64_t TextServerAdvanced::name_to_tag(const String &p_name) const { if (feature_sets.has(p_name)) { return feature_sets[p_name]; } @@ -702,11 +740,9 @@ int32_t TextServerAdvanced::name_to_tag(const String &p_name) const { return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1); } -String TextServerAdvanced::tag_to_name(int32_t p_tag) const { - for (const KeyValue<StringName, int32_t> &E : feature_sets) { - if (E.value == p_tag) { - return E.key; - } +String TextServerAdvanced::tag_to_name(int64_t p_tag) const { + if (feature_sets_inv.has(p_tag)) { + return feature_sets_inv[p_tag]; } // No readable name, use tag string. @@ -720,7 +756,7 @@ String TextServerAdvanced::tag_to_name(int32_t p_tag) const { /* Font Glyph Rendering */ /*************************************************************************/ -_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontDataForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) const { +_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontDataForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const { FontTexturePosition ret; ret.index = -1; @@ -730,12 +766,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ for (int i = 0; i < p_data->textures.size(); i++) { const FontTexture &ct = p_data->textures[i]; - if (RenderingServer::get_singleton() != nullptr) { - if (ct.texture->get_format() != p_image_format) { - continue; - } - } - if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. continue; } @@ -744,7 +774,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ continue; } - ret.y = 0x7FFFFFFF; + ret.y = 0x7fffffff; ret.x = 0; for (int j = 0; j < ct.texture_w - mw; j++) { @@ -763,7 +793,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ } } - if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_h) { + if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) { continue; // Fail, could not fit it here. } @@ -777,16 +807,31 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ ret.y = 0; int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); - if (mw > texsize) { - texsize = mw; // Special case, adapt to it? - } - if (mh > texsize) { - texsize = mh; // Special case, adapt to it? - } +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(texsize); +#else texsize = next_power_of_2(texsize); - - texsize = MIN(texsize, 4096); +#endif + if (p_msdf) { + texsize = MIN(texsize, 2048); + } else { + texsize = MIN(texsize, 1024); + } + if (mw > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mw); +#else + texsize = next_power_of_2(mw); +#endif + } + if (mh > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mh); +#else + texsize = next_power_of_2(mh); +#endif + } FontTexture tex; tex.texture_w = texsize; @@ -817,8 +862,9 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ } } tex.offsets.resize(texsize); + int32_t *offw = tex.offsets.ptrw(); for (int i = 0; i < texsize; i++) { // Zero offsets. - tex.offsets.write[i] = 0; + offw[i] = 0; } p_data->textures.push_back(tex); @@ -832,8 +878,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ struct MSContext { msdfgen::Point2 position; - msdfgen::Shape *shape; - msdfgen::Contour *contour; + msdfgen::Shape *shape = nullptr; + msdfgen::Contour *contour = nullptr; }; class DistancePixelConversion { @@ -862,7 +908,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) { } static int ft_move_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); if (!(context->contour && context->contour->edges.empty())) { context->contour = &context->shape->addContour(); } @@ -871,7 +917,7 @@ static int ft_move_to(const FT_Vector *to, void *user) { } static int ft_line_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); msdfgen::Point2 endpoint = ft_point2(*to); if (endpoint != context->position) { context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint)); @@ -881,21 +927,21 @@ static int ft_line_to(const FT_Vector *to, void *user) { } static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to))); context->position = ft_point2(*to); return 0; } static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to))); context->position = ft_point2(*to); return 0; } void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const { - MSDFThreadData *td = (MSDFThreadData *)p_td; + MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td); msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape); int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y; @@ -948,13 +994,13 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( int w = (bounds.r - bounds.l); int h = (bounds.t - bounds.b); - int mw = w + p_rect_margin * 2; - int mh = h + p_rect_margin * 2; + int mw = w + p_rect_margin * 4; + int mh = h + p_rect_margin * 4; ERR_FAIL_COND_V(mw > 4096, FontGlyph()); ERR_FAIL_COND_V(mh > 4096, FontGlyph()); - FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh); + FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); FontTexture &tex = p_data->textures.write[tex_pos.index]; @@ -983,7 +1029,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { - int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4; + int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4; ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f)); wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f)); @@ -993,28 +1039,19 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata)); - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. + int32_t *offw = tex.offsets.ptrw(); for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - tex.offsets.write[k] = tex_pos.y + mh; + offw[k] = tex_pos.y + mh; } chr.texture_idx = tex_pos.index; - chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h); - chr.rect.position = Vector2(bounds.l, -bounds.t); + chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2); + chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin); + chr.rect.size = chr.uv_rect.size; } return chr; @@ -1026,8 +1063,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma int w = bitmap.width; int h = bitmap.rows; - int mw = w + p_rect_margin * 2; - int mh = h + p_rect_margin * 2; + int mw = w + p_rect_margin * 4; + int mh = h + p_rect_margin * 4; ERR_FAIL_COND_V(mw > 4096, FontGlyph()); ERR_FAIL_COND_V(mh > 4096, FontGlyph()); @@ -1035,7 +1072,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; - FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh); + FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); // Fit character in char texture. @@ -1047,7 +1084,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { - int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size; + int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size; ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); switch (bitmap.pixel_mode) { case FT_PIXEL_MODE_MONO: { @@ -1068,30 +1105,19 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma wr[ofs + 3] = bitmap.buffer[ofs_color + 3]; } break; default: - ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + "."); + ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + "."); break; } } } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata)); - - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. + int32_t *offw = tex.offsets.ptrw(); for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - tex.offsets.write[k] = tex_pos.y + mh; + offw[k] = tex_pos.y + mh; } FontGlyph chr; @@ -1099,8 +1125,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma chr.texture_idx = tex_pos.index; chr.found = true; - chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h); - chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling; + chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2); + chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling; chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling; return chr; } @@ -1113,12 +1139,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const { ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false); + int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts. + FontDataForSizeAdvanced *fd = p_font_data->cache[p_size]; if (fd->glyph_map.has(p_glyph)) { return fd->glyph_map[p_glyph].found; } - if (p_glyph == 0) { // Non graphical or invalid glyph, do not render. + if (glyph_index == 0) { // Non graphical or invalid glyph, do not render. fd->glyph_map[p_glyph] = FontGlyph(); return true; } @@ -1150,15 +1178,35 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d } FT_Fixed v, h; - FT_Get_Advance(fd->face, p_glyph, flags, &h); - FT_Get_Advance(fd->face, p_glyph, flags | FT_LOAD_VERTICAL_LAYOUT, &v); + FT_Get_Advance(fd->face, glyph_index, flags, &h); + FT_Get_Advance(fd->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v); - int error = FT_Load_Glyph(fd->face, p_glyph, flags); + int error = FT_Load_Glyph(fd->face, glyph_index, flags); if (error) { fd->glyph_map[p_glyph] = FontGlyph(); return false; } + if (!p_font_data->msdf) { + if ((p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && p_size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4; + FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0); + } else if ((p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && p_size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5; + FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0); + } + } + + if (p_font_data->embolden != 0.f) { + FT_Pos strength = p_font_data->embolden * p_size.x * 4; // 26.6 fractional units (1 / 64). + FT_Outline_Embolden(&fd->face->glyph->outline, strength); + } + + if (p_font_data->transform != Transform2D()) { + FT_Matrix mat = { FT_Fixed(p_font_data->transform[0][0] * 65536), FT_Fixed(p_font_data->transform[0][1] * 65536), FT_Fixed(p_font_data->transform[1][0] * 65536), FT_Fixed(p_font_data->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536). + FT_Outline_Transform(&fd->face->glyph->outline, &mat); + } + if (!outline) { if (!p_font_data->msdf) { error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); @@ -1178,7 +1226,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d } } else { FT_Stroker stroker; - if (FT_Stroker_New(library, &stroker) != 0) { + if (FT_Stroker_New(ft_library, &stroker) != 0) { fd->glyph_map[p_glyph] = FontGlyph(); ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker."); } @@ -1224,8 +1272,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced // Init dynamic font. #ifdef MODULE_FREETYPE_ENABLED int error = 0; - if (!library) { - error = FT_Init_FreeType(&library); + if (!ft_library) { + error = FT_Init_FreeType(&ft_library); ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); } @@ -1240,7 +1288,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced fargs.memory_size = p_font_data->data_size; fargs.flags = FT_OPEN_MEMORY; fargs.stream = &fd->stream; - error = FT_Open_Face(library, &fargs, 0, &fd->face); + error = FT_Open_Face(ft_library, &fargs, 0, &fd->face); if (error) { FT_Done_Face(fd->face); fd->face = nullptr; @@ -1248,9 +1296,9 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced } if (p_font_data->msdf) { - fd->oversampling = 1.0f; + fd->oversampling = 1.0; fd->size.x = p_font_data->msdf_source_size; - } else if (p_font_data->oversampling <= 0.0f) { + } else if (p_font_data->oversampling <= 0.0) { fd->oversampling = font_get_global_oversampling(); } else { fd->oversampling = p_font_data->oversampling; @@ -1259,19 +1307,19 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) { int best_match = 0; int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width)); - fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width; + fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width; for (int i = 1; i < fd->face->num_fixed_sizes; i++) { int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width)); if (ndiff < diff) { best_match = i; diff = ndiff; - fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width; + fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width; } } FT_Select_Size(fd->face, best_match); } else { - FT_Set_Pixel_Sizes(fd->face, 0, float(fd->size.x * fd->oversampling)); - fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem; + FT_Set_Pixel_Sizes(fd->face, 0, double(fd->size.x * fd->oversampling)); + fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem; } fd->hb_handle = hb_ft_font_create(fd->face, nullptr); @@ -1281,6 +1329,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; + hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform.columns[0][1]); + if (!p_font_data->face_init) { // Get style flags and name. if (fd->face->family_name != nullptr) { @@ -1564,7 +1614,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced for (FT_UInt i = 0; i < amaster->num_axis; i++) { p_font_data->supported_varaitions[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536); } - FT_Done_MM_Var(library, amaster); + FT_Done_MM_Var(ft_library, amaster); } p_font_data->face_init = true; } @@ -1586,17 +1636,17 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced // Reset to default. var.tag = amaster->axis[i].tag; - var.value = (double)amaster->axis[i].def / 65536.f; + var.value = (double)amaster->axis[i].def / 65536.0; coords.write[i] = amaster->axis[i].def; if (p_font_data->variation_coordinates.has(var.tag)) { var.value = p_font_data->variation_coordinates[var.tag]; - coords.write[i] = CLAMP(var.value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum); + coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } if (p_font_data->variation_coordinates.has(tag_to_name(var.tag))) { var.value = p_font_data->variation_coordinates[tag_to_name(var.tag)]; - coords.write[i] = CLAMP(var.value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum); + coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } hb_vars.push_back(var); @@ -1604,7 +1654,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw()); hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size()); - FT_Done_MM_Var(library, amaster); + FT_Done_MM_Var(ft_library, amaster); } #else ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); @@ -1628,7 +1678,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_fo p_font_data->supported_scripts.clear(); } -hb_font_t *TextServerAdvanced::_font_get_hb_handle(RID p_font_rid, int p_size) const { +hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, nullptr); @@ -1646,7 +1696,7 @@ RID TextServerAdvanced::create_font() { return font_owner.make_rid(fd); } -void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_data) { +void TextServerAdvanced::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1657,18 +1707,18 @@ void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_ fd->data_size = fd->data.size(); } -void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) { +void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); _font_clear_cache(fd); - fd->data.clear(); + fd->data.resize(0); fd->data_ptr = p_data_ptr; fd->data_size = p_data_size; } -void TextServerAdvanced::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) { +void TextServerAdvanced::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1678,7 +1728,7 @@ void TextServerAdvanced::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p fd->style_flags = p_style; } -uint32_t /*FontStyle*/ TextServerAdvanced::font_get_style(RID p_font_rid) const { +int64_t /*FontStyle*/ TextServerAdvanced::font_get_style(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1688,7 +1738,7 @@ uint32_t /*FontStyle*/ TextServerAdvanced::font_get_style(RID p_font_rid) const return fd->style_flags; } -void TextServerAdvanced::font_set_style_name(RID p_font_rid, const String &p_name) { +void TextServerAdvanced::font_set_style_name(const RID &p_font_rid, const String &p_name) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1698,7 +1748,7 @@ void TextServerAdvanced::font_set_style_name(RID p_font_rid, const String &p_nam fd->style_name = p_name; } -String TextServerAdvanced::font_get_style_name(RID p_font_rid) const { +String TextServerAdvanced::font_get_style_name(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1708,7 +1758,7 @@ String TextServerAdvanced::font_get_style_name(RID p_font_rid) const { return fd->style_name; } -void TextServerAdvanced::font_set_name(RID p_font_rid, const String &p_name) { +void TextServerAdvanced::font_set_name(const RID &p_font_rid, const String &p_name) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1718,7 +1768,7 @@ void TextServerAdvanced::font_set_name(RID p_font_rid, const String &p_name) { fd->font_name = p_name; } -String TextServerAdvanced::font_get_name(RID p_font_rid) const { +String TextServerAdvanced::font_get_name(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1728,7 +1778,7 @@ String TextServerAdvanced::font_get_name(RID p_font_rid) const { return fd->font_name; } -void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased) { +void TextServerAdvanced::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1739,7 +1789,7 @@ void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased } } -bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const { +bool TextServerAdvanced::font_is_antialiased(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1747,7 +1797,30 @@ bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const { return fd->antialiased; } -void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) { +void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->mipmaps != p_generate_mipmaps) { + for (KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) { + for (int i = 0; i < E.value->textures.size(); i++) { + E.value->textures.write[i].dirty = true; + } + } + fd->mipmaps = p_generate_mipmaps; + } +} + +bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, false); + + MutexLock lock(fd->mutex); + return fd->mipmaps; +} + +void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1758,7 +1831,7 @@ void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_ } } -bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_rid) const { +bool TextServerAdvanced::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1766,7 +1839,7 @@ bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_r return fd->msdf; } -void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) { +void TextServerAdvanced::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1777,7 +1850,7 @@ void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi } } -int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const { +int64_t TextServerAdvanced::font_get_msdf_pixel_range(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1785,7 +1858,7 @@ int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const { return fd->msdf_range; } -void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { +void TextServerAdvanced::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1796,7 +1869,7 @@ void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { } } -int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const { +int64_t TextServerAdvanced::font_get_msdf_size(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1804,17 +1877,15 @@ int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const { return fd->msdf_source_size; } -void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) { +void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->fixed_size != p_fixed_size) { - fd->fixed_size = p_fixed_size; - } + fd->fixed_size = p_fixed_size; } -int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const { +int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1822,7 +1893,7 @@ int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const { return fd->fixed_size; } -void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) { +void TextServerAdvanced::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1833,7 +1904,7 @@ void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_ } } -bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const { +bool TextServerAdvanced::font_is_force_autohinter(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1841,7 +1912,7 @@ bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const { return fd->force_autohinter; } -void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) { +void TextServerAdvanced::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1852,7 +1923,7 @@ void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_ } } -TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const { +TextServer::Hinting TextServerAdvanced::font_get_hinting(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, HINTING_NONE); @@ -1860,7 +1931,61 @@ TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const { return fd->hinting; } -void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) { +void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + fd->subpixel_positioning = p_subpixel; +} + +TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED); + + MutexLock lock(fd->mutex); + return fd->subpixel_positioning; +} + +void TextServerAdvanced::font_set_embolden(const RID &p_font_rid, double p_strength) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->embolden != p_strength) { + _font_clear_cache(fd); + fd->embolden = p_strength; + } +} + +double TextServerAdvanced::font_get_embolden(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0.0); + + MutexLock lock(fd->mutex); + return fd->embolden; +} + +void TextServerAdvanced::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->transform != p_transform) { + _font_clear_cache(fd); + fd->transform = p_transform; + } +} + +Transform2D TextServerAdvanced::font_get_transform(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Transform2D()); + + MutexLock lock(fd->mutex); + return fd->transform; +} + +void TextServerAdvanced::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1871,7 +1996,7 @@ void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Di } } -Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) const { +Dictionary TextServerAdvanced::font_get_variation_coordinates(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -1879,7 +2004,7 @@ Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) co return fd->variation_coordinates; } -void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampling) { +void TextServerAdvanced::font_set_oversampling(const RID &p_font_rid, double p_oversampling) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1890,27 +2015,27 @@ void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampl } } -float TextServerAdvanced::font_get_oversampling(RID p_font_rid) const { +double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); return fd->oversampling; } -Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const { +Array TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); MutexLock lock(fd->mutex); Array ret; - for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = fd->cache.front(); E; E = E->next()) { - ret.push_back(E->key()); + for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) { + ret.push_back(E.key); } return ret; } -void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) { +void TextServerAdvanced::font_clear_size_cache(const RID &p_font_rid) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1921,7 +2046,7 @@ void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) { fd->cache.clear(); } -void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1932,7 +2057,7 @@ void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i & } } -void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) { +void TextServerAdvanced::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1943,23 +2068,23 @@ void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_asc fd->cache[size]->ascent = p_ascent; } -float TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const { +double TextServerAdvanced::font_get_ascent(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->ascent; } } -void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_descent) { +void TextServerAdvanced::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1969,23 +2094,23 @@ void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_de fd->cache[size]->descent = p_descent; } -float TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const { +double TextServerAdvanced::font_get_descent(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->descent; } } -void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) { +void TextServerAdvanced::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1996,23 +2121,23 @@ void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, fd->cache[size]->underline_position = p_underline_position; } -float TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const { +double TextServerAdvanced::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->underline_position; } } -void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) { +void TextServerAdvanced::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2023,23 +2148,23 @@ void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size fd->cache[size]->underline_thickness = p_underline_thickness; } -float TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const { +double TextServerAdvanced::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->underline_thickness; } } -void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scale) { +void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2047,26 +2172,31 @@ void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scal Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); +#ifdef MODULE_FREETYPE_ENABLED + if (fd->cache[size]->face) { + return; // Do not override scale for dynamic fonts, it's calculated automatically. + } +#endif fd->cache[size]->scale = p_scale; } -float TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const { +double TextServerAdvanced::font_get_scale(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->scale / fd->cache[size]->oversampling; } } -void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) { +void TextServerAdvanced::font_set_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing, int64_t p_value) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2082,12 +2212,12 @@ void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer fd->cache[size]->spacing_space = p_value; } break; default: { - ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing)); + ERR_FAIL_MSG("Invalid spacing type: " + String::num_int64(p_spacing)); } break; } } -int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const { +int64_t TextServerAdvanced::font_get_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -2099,26 +2229,26 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer: switch (p_spacing) { case TextServer::SPACING_GLYPH: { if (fd->msdf) { - return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->spacing_glyph * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->spacing_glyph; } } break; case TextServer::SPACING_SPACE: { if (fd->msdf) { - return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->spacing_space * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->spacing_space; } } break; default: { - ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing)); + ERR_FAIL_V_MSG(0, "Invalid spacing type: " + String::num_int64(p_spacing)); } break; } return 0; } -int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const { +int64_t TextServerAdvanced::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -2130,7 +2260,7 @@ int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p return fd->cache[size]->textures.size(); } -void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2140,7 +2270,7 @@ void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_s fd->cache[size]->textures.clear(); } -void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) { +void TextServerAdvanced::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2152,7 +2282,7 @@ void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_s fd->cache[size]->textures.remove_at(p_texture_index); } -void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) { +void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND(p_image.is_null()); @@ -2172,13 +2302,20 @@ void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i & tex.texture_h = p_image->get_height(); tex.format = p_image->get_format(); - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata)); + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + tex.texture = Ref<ImageTexture>(); tex.texture.instantiate(); tex.texture->create_from_image(img); + tex.dirty = false; } -Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { +Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Ref<Image>()); @@ -2187,13 +2324,15 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vect ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>()); ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>()); - const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index]; - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata)); + const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); return img; } -void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) { +void TextServerAdvanced::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2209,7 +2348,7 @@ void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i tex.offsets = p_offset; } -PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { +PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -2218,11 +2357,11 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, co ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array()); - const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; return tex.offsets; } -Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const { +Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); @@ -2239,7 +2378,7 @@ Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_ return ret; } -void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2250,7 +2389,7 @@ void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz fd->cache[size]->glyph_map.clear(); } -void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) { +void TextServerAdvanced::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2261,7 +2400,21 @@ void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz fd->cache[size]->glyph_map.erase(p_glyph); } -Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const { +double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const { + const FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0.0); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, p_font_size); + + if (fd->embolden != 0.0) { + return fd->embolden * double(size.x) / 64.0; + } else { + return 0.0; + } +} + +Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2275,14 +2428,21 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, i const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + Vector2 ea; + if (fd->embolden != 0.0) { + ea.x = fd->embolden * double(size.x) / 64.0; + } + if (fd->msdf) { - return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size; + return (gl[p_glyph].advance + ea) * (double)p_size / (double)fd->msdf_source_size; + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + return (gl[p_glyph].advance + ea).round(); } else { - return gl[p_glyph].advance; + return gl[p_glyph].advance + ea; } } -void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) { +void TextServerAdvanced::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2297,7 +2457,7 @@ void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int3 gl[p_glyph].found = true; } -Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2312,13 +2472,13 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size; + return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size; } else { return gl[p_glyph].rect.position; } } -void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) { +void TextServerAdvanced::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2333,7 +2493,7 @@ void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p gl[p_glyph].found = true; } -Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2348,13 +2508,13 @@ Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i & const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size; + return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size; } else { return gl[p_glyph].rect.size; } } -void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) { +void TextServerAdvanced::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2369,7 +2529,7 @@ void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s gl[p_glyph].found = true; } -Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Rect2()); @@ -2385,7 +2545,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i return gl[p_glyph].uv_rect; } -void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) { +void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2400,7 +2560,7 @@ void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i & gl[p_glyph].found = true; } -int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, -1); @@ -2416,7 +2576,7 @@ int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2 return gl[p_glyph].texture_idx; } -void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) { +void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2431,7 +2591,87 @@ void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector gl[p_glyph].found = true; } -Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const { +RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, RID()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size_outline(fd, p_size); + + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID()); + if (!_ensure_glyph(fd, size, p_glyph)) { + return RID(); // Invalid or non graphicl glyph, do not display errors. + } + + const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID()); + + if (RenderingServer::get_singleton() != nullptr) { + if (gl[p_glyph].texture_idx != -1) { + if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } + return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid(); + } + } + + return RID(); +} + +Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Size2()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size_outline(fd, p_size); + + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2()); + if (!_ensure_glyph(fd, size, p_glyph)) { + return Size2(); // Invalid or non graphicl glyph, do not display errors. + } + + const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2()); + + if (RenderingServer::get_singleton() != nullptr) { + if (gl[p_glyph].texture_idx != -1) { + if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } + return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size(); + } + } + + return Size2(); +} + +Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2440,20 +2680,19 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_siz ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); - Vector<Vector3> points; - Vector<int32_t> contours; - bool orientation; #ifdef MODULE_FREETYPE_ENABLED - int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); - ERR_FAIL_COND_V(error, Dictionary()); + PackedVector3Array points; + PackedInt32Array contours; - points.clear(); - contours.clear(); + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. - float h = fd->cache[size]->ascent; - float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; + int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + ERR_FAIL_COND_V(error, Dictionary()); + + double h = fd->cache[size]->ascent; + double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; if (fd->msdf) { - scale = scale * (float)p_size / (float)fd->msdf_source_size; + scale = scale * (double)p_size / (double)fd->msdf_source_size; } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); @@ -2461,19 +2700,19 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_siz for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); } - orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); -#else - return Dictionary(); -#endif + bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); Dictionary out; out["points"] = points; out["contours"] = contours; out["orientation"] = orientation; return out; +#else + return Dictionary(); +#endif } -Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) const { +Array TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); @@ -2483,13 +2722,13 @@ Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) cons ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array()); Array ret; - for (const Map<Vector2i, Vector2>::Element *E = fd->cache[size]->kerning_map.front(); E; E = E->next()) { - ret.push_back(E->key()); + for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) { + ret.push_back(E.key); } return ret; } -void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) { +void TextServerAdvanced::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2500,7 +2739,7 @@ void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) { fd->cache[size]->kerning_map.clear(); } -void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) { +void TextServerAdvanced::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2511,7 +2750,7 @@ void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const V fd->cache[size]->kerning_map.erase(p_glyph_pair); } -void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { +void TextServerAdvanced::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2522,7 +2761,7 @@ void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vect fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; } -Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const { +Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2535,7 +2774,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V if (kern.has(p_glyph_pair)) { if (fd->msdf) { - return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size; + return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size; } else { return kern[p_glyph_pair]; } @@ -2545,7 +2784,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V FT_Vector delta; FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta); if (fd->msdf) { - return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size; + return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size; } else { return Vector2(delta.x, delta.y); } @@ -2555,7 +2794,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V return Vector2(); } -int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const { +int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); @@ -2573,14 +2812,14 @@ int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, cha return FT_Get_Char_Index(fd->cache[size]->face, p_char); } } else { - return 0; + return (int64_t)p_char; } #else - return (int32_t)p_char; + return (int64_t)p_char; #endif } -bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const { +bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); @@ -2599,7 +2838,7 @@ bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const { return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; } -String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const { +String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -2616,7 +2855,7 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const { FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex); while (gindex != 0) { if (charcode != 0) { - chars += char32_t(charcode); + chars = chars + String::chr(charcode); } charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex); } @@ -2627,13 +2866,13 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const { const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map; const int32_t *E = nullptr; while ((E = gl.next(E))) { - chars += char32_t(*E); + chars = chars + String::chr(*E); } } return chars; } -void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) { +void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + "."); @@ -2642,39 +2881,86 @@ void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_siz MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - for (char32_t i = p_start; i <= p_end; i++) { + for (int64_t i = p_start; i <= p_end; i++) { #ifdef MODULE_FREETYPE_ENABLED + int32_t idx = FT_Get_Char_Index(fd->cache[size]->face, i); if (fd->cache[size]->face) { - _ensure_glyph(fd, size, FT_Get_Char_Index(fd->cache[size]->face, i)); - continue; + if (fd->msdf) { + _ensure_glyph(fd, size, (int32_t)idx); + } else { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + } else { + _ensure_glyph(fd, size, (int32_t)idx); + } + } } #endif - _ensure_glyph(fd, size, (int32_t)i); } } -void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) { +void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - ERR_FAIL_COND(!_ensure_glyph(fd, size, p_index)); +#ifdef MODULE_FREETYPE_ENABLED + int32_t idx = p_index & 0xffffff; // Remove subpixel shifts. + if (fd->cache[size]->face) { + if (fd->msdf) { + _ensure_glyph(fd, size, (int32_t)idx); + } else { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + } else { + _ensure_glyph(fd, size, (int32_t)idx); + } + } + } +#endif } -void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { +void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - if (!_ensure_glyph(fd, size, p_index)) { + + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + +#ifdef MODULE_FREETYPE_ENABLED + if (!fd->msdf && fd->cache[size]->face) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); + index = index | (xshift << 27); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25)); + index = index | (xshift << 27); + } + } +#endif + + if (!_ensure_glyph(fd, size, index)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[p_index]; + const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); @@ -2686,14 +2972,38 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size; - Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size; + cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range); } else { - Point2 cpos = p_pos.floor(); + Point2 cpos = p_pos; + cpos.y = Math::floor(cpos.y); + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.125)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.25)); + } else { + cpos.x = Math::floor(cpos.x); + } cpos += gl.rect.position; Size2 csize = gl.rect.size; RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); @@ -2703,18 +3013,33 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz } } -void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { +void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size)); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - if (!_ensure_glyph(fd, size, p_index)) { + + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + +#ifdef MODULE_FREETYPE_ENABLED + if (!fd->msdf && fd->cache[size]->face) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); + index = index | (xshift << 27); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25)); + index = index | (xshift << 27); + } + } +#endif + + if (!_ensure_glyph(fd, size, index)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[p_index]; + const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); @@ -2726,14 +3051,38 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size; - Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size; + cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range); } else { - Point2 cpos = p_pos.floor(); + Point2 cpos = p_pos; + cpos.y = Math::floor(cpos.y); + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.125)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.25)); + } else { + cpos.x = Math::floor(cpos.x); + } cpos += gl.rect.position; Size2 csize = gl.rect.size; RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); @@ -2743,7 +3092,7 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i } } -bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String &p_language) const { +bool TextServerAdvanced::font_is_language_supported(const RID &p_font_rid, const String &p_language) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2755,7 +3104,7 @@ bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String } } -void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) { +void TextServerAdvanced::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2763,7 +3112,7 @@ void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, cons fd->language_support_overrides[p_language] = p_supported; } -bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, const String &p_language) { +bool TextServerAdvanced::font_get_language_support_override(const RID &p_font_rid, const String &p_language) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2771,7 +3120,7 @@ bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, cons return fd->language_support_overrides[p_language]; } -void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, const String &p_language) { +void TextServerAdvanced::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2779,19 +3128,19 @@ void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, c fd->language_support_overrides.erase(p_language); } -Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font_rid) { +PackedStringArray TextServerAdvanced::font_get_language_support_overrides(const RID &p_font_rid) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Vector<String>()); + ERR_FAIL_COND_V(!fd, PackedStringArray()); MutexLock lock(fd->mutex); - Vector<String> out; + PackedStringArray out; for (const KeyValue<String, bool> &E : fd->language_support_overrides) { out.push_back(E.key); } return out; } -bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &p_script) const { +bool TextServerAdvanced::font_is_script_supported(const RID &p_font_rid, const String &p_script) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2805,7 +3154,7 @@ bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String & } } -void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) { +void TextServerAdvanced::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2813,7 +3162,7 @@ void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const fd->script_support_overrides[p_script] = p_supported; } -bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const String &p_script) { +bool TextServerAdvanced::font_get_script_support_override(const RID &p_font_rid, const String &p_script) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2821,7 +3170,7 @@ bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const return fd->script_support_overrides[p_script]; } -void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, const String &p_script) { +void TextServerAdvanced::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2829,19 +3178,37 @@ void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, con fd->script_support_overrides.erase(p_script); } -Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_rid) { +PackedStringArray TextServerAdvanced::font_get_script_support_overrides(const RID &p_font_rid) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Vector<String>()); + ERR_FAIL_COND_V(!fd, PackedStringArray()); MutexLock lock(fd->mutex); - Vector<String> out; - for (const Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) { - out.push_back(E->key()); + PackedStringArray out; + for (const KeyValue<String, bool> &E : fd->script_support_overrides) { + out.push_back(E.key); } return out; } -Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const { +void TextServerAdvanced::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->feature_overrides = p_overrides; +} + +Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Dictionary()); + + MutexLock lock(fd->mutex); + return fd->feature_overrides; +} + +Dictionary TextServerAdvanced::font_supported_feature_list(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2851,7 +3218,7 @@ Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const return fd->supported_features; } -Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) const { +Dictionary TextServerAdvanced::font_supported_variation_list(const RID &p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2861,11 +3228,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) con return fd->supported_varaitions; } -float TextServerAdvanced::font_get_global_oversampling() const { +double TextServerAdvanced::font_get_global_oversampling() const { return oversampling; } -void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) { +void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) { _THREAD_SAFE_METHOD_ if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -2883,7 +3250,7 @@ void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) { List<RID> text_bufs; shaped_owner.get_owned_list(&text_bufs); for (const RID &E : text_bufs) { - invalidate(shaped_owner.get_or_null(E)); + invalidate(shaped_owner.get_or_null(E), false); } } } @@ -2893,10 +3260,23 @@ void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) { /* Shaped text buffer interface */ /*************************************************************************/ -int TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const { - int32_t limit = p_pos; +int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const { + int64_t limit = p_pos; + if (p_utf32.length() != p_utf16.length()) { + const UChar *data = p_utf16.ptr(); + for (int i = 0; i < p_pos; i++) { + if (U16_IS_LEAD(data[i])) { + limit--; + } + } + } + return limit; +} + +int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const { + int64_t limit = p_pos; if (p_sd->text.length() != p_sd->utf16.length()) { - const UChar *data = p_sd->utf16.ptr(); + const UChar *data = p_sd->utf16.get_data(); for (int i = 0; i < p_pos; i++) { if (U16_IS_LEAD(data[i])) { limit--; @@ -2906,11 +3286,11 @@ int TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int p_p return limit; } -int TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const { - int32_t limit = p_pos; +int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const { + int64_t limit = p_pos; if (p_sd->text.length() != p_sd->utf16.length()) { for (int i = 0; i < p_pos; i++) { - if (p_sd->text[i] > 0xFFFF) { + if (p_sd->text[i] > 0xffff) { limit++; } } @@ -2918,42 +3298,47 @@ int TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int return limit; } -void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped) { +void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped, bool p_text) { p_shaped->valid = false; p_shaped->sort_valid = false; p_shaped->line_breaks_valid = false; p_shaped->justification_ops_valid = false; p_shaped->text_trimmed = false; - p_shaped->ascent = 0.f; - p_shaped->descent = 0.f; - p_shaped->width = 0.f; - p_shaped->upos = 0.f; - p_shaped->uthk = 0.f; + p_shaped->ascent = 0.0; + p_shaped->descent = 0.0; + p_shaped->width = 0.0; + p_shaped->upos = 0.0; + p_shaped->uthk = 0.0; p_shaped->glyphs.clear(); p_shaped->glyphs_logical.clear(); p_shaped->overrun_trim_data = TrimData(); p_shaped->utf16 = Char16String(); - if (p_shaped->script_iter != nullptr) { - memdelete(p_shaped->script_iter); - p_shaped->script_iter = nullptr; - } for (int i = 0; i < p_shaped->bidi_iter.size(); i++) { ubidi_close(p_shaped->bidi_iter[i]); } p_shaped->bidi_iter.clear(); + + if (p_text) { + if (p_shaped->script_iter != nullptr) { + memdelete(p_shaped->script_iter); + p_shaped->script_iter = nullptr; + } + p_shaped->break_ops_valid = false; + p_shaped->js_ops_valid = false; + } } void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) { ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent); - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : parent->objects) { + for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : parent->objects) { if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) { p_shaped->objects[E.key] = E.value; } } - for (int k = 0; k < parent->spans.size(); k++) { - ShapedTextDataAdvanced::Span span = parent->spans[k]; + for (int i = 0; i < parent->spans.size(); i++) { + ShapedTextDataAdvanced::Span span = parent->spans[i]; if (span.start >= p_shaped->end || span.end <= p_shaped->start) { continue; } @@ -2974,7 +3359,7 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te return shaped_owner.make_rid(sd); } -void TextServerAdvanced::shaped_text_clear(RID p_shaped) { +void TextServerAdvanced::shaped_text_clear(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2986,10 +3371,10 @@ void TextServerAdvanced::shaped_text_clear(RID p_shaped) { sd->spans.clear(); sd->objects.clear(); sd->bidi_override.clear(); - invalidate(sd); + invalidate(sd, true); } -void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) { +void TextServerAdvanced::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2999,11 +3384,11 @@ void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Dir full_copy(sd); } sd->direction = p_direction; - invalidate(sd); + invalidate(sd, false); } } -TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped) const { +TextServer::Direction TextServerAdvanced::shaped_text_get_direction(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); @@ -3011,7 +3396,15 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped return sd->direction; } -void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { +TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(const RID &p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); + + MutexLock lock(sd->mutex); + return sd->para_direction; +} + +void TextServerAdvanced::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3021,18 +3414,18 @@ void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const full_copy(sd); } sd->custom_punct = p_punct; - invalidate(sd); + invalidate(sd, false); } } -String TextServerAdvanced::shaped_text_get_custom_punctuation(RID p_shaped) const { +String TextServerAdvanced::shaped_text_get_custom_punctuation(const RID &p_shaped) const { _THREAD_SAFE_METHOD_ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, String()); return sd->custom_punct; } -void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { +void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3042,12 +3435,14 @@ void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array } sd->bidi_override.clear(); for (int i = 0; i < p_override.size(); i++) { - sd->bidi_override.push_back(p_override[i]); + if (p_override[i].get_type() == Variant::VECTOR2I) { + sd->bidi_override.push_back(p_override[i]); + } } - invalidate(sd); + invalidate(sd, false); } -void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) { +void TextServerAdvanced::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3057,11 +3452,11 @@ void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::O full_copy(sd); } sd->orientation = p_orientation; - invalidate(sd); + invalidate(sd, false); } } -void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) { +void TextServerAdvanced::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3069,11 +3464,11 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e ERR_FAIL_COND(sd->parent != RID()); if (sd->preserve_invalid != p_enabled) { sd->preserve_invalid = p_enabled; - invalidate(sd); + invalidate(sd, false); } } -bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const { +bool TextServerAdvanced::shaped_text_get_preserve_invalid(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3081,7 +3476,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const { return sd->preserve_invalid; } -void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) { +void TextServerAdvanced::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3091,11 +3486,11 @@ void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_e full_copy(sd); } sd->preserve_control = p_enabled; - invalidate(sd); + invalidate(sd, false); } } -bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const { +bool TextServerAdvanced::shaped_text_get_preserve_control(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3103,7 +3498,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const { return sd->preserve_control; } -TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_shaped) const { +TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL); @@ -3111,7 +3506,41 @@ TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_sh return sd->orientation; } -bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { +int64_t TextServerAdvanced::shaped_get_span_count(const RID &p_shaped) const { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0); + return sd->spans.size(); +} + +Variant TextServerAdvanced::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, Variant()); + ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant()); + return sd->spans[p_index].meta; +} + +void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + ERR_FAIL_INDEX(p_index, sd->spans.size()); + + ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index]; + bool changed = (span.font_size != p_size) || (span.features != p_opentype_features) || (p_fonts.size() != span.fonts.size()); + if (!changed) { + for (int i = 0; i < p_fonts.size(); i++) { + changed = changed || (span.fonts[i] != p_fonts[i]); + } + } + if (changed) { + span.fonts = p_fonts; + span.font_size = p_size; + span.features = p_opentype_features; + + invalidate(sd, false); + } +} + +bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); ERR_FAIL_COND_V(p_size <= 0, false); @@ -3136,16 +3565,17 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te span.font_size = p_size; span.language = p_language; span.features = p_opentype_features; + span.meta = p_meta; sd->spans.push_back(span); - sd->text += p_text; + sd->text = sd->text + p_text; sd->end += p_text.length(); - invalidate(sd); + invalidate(sd, true); return true; } -bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) { +bool TextServerAdvanced::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3167,16 +3597,16 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con obj.pos = span.start; sd->spans.push_back(span); - sd->text += String::chr(0xfffc).repeat(p_length); + sd->text = sd->text + String::chr(0xfffc).repeat(p_length); sd->end += p_length; sd->objects[p_key] = obj; - invalidate(sd); + invalidate(sd, true); return true; } -bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerAdvanced::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -3196,7 +3626,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) { if (E.value.pos == gl.start) { key = E.key; break; @@ -3229,85 +3659,88 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { - sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); - sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); } } sd->width += gl.advance * gl.repeat; } } + _realign(sd); + } + return true; +} - // Align embedded objects to baseline. - float full_ascent = sd->ascent; - float full_descent = sd->descent; - for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { - if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) { - if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.y = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.y = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.y = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.y = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.y -= E.value.rect.size.y; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.y -= E.value.rect.size.y / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.y); - full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); - } else { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.x = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.x = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.x = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.x = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.x -= E.value.rect.size.x; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.x -= E.value.rect.size.x / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.x); - full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); +void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const { + // Align embedded objects to baseline. + double full_ascent = p_sd->ascent; + double full_descent = p_sd->descent; + for (KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) { + if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) { + if (p_sd->orientation == ORIENTATION_HORIZONTAL) { + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.y = -p_sd->ascent; + } break; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2; + } break; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.y = 0; + } break; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.y = p_sd->descent; + } break; } + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.y -= E.value.rect.size.y; + } break; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.y -= E.value.rect.size.y / 2; + } break; + case INLINE_ALIGNMENT_TOP_TO: { + // NOP + } break; + } + full_ascent = MAX(full_ascent, -E.value.rect.position.y); + full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); + } else { + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.x = -p_sd->ascent; + } break; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2; + } break; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.x = 0; + } break; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.x = p_sd->descent; + } break; + } + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.x -= E.value.rect.size.x; + } break; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.x -= E.value.rect.size.x / 2; + } break; + case INLINE_ALIGNMENT_TOP_TO: { + // NOP + } break; + } + full_ascent = MAX(full_ascent, -E.value.rect.position.x); + full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); } } - sd->ascent = full_ascent; - sd->descent = full_descent; } - return true; + p_sd->ascent = full_ascent; + p_sd->descent = full_descent; } -RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_length) const { +RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); @@ -3338,7 +3771,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng return shaped_owner.make_rid(new_sd); } -bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const { +bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const { if (p_new_sd->valid) { return true; } @@ -3397,7 +3830,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S Variant key; bool find_embedded = false; if (gl.count == 1) { - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : p_sd->objects) { + for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) { if (E.value.pos == gl.start) { find_embedded = true; key = E.key; @@ -3428,8 +3861,8 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) { p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { - p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); - p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); + p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); } } p_new_sd->width += gl.advance * gl.repeat; @@ -3440,79 +3873,14 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S } } - // Align embedded objects to baseline. - float full_ascent = p_new_sd->ascent; - float full_descent = p_new_sd->descent; - for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : p_new_sd->objects) { - if ((E.value.pos >= p_new_sd->start) && (E.value.pos < p_new_sd->end)) { - if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.y = -p_new_sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.y = (-p_new_sd->ascent + p_new_sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.y = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.y = p_new_sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.y -= E.value.rect.size.y; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.y -= E.value.rect.size.y / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.y); - full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); - } else { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.x = -p_new_sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.x = (-p_new_sd->ascent + p_new_sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.x = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.x = p_new_sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.x -= E.value.rect.size.x; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.x -= E.value.rect.size.x / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.x); - full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); - } - } - } - p_new_sd->ascent = full_ascent; - p_new_sd->descent = full_descent; + _realign(p_new_sd); } p_new_sd->valid = true; return true; } -RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const { +RID TextServerAdvanced::shaped_text_get_parent(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); @@ -3520,9 +3888,9 @@ RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const { return sd->parent; } -float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) { +double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -3561,19 +3929,24 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, } } - float justification_width; + double justification_width; if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) { if (sd->overrun_trim_data.trim_pos >= 0) { - start_pos = sd->overrun_trim_data.trim_pos; + if (sd->para_direction == DIRECTION_RTL) { + start_pos = sd->overrun_trim_data.trim_pos; + } else { + end_pos = sd->overrun_trim_data.trim_pos; + } justification_width = sd->width_trimmed; } else { - return sd->width; + return Math::ceil(sd->width); } } else { justification_width = sd->width; } if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) { + // Trim spaces. while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat; sd->glyphs.write[start_pos].advance = 0; @@ -3584,6 +3957,14 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, sd->glyphs.write[end_pos].advance = 0; end_pos -= sd->glyphs[end_pos].count; } + } else { + // Skip breaks, but do not reset size. + while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { + start_pos += sd->glyphs[start_pos].count; + } + while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { + end_pos -= sd->glyphs[end_pos].count; + } } int space_count = 0; @@ -3592,7 +3973,10 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, const Glyph &gl = sd->glyphs[i]; if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) { - elongation_count++; + if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) { + // Expand once per elongation sequence. + elongation_count++; + } } if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { space_count++; @@ -3601,32 +3985,37 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, } if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) { - float delta_width_per_kashida = (p_width - justification_width) / elongation_count; + double delta_width_per_kashida = (p_width - justification_width) / elongation_count; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { if (((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) { - int count = delta_width_per_kashida / gl.advance; - int prev_count = gl.repeat; - if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { - gl.repeat = MAX(count, 0); + if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) { + // Expand once per elongation sequence. + int count = delta_width_per_kashida / gl.advance; + int prev_count = gl.repeat; + if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + gl.repeat = MAX(count, 0); + } else { + gl.repeat = MAX(count + 1, 1); + } + justification_width += (gl.repeat - prev_count) * gl.advance; } - justification_width += (gl.repeat - prev_count) * gl.advance; } } } } - float adv_remain = 0; if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) { - float delta_width_per_space = (p_width - justification_width) / space_count; + double delta_width_per_space = (p_width - justification_width) / space_count; + double adv_remain = 0; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { - float old_adv = gl.advance; - float new_advance; + double old_adv = gl.advance; + double new_advance; if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { - new_advance = MAX(gl.advance + delta_width_per_space, 0.f); + new_advance = MAX(gl.advance + delta_width_per_space, 0.0); } else { new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size); } @@ -3653,12 +4042,12 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, sd->width = justification_width; } - return sd->width; + return Math::ceil(justification_width); } -float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) { +double TextServerAdvanced::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -3668,8 +4057,14 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3 const_cast<TextServerAdvanced *>(this)->shaped_text_update_breaks(p_shaped); } + for (int i = 0; i < p_tab_stops.size(); i++) { + if (p_tab_stops[i] <= 0) { + return 0.0; + } + } + int tab_index = 0; - float off = 0.f; + double off = 0.0; int start, end, delta; if (sd->para_direction == DIRECTION_LTR) { @@ -3686,7 +4081,7 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3 for (int i = start; i != end; i += delta) { if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { - float tab_off = 0.f; + double tab_off = 0.0; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; tab_index++; @@ -3694,7 +4089,7 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3 tab_index = 0; } } - float old_adv = gl[i].advance; + double old_adv = gl[i].advance; gl[i].advance = tab_off - off; sd->width += gl[i].advance - old_adv; off = 0; @@ -3703,10 +4098,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3 off += gl[i].advance * gl[i].repeat; } - return 0.f; + return 0.0; } -void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) { +void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, int64_t p_trim_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); @@ -3735,23 +4130,56 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl return; } + Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans; + if (sd->parent != RID()) { + ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); + ERR_FAIL_COND(!parent_sd->valid); + spans = parent_sd->spans; + } + + if (spans.size() == 0) { + 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; - int32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, last_gl_font_size, '.'); - Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, dot_gl_idx); - int32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, last_gl_font_size, ' '); - Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, whitespace_gl_idx); + + // Find usable fonts, if fonts from the last glyph do not have required chars. + RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(dot_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (font_has_char(fonts[i], '.')) { + dot_gl_font_rid = fonts[i]; + break; + } + } + } + RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(whitespace_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (font_has_char(fonts[i], ' ')) { + whitespace_gl_font_rid = fonts[i]; + break; + } + } + } + + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; - if (add_ellipsis) { - ellipsis_width = 3 * dot_adv.x + font_get_spacing(last_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { + ellipsis_width = 3 * dot_adv.x + font_get_spacing(whitespace_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; - float width = sd->width; + double width = sd->width; - bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL); + bool is_rtl = sd->para_direction == DIRECTION_RTL; int trim_pos = (is_rtl) ? sd_size : 0; int ellipsis_pos = (enforce_ellipsis) ? 0 : -1; @@ -3809,23 +4237,25 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl gl.count = 1; gl.advance = whitespace_adv.x; gl.index = whitespace_gl_idx; - gl.font_rid = last_gl_font_rid; + gl.font_rid = whitespace_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); sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } // Add ellipsis dots. - Glyph gl; - gl.count = 1; - gl.repeat = 3; - 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); - - sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + if (dot_gl_idx != 0) { + Glyph gl; + gl.count = 1; + gl.repeat = 3; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = dot_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + + sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + } } sd->text_trimmed = true; @@ -3833,7 +4263,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl } } -int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const { +int64_t TextServerAdvanced::shaped_text_get_trim_pos(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); @@ -3841,7 +4271,7 @@ int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const { return sd->overrun_trim_data.trim_pos; } -int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const { +int64_t TextServerAdvanced::shaped_text_get_ellipsis_pos(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); @@ -3849,7 +4279,7 @@ int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const { return sd->overrun_trim_data.ellipsis_pos; } -const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) const { +const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid."); @@ -3857,7 +4287,7 @@ const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) c return sd->overrun_trim_data.ellipsis_glyph_buf.ptr(); } -int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const { +int64_t TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid."); @@ -3865,7 +4295,7 @@ int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const return sd->overrun_trim_data.ellipsis_glyph_buf.size(); } -bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { +bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3878,44 +4308,45 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { return true; // Nothing to do. } - const UChar *data = sd->utf16.ptr(); + const UChar *data = sd->utf16.get_data(); - HashMap<int, bool> breaks; - UErrorCode err = U_ZERO_ERROR; - int i = 0; - while (i < sd->spans.size()) { - String language = sd->spans[i].language; - int r_start = sd->spans[i].start; - while (i + 1 < sd->spans.size() && language == sd->spans[i + 1].language) { - i++; - } - int r_end = sd->spans[i].end; - UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err); - if (U_FAILURE(err)) { - // No data loaded - use fallback. - for (int j = r_start; j < r_end; j++) { - char32_t c = sd->text[j - sd->start]; - if (is_whitespace(c)) { - breaks[j] = false; - } - if (is_linebreak(c)) { - breaks[j] = true; - } + if (!sd->break_ops_valid) { + sd->breaks.clear(); + UErrorCode err = U_ZERO_ERROR; + int i = 0; + while (i < sd->spans.size()) { + String language = sd->spans[i].language; + int r_start = sd->spans[i].start; + while (i + 1 < sd->spans.size() && language == sd->spans[i + 1].language) { + i++; } - } else { - while (ubrk_next(bi) != UBRK_DONE) { - int pos = _convert_pos(sd, ubrk_current(bi)) + r_start - 1; - if (pos != r_end) { + int r_end = sd->spans[i].end; + UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err); + if (U_FAILURE(err)) { + // No data loaded - use fallback. + for (int j = r_start; j < r_end; j++) { + char32_t c = sd->text[j - sd->start]; + if (is_whitespace(c)) { + sd->breaks[j + 1] = false; + } + if (is_linebreak(c)) { + sd->breaks[j + 1] = true; + } + } + } else { + while (ubrk_next(bi) != UBRK_DONE) { + int pos = _convert_pos(sd, ubrk_current(bi)) + r_start; if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) { - breaks[pos] = true; + sd->breaks[pos] = true; } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) { - breaks[pos] = false; + sd->breaks[pos] = false; } } } + ubrk_close(bi); + i++; } - ubrk_close(bi); - i++; + sd->break_ops_valid = true; } sd->sort_valid = false; @@ -3927,7 +4358,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { int c_punct_size = sd->custom_punct.length(); const char32_t *c_punct = sd->custom_punct.ptr(); - for (i = 0; i < sd_size; i++) { + for (int i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = ch[sd_glyphs[i].start - sd->start]; if (c == 0xfffc) { @@ -3940,7 +4371,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } if (c_punct_size == 0) { - if (u_ispunct(c) && c != 0x005F) { + if (u_ispunct(c) && c != 0x005f) { sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; } } else { @@ -3954,34 +4385,46 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_underscore(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; } - if (breaks.has(sd->glyphs[i].start)) { - if (breaks[sd->glyphs[i].start]) { + if (sd->breaks.has(sd_glyphs[i].end)) { + if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + } else if (is_whitespace(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } else { - if (is_whitespace(c)) { - sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; + int count = sd_glyphs[i].count; + // Do not add extra space at the end of the line. + if (sd_glyphs[i].end == sd->end) { + continue; + } + // Do not add extra space after existing space. + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { + if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; + } } else { - Glyph gl; - gl.start = sd_glyphs[i].start; - gl.end = sd_glyphs[i].end; - gl.count = 1; - gl.font_rid = sd_glyphs[i].font_rid; - gl.font_size = sd_glyphs[i].font_size; - gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; - if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) { - gl.flags |= GRAPHEME_IS_RTL; - sd->glyphs.insert(i, gl); // Insert before. - } else { - sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after. + if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; } - - // Update write pointer and size. - sd_size = sd->glyphs.size(); - sd_glyphs = sd->glyphs.ptrw(); - - i += sd_glyphs[i].count; - continue; } + Glyph gl; + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; + gl.count = 1; + gl.font_rid = sd_glyphs[i].font_rid; + gl.font_size = sd_glyphs[i].font_size; + gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE; + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { + gl.flags |= GRAPHEME_IS_RTL; + sd->glyphs.insert(i, gl); // Insert before. + } else { + sd->glyphs.insert(i + count, gl); // Insert after. + } + i += count; + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); + continue; } } @@ -3994,10 +4437,10 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { return sd->line_breaks_valid; } -_FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_data, int p_start, int p_end) { - int kashida_pos = -1; +_FORCE_INLINE_ int64_t _generate_kashida_justification_opportunies(const String &p_data, int64_t p_start, int64_t p_end) { + int64_t kashida_pos = -1; int8_t priority = 100; - int i = p_start; + int64_t i = p_start; char32_t pc = 0; @@ -4013,7 +4456,7 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d priority = 0; } if (priority >= 1 && i < p_end - 1) { - if (is_seen_sad(c) && (p_data[i + 1] != 0x200C)) { + if (is_seen_sad(c) && (p_data[i + 1] != 0x200c)) { kashida_pos = i; priority = 1; } @@ -4069,7 +4512,7 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d return kashida_pos; } -bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { +bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -4085,95 +4528,126 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { return true; // Nothing to do. } - const UChar *data = sd->utf16.ptr(); - int32_t data_size = sd->utf16.length(); + const UChar *data = sd->utf16.get_data(); + int data_size = sd->utf16.length(); - Map<int, bool> jstops; + if (!sd->js_ops_valid) { + sd->jstops.clear(); - // Use ICU word iterator and custom kashida detection. - UErrorCode err = U_ZERO_ERROR; - UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err); - if (U_FAILURE(err)) { - // No data - use fallback. - int limit = 0; - for (int i = 0; i < sd->text.length(); i++) { - if (is_whitespace(data[i])) { - int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start; - if (ks != -1) { - jstops[ks] = true; - } - limit = i + 1; + // Use ICU word iterator and custom kashida detection. + UErrorCode err = U_ZERO_ERROR; + UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err); + if (U_FAILURE(err)) { + // No data - use fallback. + int limit = 0; + for (int i = 0; i < sd->text.length(); i++) { + if (is_whitespace(data[i])) { + int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start; + if (ks != -1) { + sd->jstops[ks] = true; + } + limit = i + 1; + } } - } - int ks = _generate_kashida_justification_opportunies(sd->text, limit, sd->text.length()) + sd->start; - if (ks != -1) { - jstops[ks] = true; - } - } else { - int limit = 0; - while (ubrk_next(bi) != UBRK_DONE) { - if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) { - int i = _convert_pos(sd, ubrk_current(bi)); - jstops[i + sd->start] = false; - int ks = _generate_kashida_justification_opportunies(sd->text, limit, i); - if (ks != -1) { - jstops[ks + sd->start] = true; - } - limit = i; + int ks = _generate_kashida_justification_opportunies(sd->text, limit, sd->text.length()) + sd->start; + if (ks != -1) { + sd->jstops[ks] = true; } + } else { + int limit = 0; + while (ubrk_next(bi) != UBRK_DONE) { + if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) { + int i = _convert_pos(sd, ubrk_current(bi)); + sd->jstops[i + sd->start] = false; + int ks = _generate_kashida_justification_opportunies(sd->text, limit, i); + if (ks != -1) { + sd->jstops[ks + sd->start] = true; + } + limit = i; + } + } + ubrk_close(bi); } - ubrk_close(bi); + + sd->js_ops_valid = true; } sd->sort_valid = false; sd->glyphs_logical.clear(); - int sd_size = sd->glyphs.size(); - if (jstops.size() > 0) { + Glyph *sd_glyphs = sd->glyphs.ptrw(); + int sd_size = sd->glyphs.size(); + if (sd->jstops.size() > 0) { for (int i = 0; i < sd_size; i++) { - if (sd->glyphs[i].count > 0) { - if (jstops.has(sd->glyphs[i].start)) { - char32_t c = sd->text[sd->glyphs[i].start - sd->start]; + if (sd_glyphs[i].count > 0) { + char32_t c = sd->text[sd_glyphs[i].start - sd->start]; + if (c == 0x0640) { + sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION; + } + if (sd->jstops.has(sd_glyphs[i].start)) { if (c == 0xfffc) { continue; } - if (jstops[sd->glyphs[i].start]) { - if (c == 0x0640) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION; - } else { - if (sd->glyphs[i].font_rid != RID()) { + if (sd->jstops[sd_glyphs[i].start]) { + if (c != 0x0640) { + if (sd_glyphs[i].font_rid != RID()) { Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size); - if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { - gl.start = sd->glyphs[i].start; - gl.end = sd->glyphs[i].end; + if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; gl.repeat = 0; gl.count = 1; if (sd->orientation == ORIENTATION_HORIZONTAL) { - gl.y_off = sd->glyphs[i].y_off; + gl.y_off = sd_glyphs[i].y_off; } else { - gl.x_off = sd->glyphs[i].x_off; + gl.x_off = sd_glyphs[i].x_off; } gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL; sd->glyphs.insert(i, gl); i++; + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); + continue; } } } - } else if (!is_whitespace(c)) { + } else if ((sd_glyphs[i].flags & GRAPHEME_IS_SPACE) != GRAPHEME_IS_SPACE) { + int count = sd_glyphs[i].count; + // Do not add extra spaces at the end of the line. + if (sd_glyphs[i].end == sd->end) { + continue; + } + // Do not add extra space after existing space. + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { + if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; + } + } else { + if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; + } + } + // Inject virtual space for alignment. Glyph gl; - gl.start = sd->glyphs[i].start; - gl.end = sd->glyphs[i].end; + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; gl.count = 1; - gl.font_rid = sd->glyphs[i].font_rid; - gl.font_size = sd->glyphs[i].font_size; + gl.font_rid = sd_glyphs[i].font_rid; + gl.font_size = sd_glyphs[i].font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL; - if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) { + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { gl.flags |= GRAPHEME_IS_RTL; sd->glyphs.insert(i, gl); // Insert before. } else { - sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after. + sd->glyphs.insert(i + count, gl); // Insert after. } - i += sd->glyphs[i].count; + i += count; + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); continue; } } @@ -4185,8 +4659,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { return sd->justification_ops_valid; } -Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) { +Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) { hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size); + bool subpos = (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); ERR_FAIL_COND_V(hb_font == nullptr, Glyph()); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -4212,16 +4687,24 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char gl.font_size = p_font_size; if (glyph_count > 0) { - float scale = font_get_scale(p_font, p_font_size); + double scale = font_get_scale(p_font, p_font_size); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale)); + if (subpos) { + gl.advance = glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size); + } else { + gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size)); + } } else { gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / scale)); } gl.count = 1; gl.index = glyph_info[0].codepoint; - gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / scale)); + if (subpos) { + gl.x_off = glyph_pos[0].x_offset / (64.0 / scale); + } else { + gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / scale)); + } gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / scale)); if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) { @@ -4231,7 +4714,27 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char return gl; } -void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index) { +_FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) { + Array keys = p_source.keys(); + Array values = p_source.values(); + for (int i = 0; i < keys.size(); i++) { + int32_t value = values[i]; + if (value >= 0) { + hb_feature_t feature; + if (keys[i].get_type() == Variant::STRING) { + feature.tag = name_to_tag(keys[i]); + } else { + feature.tag = keys[i]; + } + feature.value = value; + feature.start = 0; + feature.end = -1; + r_ftrs.push_back(feature); + } + } +} + +void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index) { int fs = p_sd->spans[p_span].font_size; if (p_fb_index >= p_fonts.size()) { // Add fallback glyphs. @@ -4252,8 +4755,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y); } else { gl.advance = get_hex_code_box_size(fs, gl.index).y; - p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); - p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); + p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5)); + p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5)); } p_sd->width += gl.advance; @@ -4264,10 +4767,14 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } RID f = p_fonts[p_fb_index]; + FontDataAdvanced *fd = font_owner.get_or_null(f); + Vector2i fss = _get_size(fd, fs); hb_font_t *hb_font = _font_get_hb_handle(f, fs); - float scale = font_get_scale(f, fs); - float sp_sp = font_get_spacing(f, fs, SPACING_SPACE); - float sp_gl = font_get_spacing(f, fs, SPACING_GLYPH); + double scale = font_get_scale(f, fs); + double sp_sp = font_get_spacing(f, fs, SPACING_SPACE); + double sp_gl = font_get_spacing(f, fs, SPACING_GLYPH); + double ea = _get_extra_advance(f, fs); + bool subpos = (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); ERR_FAIL_COND(hb_font == nullptr); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -4287,17 +4794,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start); Vector<hb_feature_t> ftrs; - for (const Variant *ftr = p_sd->spans[p_span].features.next(nullptr); ftr != nullptr; ftr = p_sd->spans[p_span].features.next(ftr)) { - double values = p_sd->spans[p_span].features[*ftr]; - if (values >= 0) { - hb_feature_t feature; - feature.tag = *ftr; - feature.value = values; - feature.start = 0; - feature.end = -1; - ftrs.push_back(feature); - } - } + _add_featuers(font_get_opentype_feature_overrides(f), ftrs); + _add_featuers(p_sd->spans[p_span].features, ftrs); + hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size()); unsigned int glyph_count = 0; @@ -4351,12 +4850,21 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.index = glyph_info[i].codepoint; if (gl.index != 0) { + _ensure_glyph(fd, fss, gl.index); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale)); + if (subpos) { + gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea; + } else { + gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale) + ea); + } } else { gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / scale)); } - gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale)); + if (subpos) { + gl.x_off = glyph_pos[i].x_offset / (64.0 / scale); + } else { + gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale)); + } gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / scale)); } if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) { @@ -4400,7 +4908,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off); p_sd->descent = MAX(p_sd->descent, w[i + j].y_off); } else { - float gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); + double gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); p_sd->ascent = MAX(p_sd->ascent, gla); p_sd->descent = MAX(p_sd->descent, gla); } @@ -4430,7 +4938,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } } -bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { +bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -4439,7 +4947,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { return true; } - invalidate(sd); + invalidate(sd, false); if (sd->parent != RID()) { shaped_text_shape(sd->parent); ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); @@ -4454,7 +4962,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } sd->utf16 = sd->text.utf16(); - const UChar *data = sd->utf16.ptr(); + const UChar *data = sd->utf16.get_data(); // Create script iterator. if (sd->script_iter == nullptr) { @@ -4573,9 +5081,9 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } sd->glyphs.push_back(gl); } else { - Vector<RID> fonts; - Vector<RID> fonts_scr_only; - Vector<RID> fonts_no_match; + Array fonts; + Array fonts_scr_only; + Array 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)) { @@ -4598,75 +5106,12 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } } - // Align embedded objects to baseline. - float full_ascent = sd->ascent; - float full_descent = sd->descent; - for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { - if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.y = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.y = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.y = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.y = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.y -= E.value.rect.size.y; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.y -= E.value.rect.size.y / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.y); - full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); - } else { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.x = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.x = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.x = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.x = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.x -= E.value.rect.size.x; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.x -= E.value.rect.size.x / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.x); - full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); - } - } - sd->ascent = full_ascent; - sd->descent = full_descent; + _realign(sd); sd->valid = true; return sd->valid; } -bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const { +bool TextServerAdvanced::shaped_text_is_ready(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -4674,7 +5119,7 @@ bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const { return sd->valid; } -const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const { +const Glyph *TextServerAdvanced::shaped_text_get_glyphs(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); @@ -4685,7 +5130,7 @@ const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const { return sd->glyphs.ptr(); } -int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const { +int64_t TextServerAdvanced::shaped_text_get_glyph_count(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); @@ -4696,7 +5141,7 @@ int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const { return sd->glyphs.size(); } -const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) { +const Glyph *TextServerAdvanced::shaped_text_sort_logical(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); @@ -4714,7 +5159,7 @@ const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) { return sd->glyphs_logical.ptr(); } -Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const { +Vector2i TextServerAdvanced::shaped_text_get_range(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Vector2i()); @@ -4722,20 +5167,20 @@ Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const { return Vector2(sd->start, sd->end); } -Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const { +Array TextServerAdvanced::shaped_text_get_objects(const RID &p_shaped) const { Array ret; const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, ret); MutexLock lock(sd->mutex); - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) { ret.push_back(E.key); } return ret; } -Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const { +Rect2 TextServerAdvanced::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Rect2()); @@ -4747,7 +5192,7 @@ Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_ke return sd->objects[p_key].rect; } -Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const { +Size2 TextServerAdvanced::shaped_text_get_size(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Size2()); @@ -4756,15 +5201,15 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const { const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { - return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent); + return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent).ceil(); } else { - return Size2(sd->ascent + sd->descent, (sd->text_trimmed ? sd->width_trimmed : sd->width)); + return Size2(sd->ascent + sd->descent, (sd->text_trimmed ? sd->width_trimmed : sd->width)).ceil(); } } -float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const { +double TextServerAdvanced::shaped_text_get_ascent(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -4773,9 +5218,9 @@ float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const { return sd->ascent; } -float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const { +double TextServerAdvanced::shaped_text_get_descent(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -4784,20 +5229,20 @@ float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const { return sd->descent; } -float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const { +double TextServerAdvanced::shaped_text_get_width(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); } - return (sd->text_trimmed ? sd->width_trimmed : sd->width); + return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width); } -float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const { +double TextServerAdvanced::shaped_text_get_underline_position(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -4807,9 +5252,9 @@ float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const return sd->upos; } -float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const { +double TextServerAdvanced::shaped_text_get_underline_thickness(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -5006,7 +5451,7 @@ String TextServerAdvanced::format_number(const String &p_string, const String &p res.replace("e", num_systems[i].exp); res.replace("E", num_systems[i].exp); char32_t *data = res.ptrw(); - for (int j = 0; j < res.size(); j++) { + for (int j = 0; j < res.length(); j++) { if (data[j] >= 0x30 && data[j] <= 0x39) { data[j] = num_systems[i].digits[data[j] - 0x30]; } else if (data[j] == '.' || data[j] == ',') { @@ -5030,7 +5475,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_ } res.replace(num_systems[i].exp, "e"); char32_t *data = res.ptrw(); - for (int j = 0; j < res.size(); j++) { + for (int j = 0; j < res.length(); j++) { if (data[j] == num_systems[i].digits[10]) { data[j] = '.'; } else { @@ -5072,13 +5517,13 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const { Char16String utf16 = p_string.utf16(); // Normalize. - Char16String normalized; + Vector<char16_t> normalized; err = U_ZERO_ERROR; - int32_t len = unorm2_normalize(unorm, utf16.ptr(), -1, nullptr, 0, &err); + int32_t len = unorm2_normalize(unorm, utf16.get_data(), -1, nullptr, 0, &err); ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err)); normalized.resize(len); err = U_ZERO_ERROR; - unorm2_normalize(unorm, utf16.ptr(), -1, normalized.ptrw(), len, &err); + unorm2_normalize(unorm, utf16.get_data(), -1, normalized.ptrw(), len, &err); ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err)); // Convert back to UTF-32. @@ -5088,12 +5533,93 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const { String result; for (int i = 0; i < normalized_string.length(); i++) { if (u_getCombiningClass(normalized_string[i]) == 0) { - result += normalized_string[i]; + result = result + normalized_string[i]; } } return result; } +String TextServerAdvanced::string_to_upper(const String &p_string, const String &p_language) const { + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + Vector<char16_t> upper; + UErrorCode err = U_ZERO_ERROR; + int32_t len = u_strToUpper(nullptr, 0, utf16.get_data(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err)); + upper.resize(len); + err = U_ZERO_ERROR; + u_strToUpper(upper.ptrw(), len, utf16.get_data(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err)); + + // Convert back to UTF-32. + return String::utf16(upper.ptr(), len); +} + +String TextServerAdvanced::string_to_lower(const String &p_string, const String &p_language) const { + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + Vector<char16_t> lower; + UErrorCode err = U_ZERO_ERROR; + int32_t len = u_strToLower(nullptr, 0, utf16.get_data(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err)); + lower.resize(len); + err = U_ZERO_ERROR; + u_strToLower(lower.ptrw(), len, utf16.get_data(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err)); + + // Convert back to UTF-32. + return String::utf16(lower.ptr(), len); +} + +PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_string, const String &p_language) const { + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + Set<int> breaks; + UErrorCode err = U_ZERO_ERROR; + UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.ptr(), utf16.length(), &err); + if (U_FAILURE(err)) { + // No data loaded - use fallback. + for (int i = 0; i < p_string.length(); i++) { + char32_t c = p_string[i]; + if (is_whitespace(c) || is_linebreak(c)) { + breaks.insert(i); + } + } + } else { + while (ubrk_next(bi) != UBRK_DONE) { + int pos = _convert_pos(p_string, utf16, ubrk_current(bi)) - 1; + if (pos != p_string.length() - 1) { + breaks.insert(pos); + } + } + } + ubrk_close(bi); + + PackedInt32Array ret; + for (int i = 0; i < p_string.length(); i++) { + char32_t c = p_string[i]; + if (c == 0xfffc) { + continue; + } + if (u_ispunct(c) && c != 0x005F) { + ret.push_back(i); + continue; + } + if (is_underscore(c)) { + ret.push_back(i); + continue; + } + if (breaks.has(i)) { + ret.push_back(i); + continue; + } + } + return ret; +} + TextServerAdvanced::TextServerAdvanced() { _insert_num_systems_lang(); _insert_feature_sets(); @@ -5102,14 +5628,8 @@ TextServerAdvanced::TextServerAdvanced() { TextServerAdvanced::~TextServerAdvanced() { _bmp_free_font_funcs(); - if (library != nullptr) { - FT_Done_FreeType(library); + if (ft_library != nullptr) { + FT_Done_FreeType(ft_library); } u_cleanup(); -#ifndef ICU_STATIC_DATA - if (icu_data != nullptr) { - memfree(icu_data); - icu_data = nullptr; - } -#endif } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 9a22180f39..1b4293aa72 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,13 +36,61 @@ /* shaping and advanced font features support. */ /*************************************************************************/ -#include "servers/text_server.h" +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/godot.hpp> + +#include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/mutex_lock.hpp> + +#include <godot_cpp/variant/array.hpp> +#include <godot_cpp/variant/dictionary.hpp> +#include <godot_cpp/variant/packed_int32_array.hpp> +#include <godot_cpp/variant/packed_string_array.hpp> +#include <godot_cpp/variant/packed_vector2_array.hpp> +#include <godot_cpp/variant/rect2.hpp> +#include <godot_cpp/variant/rid.hpp> +#include <godot_cpp/variant/string.hpp> +#include <godot_cpp/variant/vector2.hpp> +#include <godot_cpp/variant/vector2i.hpp> + +#include <godot_cpp/classes/text_server.hpp> +#include <godot_cpp/classes/text_server_extension.hpp> +#include <godot_cpp/classes/text_server_manager.hpp> + +#include <godot_cpp/classes/caret_info.hpp> +#include <godot_cpp/classes/global_constants_binds.hpp> +#include <godot_cpp/classes/glyph.hpp> +#include <godot_cpp/classes/image.hpp> +#include <godot_cpp/classes/image_texture.hpp> +#include <godot_cpp/classes/ref.hpp> + +#include <godot_cpp/templates/hash_map.hpp> +#include <godot_cpp/templates/map.hpp> +#include <godot_cpp/templates/rid_owner.hpp> +#include <godot_cpp/templates/set.hpp> +#include <godot_cpp/templates/thread_work_pool.hpp> +#include <godot_cpp/templates/vector.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. #include "core/templates/rid_owner.h" #include "core/templates/thread_work_pool.h" #include "scene/resources/texture.h" +#include "servers/text/text_server_extension.h" + +#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. + +#endif + #include "script_iterator.h" +// Thirdparty headers. + #include <unicode/ubidi.h> #include <unicode/ubrk.h> #include <unicode/uchar.h> @@ -55,8 +103,6 @@ #include <unicode/ustring.h> #include <unicode/utypes.h> -#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. - #ifdef MODULE_FREETYPE_ENABLED #include <ft2build.h> #include FT_FREETYPE_H @@ -73,12 +119,11 @@ #include <hb-icu.h> #include <hb.h> -class TextServerAdvanced : public TextServer { - GDCLASS(TextServerAdvanced, TextServer); - _THREAD_SAFE_CLASS_ +/*************************************************************************/ - static String interface_name; - static uint32_t interface_features; +class TextServerAdvanced : public TextServerExtension { + GDCLASS(TextServerAdvanced, TextServerExtension); + _THREAD_SAFE_CLASS_ struct NumSystemData { Set<StringName> lang; @@ -89,21 +134,23 @@ class TextServerAdvanced : public TextServer { Vector<NumSystemData> num_systems; Map<StringName, int32_t> feature_sets; + Map<int32_t, StringName> feature_sets_inv; void _insert_num_systems_lang(); void _insert_feature_sets(); + _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag); // ICU support data. - uint8_t *icu_data = nullptr; + bool icu_data_loaded = false; // Font cache data. #ifdef MODULE_FREETYPE_ENABLED - mutable FT_Library library = nullptr; + mutable FT_Library ft_library = nullptr; #endif - const int rect_range = 2; + const int rect_range = 1; struct FontTexture { Image::Format format; @@ -112,6 +159,7 @@ class TextServerAdvanced : public TextServer { int texture_h = 0; PackedInt32Array offsets; Ref<ImageTexture> texture; + bool dirty = true; }; struct FontTexturePosition { @@ -129,12 +177,12 @@ class TextServerAdvanced : public TextServer { }; struct FontDataForSizeAdvanced { - float ascent = 0.f; - float descent = 0.f; - float underline_position = 0.f; - float underline_thickness = 0.f; - float scale = 1.f; - float oversampling = 1.f; + double ascent = 0.0; + double descent = 0.0; + double underline_position = 0.0; + double underline_thickness = 0.0; + double scale = 1.0; + double oversampling = 1.0; int spacing_glyph = 0; int spacing_space = 0; @@ -168,14 +216,18 @@ class TextServerAdvanced : public TextServer { Mutex mutex; bool antialiased = true; + bool mipmaps = false; bool msdf = false; int msdf_range = 14; int msdf_source_size = 48; int fixed_size = 0; bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; + TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; Dictionary variation_coordinates; - float oversampling = 0.f; + double oversampling = 0.0; + double embolden = 0.0; + Transform2D transform; uint32_t style_flags = 0; String font_name; @@ -187,6 +239,7 @@ class TextServerAdvanced : public TextServer { Set<uint32_t> supported_scripts; Dictionary supported_features; Dictionary supported_varaitions; + Dictionary feature_overrides; // Language/script support override. Map<String, bool> language_support_overrides; @@ -199,14 +252,14 @@ class TextServerAdvanced : public TextServer { ~FontDataAdvanced() { work_pool.finish(); - for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = cache.front(); E; E = E->next()) { - memdelete(E->get()); + for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : cache) { + memdelete(E.value); } cache.clear(); } }; - _FORCE_INLINE_ FontTexturePosition find_texture_pos_for_glyph(FontDataForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) const; + _FORCE_INLINE_ FontTexturePosition find_texture_pos_for_glyph(FontDataForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const; #ifdef MODULE_MSDFGEN_ENABLED _FORCE_INLINE_ FontGlyph rasterize_msdf(FontDataAdvanced *p_font_data, FontDataForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const; #endif @@ -238,9 +291,76 @@ class TextServerAdvanced : public TextServer { } } + _FORCE_INLINE_ double _get_extra_advance(RID p_font_rid, int p_font_size) const; + // Shaped text cache data. + struct TrimData { + int trim_pos = -1; + int ellipsis_pos = -1; + Vector<Glyph> ellipsis_glyph_buf; + }; + + struct ShapedTextDataAdvanced { + Mutex mutex; + + /* Source data */ + RID parent; // Substring parent ShapedTextData. + + int start = 0; // Substring start offset in the parent string. + int end = 0; // Substring end offset in the parent string. + + String text; + String custom_punct; + TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. + TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; + + struct Span { + int start = -1; + int end = -1; + + Array fonts; + int font_size = 0; + + Variant embedded_key; + + String language; + Dictionary features; + Variant meta; + }; + Vector<Span> spans; + + struct EmbeddedObject { + int pos = 0; + InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER; + Rect2 rect; + }; + Map<Variant, EmbeddedObject> objects; + + /* Shaped data */ + TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. + bool valid = false; // String is shaped. + bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). + bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. + bool sort_valid = false; + bool text_trimmed = false; + + bool preserve_invalid = true; // Draw hex code box instead of missing characters. + bool preserve_control = false; // Draw control characters. + + double ascent = 0.0; // Ascent for horizontal layout, 1/2 of width for vertical. + double descent = 0.0; // Descent for horizontal layout, 1/2 of width for vertical. + double width = 0.0; // Width for horizontal layout, height for vertical. + double width_trimmed = 0.0; + + double upos = 0.0; + double uthk = 0.0; + + TrimData overrun_trim_data; + bool fit_width_minimum_reached = false; + + Vector<Glyph> glyphs; + Vector<Glyph> glyphs_logical; - struct ShapedTextDataAdvanced : public ShapedTextData { /* Intermediate data */ Char16String utf16; Vector<UBiDi *> bidi_iter; @@ -248,6 +368,11 @@ class TextServerAdvanced : public TextServer { ScriptIterator *script_iter = nullptr; hb_buffer_t *hb_buffer = nullptr; + HashMap<int, bool> jstops; + HashMap<int, bool> breaks; + bool break_ops_valid = false; + bool js_ops_valid = false; + ~ShapedTextDataAdvanced() { for (int i = 0; i < bidi_iter.size(); i++) { ubidi_close(bidi_iter[i]); @@ -263,15 +388,19 @@ class TextServerAdvanced : public TextServer { // Common data. - float oversampling = 1.f; + double oversampling = 1.0; mutable RID_PtrOwner<FontDataAdvanced> font_owner; mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner; - int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const; - int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const; - bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const; - void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index); - Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size); + void _realign(ShapedTextDataAdvanced *p_sd) const; + int64_t _convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const; + int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const; + int64_t _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const; + bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const; + void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index); + Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size); + + _FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs); // HarfBuzz bitmap font interface. @@ -296,19 +425,38 @@ class TextServerAdvanced : public TextServer { static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); static hb_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy); + hb_font_t *_font_get_hb_handle(const RID &p_font, int64_t p_font_size) const; + + struct GlyphCompare { // For line breaking reordering. + _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const { + if (l.start == r.start) { + if (l.count == r.count) { + if ((l.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { + return false; + } else { + return true; + } + } + return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant. + } else { + return l.start < r.start; + } + } + }; + protected: static void _bind_methods(){}; void full_copy(ShapedTextDataAdvanced *p_shaped); - void invalidate(ShapedTextDataAdvanced *p_shaped); + void invalidate(ShapedTextDataAdvanced *p_shaped, bool p_text = false); public: virtual bool has_feature(Feature p_feature) const override; virtual String get_name() const override; - virtual uint32_t get_features() const override; + virtual int64_t get_features() const override; - virtual void free(RID p_rid) override; - virtual bool has(RID p_rid) override; + virtual void free_rid(const RID &p_rid) override; + virtual bool has(const RID &p_rid) override; virtual bool load_support_data(const String &p_filename) override; virtual String get_support_data_filename() const override; @@ -317,210 +465,236 @@ public: virtual bool is_locale_right_to_left(const String &p_locale) const override; - virtual int32_t name_to_tag(const String &p_name) const override; - virtual String tag_to_name(int32_t p_tag) const override; + virtual int64_t name_to_tag(const String &p_name) const override; + virtual String tag_to_name(int64_t p_tag) const override; /* Font interface */ virtual RID create_font() override; - virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override; - virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override; + virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; + virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + + virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override; + virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override; + + virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override; + virtual String font_get_style_name(const RID &p_font_rid) const override; - virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override; - virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override; + virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; + virtual String font_get_name(const RID &p_font_rid) const override; - virtual void font_set_style_name(RID p_font_rid, const String &p_name) override; - virtual String font_get_style_name(RID p_font_rid) const override; + virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override; + virtual bool font_is_antialiased(const RID &p_font_rid) const override; - virtual void font_set_name(RID p_font_rid, const String &p_name) override; - virtual String font_get_name(RID p_font_rid) const override; + virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; + virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; - virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override; - virtual bool font_is_antialiased(RID p_font_rid) const override; + virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override; + virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override; - virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override; - virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override; + virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override; + virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override; - virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override; - virtual int font_get_msdf_pixel_range(RID p_font_rid) const override; + virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override; + virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override; - virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override; - virtual int font_get_msdf_size(RID p_font_rid) const override; + virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override; + virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override; - virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override; - virtual int font_get_fixed_size(RID p_font_rid) const override; + virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override; + virtual bool font_is_force_autohinter(const RID &p_font_rid) const override; - virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override; - virtual bool font_is_force_autohinter(RID p_font_rid) const override; + virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override; + virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override; - virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override; - virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override; + virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override; + virtual double font_get_embolden(const RID &p_font_rid) const override; - virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; - virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; + virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override; + virtual Transform2D font_get_transform(const RID &p_font_rid) const override; - virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override; - virtual float font_get_oversampling(RID p_font_rid) const override; + virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override; + virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override; - virtual Array font_get_size_cache_list(RID p_font_rid) const override; - virtual void font_clear_size_cache(RID p_font_rid) override; - virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override; + virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override; + virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override; - hb_font_t *_font_get_hb_handle(RID p_font, int p_font_size) const; + virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; + virtual double font_get_oversampling(const RID &p_font_rid) const override; - virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override; - virtual float font_get_ascent(RID p_font_rid, int p_size) const override; + virtual Array font_get_size_cache_list(const RID &p_font_rid) const override; + virtual void font_clear_size_cache(const RID &p_font_rid) override; + virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override; - virtual float font_get_descent(RID p_font_rid, int p_size) const override; + virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override; + virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override; - virtual float font_get_underline_position(RID p_font_rid, int p_size) const override; + virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override; + virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override; - virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override; + virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override; + virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override; - virtual float font_get_scale(RID p_font_rid, int p_size) const override; + virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override; + virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override; - virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override; + virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override; + virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override; - virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override; + virtual void font_set_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing, int64_t p_value) override; + virtual int64_t font_get_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing) const override; - virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override; - virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override; + virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override; + virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override; - virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override; - virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override; + virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override; + virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; - virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override; + virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; + virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; - virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override; + virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; + virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; - virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override; + virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override; - virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override; + virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override; - virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override; + virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override; - virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override; + virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override; - virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override; + virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override; - virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override; - virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override; - virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override; + virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; - virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override; + virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; - virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override; + virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; + virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; + virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; - virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override; - virtual String font_get_supported_chars(RID p_font_rid) const override; + virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; + virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override; - virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override; - virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override; + virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override; - virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override; + virtual String font_get_supported_chars(const RID &p_font_rid) const override; - virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override; - virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override; - virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override; - virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override; - virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override; + virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override; + virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override; - virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override; - virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override; - virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override; - virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override; - virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override; + virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual Dictionary font_supported_feature_list(RID p_font_rid) const override; - virtual Dictionary font_supported_variation_list(RID p_font_rid) const override; + virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override; + virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override; + virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override; + virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override; + virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override; - virtual float font_get_global_oversampling() const override; - virtual void font_set_global_oversampling(float p_oversampling) override; + virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override; + virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override; + virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override; + virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override; + virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override; + + virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override; + virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override; + + virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override; + virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override; + + virtual double font_get_global_oversampling() const override; + virtual void font_set_global_oversampling(double p_oversampling) override; /* Shaped text buffer interface */ virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual void shaped_text_clear(RID p_shaped) override; + virtual void shaped_text_clear(const RID &p_shaped) override; - virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override; - virtual Direction shaped_text_get_direction(RID p_shaped) const override; + virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override; + virtual Direction shaped_text_get_direction(const RID &p_shaped) const override; + virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override; - virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override; - virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; - virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override; - virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; + virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override; - virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override; + virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override; + virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override; - virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; + virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override; + virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override; - virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; + virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; + virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override; + virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; - virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; - virtual RID shaped_text_get_parent(RID p_shaped) const override; + virtual int64_t shaped_get_span_count(const RID &p_shaped) const override; + virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override; + virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override; - virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; - virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override; + virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override; + virtual RID shaped_text_get_parent(const RID &p_shaped) const override; - virtual bool shaped_text_shape(RID p_shaped) override; - virtual bool shaped_text_update_breaks(RID p_shaped) override; - virtual bool shaped_text_update_justification_ops(RID p_shaped) override; + virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; + virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override; - virtual int shaped_text_get_trim_pos(RID p_shaped) const override; - virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override; - virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override; - virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override; + virtual bool shaped_text_shape(const RID &p_shaped) override; + virtual bool shaped_text_update_breaks(const RID &p_shaped) override; + virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override; - virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override; + virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override; + virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override; + virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override; + virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override; - virtual bool shaped_text_is_ready(RID p_shaped) const override; + virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, int64_t p_trim_flags) override; - virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override; - virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override; - virtual int shaped_text_get_glyph_count(RID p_shaped) const override; + virtual bool shaped_text_is_ready(const RID &p_shaped) const override; - virtual Vector2i shaped_text_get_range(RID p_shaped) const override; + virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override; + virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override; + virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) 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; + virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override; - virtual Size2 shaped_text_get_size(RID p_shaped) const override; - virtual float shaped_text_get_ascent(RID p_shaped) const override; - virtual float shaped_text_get_descent(RID p_shaped) const override; - virtual float shaped_text_get_width(RID p_shaped) const override; - virtual float shaped_text_get_underline_position(RID p_shaped) const override; - virtual float shaped_text_get_underline_thickness(RID p_shaped) const override; + virtual Array shaped_text_get_objects(const RID &p_shaped) const override; + virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override; + + virtual Size2 shaped_text_get_size(const RID &p_shaped) const override; + virtual double shaped_text_get_ascent(const RID &p_shaped) const override; + virtual double shaped_text_get_descent(const RID &p_shaped) const override; + virtual double shaped_text_get_width(const RID &p_shaped) const override; + virtual double shaped_text_get_underline_position(const RID &p_shaped) const override; + virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override; virtual String format_number(const String &p_string, const String &p_language = "") const override; virtual String parse_number(const String &p_string, const String &p_language = "") const override; virtual String percent_sign(const String &p_language = "") const override; + virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override; + virtual String strip_diacritics(const String &p_string) const override; + virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; + virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + TextServerAdvanced(); ~TextServerAdvanced(); }; diff --git a/modules/text_server_fb/.gitignore b/modules/text_server_fb/.gitignore new file mode 100644 index 0000000000..15cc38b59c --- /dev/null +++ b/modules/text_server_fb/.gitignore @@ -0,0 +1,2 @@ +# Godot-cpp headers +gdextension_build/godot-cpp diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub index 31d1db6167..121f38fcd5 100644 --- a/modules/text_server_fb/SCsub +++ b/modules/text_server_fb/SCsub @@ -4,22 +4,14 @@ Import("env") Import("env_modules") freetype_enabled = env.module_check_dependencies("text_server_fb", ["freetype"], True) -msdngen_enabled = env.module_check_dependencies("text_server_fb", ["msdfgen"], True) +msdfgen_enabled = env.module_check_dependencies("text_server_fb", ["msdfgen"], True) env_text_server_fb = env_modules.Clone() -if msdngen_enabled: - env_text_server_fb.Append( - CPPPATH=[ - "#thirdparty/msdfgen", - ] - ) +if env["builtin_msdfgen"] and msdfgen_enabled: + env_text_server_fb.Append(CPPPATH=["#thirdparty/msdfgen"]) -if freetype_enabled: - env_text_server_fb.Append( - CPPPATH=[ - "#thirdparty/freetype/include", - ] - ) +if env["builtin_freetype"] and freetype_enabled: + env_text_server_fb.Append(CPPPATH=["#thirdparty/freetype/include"]) env_text_server_fb.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/text_server_fb/doc_classes/TextServerFallback.xml b/modules/text_server_fb/doc_classes/TextServerFallback.xml index 8aadf2b882..950b64e49f 100644 --- a/modules/text_server_fb/doc_classes/TextServerFallback.xml +++ b/modules/text_server_fb/doc_classes/TextServerFallback.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TextServerFallback" inherits="TextServer" version="4.0"> +<class name="TextServerFallback" inherits="TextServerExtension" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Fallback implementation of the Text Server, without BiDi and complex text layout support. </brief_description> diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct new file mode 100644 index 0000000000..1753bc8b86 --- /dev/null +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -0,0 +1,205 @@ +#!/usr/bin/env python +import atexit +import os +import sys +import methods +import time + +# For the reference: +# - CCFLAGS are compilation flags shared between C and C++ +# - CFLAGS are for C-specific compilation flags +# - CXXFLAGS are for C++-specific compilation flags +# - CPPFLAGS are for pre-processor flags +# - CPPDEFINES are for pre-processor defines +# - LINKFLAGS are for linking flags + +time_at_start = time.time() + +env = SConscript("./godot-cpp/SConstruct") +env.__class__.disable_warnings = methods.disable_warnings + +opts = Variables([], ARGUMENTS) +opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True)) +opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True)) +opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False)) + +opts.Update(env) + +if not env["verbose"]: + methods.no_verbose(sys, env) + +# MSDFGEN +if env["msdfgen_enabled"] and env["freetype_enabled"]: + env_msdfgen = env.Clone() + env_msdfgen.disable_warnings() + + thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/" + thirdparty_msdfgen_sources = [ + "core/Contour.cpp", + "core/EdgeHolder.cpp", + "core/MSDFErrorCorrection.cpp", + "core/Projection.cpp", + "core/Scanline.cpp", + "core/Shape.cpp", + "core/SignedDistance.cpp", + "core/Vector2.cpp", + "core/contour-combiners.cpp", + "core/edge-coloring.cpp", + "core/edge-segments.cpp", + "core/edge-selectors.cpp", + "core/equation-solver.cpp", + "core/msdf-error-correction.cpp", + "core/msdfgen.cpp", + "core/rasterization.cpp", + "core/render-sdf.cpp", + "core/sdf-error-estimation.cpp", + "core/shape-description.cpp", + ] + thirdparty_msdfgen_sources = [thirdparty_msdfgen_dir + file for file in thirdparty_msdfgen_sources] + + env_msdfgen.Append(CPPPATH=["../../../thirdparty/freetype/include", "../../../thirdparty/msdfgen"]) + env.Append(CPPPATH=["../../../thirdparty/msdfgen"]) + env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"]) + + lib = env_msdfgen.Library( + f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + thirdparty_msdfgen_sources, + ) + env.Append(LIBS=[lib]) + +# FreeType +if env["freetype_enabled"]: + env_freetype = env.Clone() + env_freetype.disable_warnings() + + thirdparty_freetype_dir = "../../../thirdparty/freetype/" + thirdparty_freetype_sources = [ + "src/autofit/autofit.c", + "src/base/ftbase.c", + "src/base/ftbbox.c", + "src/base/ftbdf.c", + "src/base/ftbitmap.c", + "src/base/ftcid.c", + "src/base/ftdebug.c", + "src/base/ftfstype.c", + "src/base/ftgasp.c", + "src/base/ftglyph.c", + "src/base/ftgxval.c", + "src/base/ftinit.c", + "src/base/ftmm.c", + "src/base/ftotval.c", + "src/base/ftpatent.c", + "src/base/ftpfr.c", + "src/base/ftstroke.c", + "src/base/ftsynth.c", + "src/base/ftsystem.c", + "src/base/fttype1.c", + "src/base/ftwinfnt.c", + "src/bdf/bdf.c", + "src/bzip2/ftbzip2.c", + "src/cache/ftcache.c", + "src/cff/cff.c", + "src/cid/type1cid.c", + "src/gxvalid/gxvalid.c", + "src/gzip/ftgzip.c", + "src/lzw/ftlzw.c", + "src/otvalid/otvalid.c", + "src/pcf/pcf.c", + "src/pfr/pfr.c", + "src/psaux/psaux.c", + "src/pshinter/pshinter.c", + "src/psnames/psnames.c", + "src/raster/raster.c", + "src/sdf/sdf.c", + "src/smooth/smooth.c", + "src/truetype/truetype.c", + "src/type1/type1.c", + "src/type42/type42.c", + "src/winfonts/winfnt.c", + "src/sfnt/sfnt.c", + ] + thirdparty_freetype_sources = [thirdparty_freetype_dir + file for file in thirdparty_freetype_sources] + + thirdparty_png_dir = "../../../thirdparty/libpng/" + thirdparty_png_sources = [ + "png.c", + "pngerror.c", + "pngget.c", + "pngmem.c", + "pngpread.c", + "pngread.c", + "pngrio.c", + "pngrtran.c", + "pngrutil.c", + "pngset.c", + "pngtrans.c", + "pngwio.c", + "pngwrite.c", + "pngwtran.c", + "pngwutil.c", + ] + thirdparty_freetype_sources += [thirdparty_png_dir + file for file in thirdparty_png_sources] + + thirdparty_zlib_dir = "../../../thirdparty/zlib/" + thirdparty_zlib_sources = [ + "adler32.c", + "compress.c", + "crc32.c", + "deflate.c", + "infback.c", + "inffast.c", + "inflate.c", + "inftrees.c", + "trees.c", + "uncompr.c", + "zutil.c", + ] + thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources] + + env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir]) + env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"]) + + env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)]) + if env["target"] == "debug": + env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) + + env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) + + lib = env_freetype.Library( + f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + thirdparty_freetype_sources, + ) + env.Append(LIBS=[lib]) + + +env.Append(CPPDEFINES=["GDEXTENSION"]) +env.Append(CPPPATH=["../"]) +sources = Glob("../*.cpp") + +if env["platform"] == "osx": + methods.write_osx_plist( + f'./bin/libtextserver_fallback.osx.{env["target"]}.framework', + f'libtextserver_fallback.osx.{env["target"]}', + "org.godotengine.textserver_fallback", + "Fallback Text Server", + ) + library = env.SharedLibrary( + f'./bin/libtextserver_fallback.osx.{env["target"]}.framework/libtextserver_fallback.osx.{env["target"]}', + source=sources, + ) +else: + library = env.SharedLibrary( + f'./bin/libtextserver_fallback.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}', + source=sources, + ) + +Default(library) + + +def print_elapsed_time(): + elapsed_time_sec = round(time.time() - time_at_start, 3) + time_ms = round((elapsed_time_sec % 1) * 1000) + print("[Time elapsed: {}.{:03}]".format(time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), time_ms)) + + +atexit.register(print_elapsed_time) diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py new file mode 100644 index 0000000000..d404f2851e --- /dev/null +++ b/modules/text_server_fb/gdextension_build/methods.py @@ -0,0 +1,130 @@ +import os +import sys + + +def no_verbose(sys, env): + colors = {} + + # Colors are disabled in non-TTY environments such as pipes. This means + # that if output is redirected to a file, it will not contain color codes + if sys.stdout.isatty(): + colors["blue"] = "\033[0;94m" + colors["bold_blue"] = "\033[1;94m" + colors["reset"] = "\033[0m" + else: + colors["blue"] = "" + colors["bold_blue"] = "" + colors["reset"] = "" + + # There is a space before "..." to ensure that source file names can be + # Ctrl + clicked in the VS Code terminal. + compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + link_program_message = "{}Linking Program {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format( + colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"] + ) + + env.Append(CXXCOMSTR=[compile_source_message]) + env.Append(CCCOMSTR=[compile_source_message]) + env.Append(SHCCCOMSTR=[compile_shared_source_message]) + env.Append(SHCXXCOMSTR=[compile_shared_source_message]) + env.Append(ARCOMSTR=[link_library_message]) + env.Append(RANLIBCOMSTR=[ranlib_library_message]) + env.Append(SHLINKCOMSTR=[link_shared_library_message]) + env.Append(LINKCOMSTR=[link_program_message]) + env.Append(JARCOMSTR=[java_library_message]) + env.Append(JAVACCOMSTR=[java_compile_source_message]) + + +def disable_warnings(self): + # 'self' is the environment + if self["platform"] == "windows" and not self["use_mingw"]: + # We have to remove existing warning level defines before appending /w, + # otherwise we get: "warning D9025 : overriding '/W3' with '/w'" + warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"] + self.Append(CCFLAGS=["/w"]) + self.Append(CFLAGS=["/w"]) + self.Append(CXXFLAGS=["/w"]) + self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags] + self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags] + self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags] + else: + self.Append(CCFLAGS=["-w"]) + self.Append(CFLAGS=["-w"]) + self.Append(CXXFLAGS=["-w"]) + + +def make_icu_data(target, source, env): + dst = target[0].srcnode().abspath + g = open(dst, "w", encoding="utf-8") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n") + g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n") + g.write("#ifndef _ICU_DATA_H\n") + g.write("#define _ICU_DATA_H\n") + g.write('#include "unicode/utypes.h"\n') + g.write('#include "unicode/udata.h"\n') + g.write('#include "unicode/uversion.h"\n') + + f = open(source[0].srcnode().abspath, "rb") + buf = f.read() + + g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n") + g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n') + for i in range(len(buf)): + g.write("\t" + str(buf[i]) + ",\n") + + g.write("};\n") + g.write("#endif") + + +def write_osx_plist(target, binary_name, identifier, name): + os.makedirs(f"{target}/Resourece/", exist_ok=True) + f = open(f"{target}/Resourece/Info.plist", "w") + + f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n') + f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n') + f.write(f'<plist version="1.0">\n') + f.write(f"<dict>\n") + f.write(f"\t<key>CFBundleExecutable</key>\n") + f.write(f"\t<string>{binary_name}</string>\n") + f.write(f"\t<key>CFBundleIdentifier</key>\n") + f.write(f"\t<string>{identifier}</string>\n") + f.write(f"\t<key>CFBundleInfoDictionaryVersion</key>\n") + f.write(f"\t<string>6.0</string>\n") + f.write(f"\t<key>CFBundleName</key>\n") + f.write(f"\t<string>{name}</string>\n") + f.write(f"\t<key>CFBundlePackageType</key>\n") + f.write(f"\t<string>FMWK</string>\n") + f.write(f"\t<key>CFBundleShortVersionString</key>\n") + f.write(f"\t<string>1.0.0</string>\n") + f.write(f"\t<key>CFBundleSupportedPlatforms</key>\n") + f.write(f"\t<array>\n") + f.write(f"\t\t<string>MacOSX</string>\n") + f.write(f"\t</array>\n") + f.write(f"\t<key>CFBundleVersion</key>\n") + f.write(f"\t<string>1.0.0</string>\n") + f.write(f"\t<key>LSMinimumSystemVersion</key>\n") + f.write(f"\t<string>10.14</string>\n") + f.write(f"</dict>\n") + f.write(f"</plist>\n") diff --git a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension new file mode 100644 index 0000000000..1026c6cb85 --- /dev/null +++ b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension @@ -0,0 +1,12 @@ +[configuration] + +entry_symbol = "textserver_fallback_init" + +[libraries] + +linux.64.debug = "bin/libtextserver_fallback.linux.debug.64.so" +linux.64.release = "bin/libtextserver_fallback.linux.release.64.so" +windows.64.debug = "bin/libtextserver_fallback.windows.debug.64.dll" +windows.64.release = "bin/libtextserver_fallback.windows.release.64.dll" +macos.debug = "bin/libtextserver_fallback.osx.debug.framework" +macos.release = "bin/libtextserver_fallback.osx.release.framework" diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp index 0b59040ce8..fa7b87fc17 100644 --- a/modules/text_server_fb/register_types.cpp +++ b/modules/text_server_fb/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -32,17 +32,46 @@ #include "text_server_fb.h" -void preregister_text_server_fb_types() { +void initialize_text_server_fb_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } + GDREGISTER_CLASS(TextServerFallback); - if (TextServerManager::get_singleton()) { + TextServerManager *tsman = TextServerManager::get_singleton(); + if (tsman) { Ref<TextServerFallback> ts; ts.instantiate(); - TextServerManager::get_singleton()->add_interface(ts); + tsman->add_interface(ts); } } -void register_text_server_fb_types() { +void uninitialize_text_server_fb_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } } -void unregister_text_server_fb_types() { +#ifdef GDEXTENSION + +#include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/defs.hpp> +#include <godot_cpp/core/memory.hpp> + +using namespace godot; + +extern "C" { + +GDNativeBool GDN_EXPORT textserver_fallback_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) { + GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); + + init_obj.register_initializer(&initialize_text_server_fb_module); + init_obj.register_terminator(&uninitialize_text_server_fb_module); + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SERVERS); + + return init_obj.init(); } + +} // ! extern "C" + +#endif // ! GDEXTENSION diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h index c854db92e5..229aec2266 100644 --- a/modules/text_server_fb/register_types.h +++ b/modules/text_server_fb/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,10 +31,14 @@ #ifndef TEXT_SERVER_FB_REGISTER_TYPES_H #define TEXT_SERVER_FB_REGISTER_TYPES_H -#define MODULE_TEXT_SERVER_FB_HAS_PREREGISTER +#ifdef GDEXTENSION +#include <godot_cpp/core/class_db.hpp> +using namespace godot; +#else +#include "modules/register_module_types.h" +#endif -void preregister_text_server_fb_types(); -void register_text_server_fb_types(); -void unregister_text_server_fb_types(); +void initialize_text_server_fb_module(ModuleInitializationLevel p_level); +void uninitialize_text_server_fb_module(ModuleInitializationLevel p_level); #endif // TEXT_SERVER_FB_REGISTER_TYPES_H diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 8979d9ff4c..257c569a25 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,11 +30,29 @@ #include "text_server_fb.h" +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/classes/file.hpp> +#include <godot_cpp/classes/rendering_server.hpp> +#include <godot_cpp/classes/translation_server.hpp> +#include <godot_cpp/core/error_macros.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + #include "core/error/error_macros.h" #include "core/string/print_string.h" +#include "core/string/ucaps.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen. +#endif + +// Thirdparty headers. + #ifdef MODULE_MSDFGEN_ENABLED #include "core/ShapeDistanceFinder.h" #include "core/contour-combiners.h" @@ -43,60 +61,60 @@ #endif /*************************************************************************/ -/* Character properties. */ -/*************************************************************************/ - -_FORCE_INLINE_ bool is_control(char32_t p_char) { - return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009F); -} -_FORCE_INLINE_ bool is_whitespace(char32_t p_char) { - return (p_char == 0x0020) || (p_char == 0x00A0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085); -} - -_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_punct(char32_t p_char) { - 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); -} - -/*************************************************************************/ - -String TextServerFallback::interface_name = "Fallback"; -uint32_t TextServerFallback::interface_features = 0; // Nothing is supported. +#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xff) << 24) | (((uint32_t)(c2)&0xff) << 16) | (((uint32_t)(c3)&0xff) << 8) | ((uint32_t)(c4)&0xff))) bool TextServerFallback::has_feature(Feature p_feature) const { - return (interface_features & p_feature) == p_feature; + switch (p_feature) { + case FEATURE_SIMPLE_LAYOUT: + case FEATURE_FONT_BITMAP: +#ifdef MODULE_FREETYPE_ENABLED + case FEATURE_FONT_DYNAMIC: +#endif +#ifdef MODULE_MSDFGEN_ENABLED + case FEATURE_FONT_MSDF: +#endif + return true; + default: { + } + } + return false; } String TextServerFallback::get_name() const { - return interface_name; +#ifdef GDEXTENSION + return "Fallback (GDExtension)"; +#else + return "Fallback (Built-in)"; +#endif } -uint32_t TextServerFallback::get_features() const { +int64_t TextServerFallback::get_features() const { + int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP; +#ifdef MODULE_FREETYPE_ENABLED + interface_features |= FEATURE_FONT_DYNAMIC; +#endif +#ifdef MODULE_MSDFGEN_ENABLED + interface_features |= FEATURE_FONT_MSDF; +#endif + return interface_features; } -void TextServerFallback::free(RID p_rid) { +void TextServerFallback::free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontDataFallback *fd = font_owner.get_or_null(p_rid); font_owner.free(p_rid); memdelete(fd); } else if (shaped_owner.owns(p_rid)) { - ShapedTextData *sd = shaped_owner.get_or_null(p_rid); + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_rid); shaped_owner.free(p_rid); memdelete(sd); } } -bool TextServerFallback::has(RID p_rid) { +bool TextServerFallback::has(const RID &p_rid) { _THREAD_SAFE_METHOD_ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid); } @@ -113,21 +131,27 @@ bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const { return false; // No RTL support. } +_FORCE_INLINE_ void TextServerFallback::_insert_feature(const StringName &p_name, int32_t p_tag) { + feature_sets.insert(p_name, p_tag); + feature_sets_inv.insert(p_tag, p_name); +} + void TextServerFallback::_insert_feature_sets() { // Registered OpenType variation tag. - feature_sets.insert("italic", OT_TAG('i', 't', 'a', 'l')); - feature_sets.insert("optical_size", OT_TAG('o', 'p', 's', 'z')); - feature_sets.insert("slant", OT_TAG('s', 'l', 'n', 't')); - feature_sets.insert("width", OT_TAG('w', 'd', 't', 'h')); - feature_sets.insert("weight", OT_TAG('w', 'g', 'h', 't')); + _insert_feature("italic", OT_TAG('i', 't', 'a', 'l')); + _insert_feature("optical_size", OT_TAG('o', 'p', 's', 'z')); + _insert_feature("slant", OT_TAG('s', 'l', 'n', 't')); + _insert_feature("width", OT_TAG('w', 'd', 't', 'h')); + _insert_feature("weight", OT_TAG('w', 'g', 'h', 't')); } _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) { char tag[4]; uint32_t i; - if (!p_str || !p_len || !*p_str) + if (!p_str || !p_len || !*p_str) { return OT_TAG(0, 0, 0, 0); + } if (p_len < 0 || p_len > 4) { p_len = 4; @@ -143,7 +167,7 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) { return OT_TAG(tag[0], tag[1], tag[2], tag[3]); } -int32_t TextServerFallback::name_to_tag(const String &p_name) const { +int64_t TextServerFallback::name_to_tag(const String &p_name) const { if (feature_sets.has(p_name)) { return feature_sets[p_name]; } @@ -159,11 +183,9 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) { p_buf[3] = (char)(uint8_t)(p_tag >> 0); } -String TextServerFallback::tag_to_name(int32_t p_tag) const { - for (const KeyValue<StringName, int32_t> &E : feature_sets) { - if (E.value == p_tag) { - return E.key; - } +String TextServerFallback::tag_to_name(int64_t p_tag) const { + if (feature_sets_inv.has(p_tag)) { + return feature_sets_inv[p_tag]; } // No readable name, use tag string. @@ -177,7 +199,7 @@ String TextServerFallback::tag_to_name(int32_t p_tag) const { /* Font Glyph Rendering */ /*************************************************************************/ -_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontDataForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) const { +_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontDataForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const { FontTexturePosition ret; ret.index = -1; @@ -187,12 +209,6 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ for (int i = 0; i < p_data->textures.size(); i++) { const FontTexture &ct = p_data->textures[i]; - if (RenderingServer::get_singleton() != nullptr) { - if (ct.texture->get_format() != p_image_format) { - continue; - } - } - if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. continue; } @@ -201,7 +217,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ continue; } - ret.y = 0x7FFFFFFF; + ret.y = 0x7fffffff; ret.x = 0; for (int j = 0; j < ct.texture_w - mw; j++) { @@ -220,7 +236,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ } } - if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_h) { + if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) { continue; // Fail, could not fit it here. } @@ -234,16 +250,32 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ ret.y = 0; int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); - if (mw > texsize) { - texsize = mw; // Special case, adapt to it? - } - if (mh > texsize) { - texsize = mh; // Special case, adapt to it? - } +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(texsize); +#else texsize = next_power_of_2(texsize); +#endif - texsize = MIN(texsize, 4096); + if (p_msdf) { + texsize = MIN(texsize, 2048); + } else { + texsize = MIN(texsize, 1024); + } + if (mw > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mw); +#else + texsize = next_power_of_2(mw); +#endif + } + if (mh > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mh); +#else + texsize = next_power_of_2(mh); +#endif + } FontTexture tex; tex.texture_w = texsize; @@ -274,8 +306,9 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ } } tex.offsets.resize(texsize); + int32_t *offw = tex.offsets.ptrw(); for (int i = 0; i < texsize; i++) { // Zero offsets. - tex.offsets.write[i] = 0; + offw[i] = 0; } p_data->textures.push_back(tex); @@ -289,8 +322,8 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ struct MSContext { msdfgen::Point2 position; - msdfgen::Shape *shape; - msdfgen::Contour *contour; + msdfgen::Shape *shape = nullptr; + msdfgen::Contour *contour = nullptr; }; class DistancePixelConversion { @@ -319,7 +352,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) { } static int ft_move_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); if (!(context->contour && context->contour->edges.empty())) { context->contour = &context->shape->addContour(); } @@ -328,7 +361,7 @@ static int ft_move_to(const FT_Vector *to, void *user) { } static int ft_line_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); msdfgen::Point2 endpoint = ft_point2(*to); if (endpoint != context->position) { context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint)); @@ -338,21 +371,21 @@ static int ft_line_to(const FT_Vector *to, void *user) { } static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to))); context->position = ft_point2(*to); return 0; } static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to))); context->position = ft_point2(*to); return 0; } void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const { - MSDFThreadData *td = (MSDFThreadData *)p_td; + MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td); msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape); int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y; @@ -405,13 +438,13 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( int w = (bounds.r - bounds.l); int h = (bounds.t - bounds.b); - int mw = w + p_rect_margin * 2; - int mh = h + p_rect_margin * 2; + int mw = w + p_rect_margin * 4; + int mh = h + p_rect_margin * 4; ERR_FAIL_COND_V(mw > 4096, FontGlyph()); ERR_FAIL_COND_V(mh > 4096, FontGlyph()); - FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh); + FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); FontTexture &tex = p_data->textures.write[tex_pos.index]; @@ -440,7 +473,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { - int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4; + int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4; ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f)); wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f)); @@ -450,28 +483,18 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata)); - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. + int32_t *offw = tex.offsets.ptrw(); for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - tex.offsets.write[k] = tex_pos.y + mh; + offw[k] = tex_pos.y + mh; } chr.texture_idx = tex_pos.index; - chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h); - chr.rect.position = Vector2(bounds.l, -bounds.t); + chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2); + chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin); chr.rect.size = chr.uv_rect.size; } return chr; @@ -483,8 +506,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma int w = bitmap.width; int h = bitmap.rows; - int mw = w + p_rect_margin * 2; - int mh = h + p_rect_margin * 2; + int mw = w + p_rect_margin * 4; + int mh = h + p_rect_margin * 4; ERR_FAIL_COND_V(mw > 4096, FontGlyph()); ERR_FAIL_COND_V(mh > 4096, FontGlyph()); @@ -492,7 +515,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; - FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh); + FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); // Fit character in char texture. @@ -504,7 +527,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { - int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size; + int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size; ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph()); switch (bitmap.pixel_mode) { case FT_PIXEL_MODE_MONO: { @@ -525,30 +548,19 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma wr[ofs + 3] = bitmap.buffer[ofs_color + 3]; } break; default: - ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + "."); + ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + "."); break; } } } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata)); - - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. + int32_t *offw = tex.offsets.ptrw(); for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - tex.offsets.write[k] = tex_pos.y + mh; + offw[k] = tex_pos.y + mh; } FontGlyph chr; @@ -556,8 +568,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma chr.texture_idx = tex_pos.index; chr.found = true; - chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h); - chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling; + chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2); + chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling; chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling; return chr; } @@ -570,12 +582,14 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const { ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false); + int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts. + FontDataForSizeFallback *fd = p_font_data->cache[p_size]; if (fd->glyph_map.has(p_glyph)) { return fd->glyph_map[p_glyph].found; } - if (p_glyph == 0) { // Non graphical or invalid glyph, do not render. + if (glyph_index == 0) { // Non graphical or invalid glyph, do not render. fd->glyph_map[p_glyph] = FontGlyph(); return true; } @@ -606,7 +620,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d flags |= FT_LOAD_COLOR; } - int32_t glyph_index = FT_Get_Char_Index(fd->face, p_glyph); + glyph_index = FT_Get_Char_Index(fd->face, glyph_index); FT_Fixed v, h; FT_Get_Advance(fd->face, glyph_index, flags, &h); @@ -618,6 +632,26 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d return false; } + if (!p_font_data->msdf) { + if ((p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && p_size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4; + FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0); + } else if ((p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && p_size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5; + FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0); + } + } + + if (p_font_data->embolden != 0.f) { + FT_Pos strength = p_font_data->embolden * p_size.x * 4; // 26.6 fractional units (1 / 64). + FT_Outline_Embolden(&fd->face->glyph->outline, strength); + } + + if (p_font_data->transform != Transform2D()) { + FT_Matrix mat = { FT_Fixed(p_font_data->transform[0][0] * 65536), FT_Fixed(p_font_data->transform[0][1] * 65536), FT_Fixed(p_font_data->transform[1][0] * 65536), FT_Fixed(p_font_data->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536). + FT_Outline_Transform(&fd->face->glyph->outline, &mat); + } + if (!outline) { if (!p_font_data->msdf) { error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); @@ -637,7 +671,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d } } else { FT_Stroker stroker; - if (FT_Stroker_New(library, &stroker) != 0) { + if (FT_Stroker_New(ft_library, &stroker) != 0) { fd->glyph_map[p_glyph] = FontGlyph(); ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker."); } @@ -683,8 +717,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback // Init dynamic font. #ifdef MODULE_FREETYPE_ENABLED int error = 0; - if (!library) { - error = FT_Init_FreeType(&library); + if (!ft_library) { + error = FT_Init_FreeType(&ft_library); ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); } @@ -699,7 +733,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback fargs.memory_size = p_font_data->data_size; fargs.flags = FT_OPEN_MEMORY; fargs.stream = &fd->stream; - error = FT_Open_Face(library, &fargs, 0, &fd->face); + error = FT_Open_Face(ft_library, &fargs, 0, &fd->face); if (error) { FT_Done_Face(fd->face); fd->face = nullptr; @@ -707,9 +741,9 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback } if (p_font_data->msdf) { - fd->oversampling = 1.0f; + fd->oversampling = 1.0; fd->size.x = p_font_data->msdf_source_size; - } else if (p_font_data->oversampling <= 0.0f) { + } else if (p_font_data->oversampling <= 0.0) { fd->oversampling = font_get_global_oversampling(); } else { fd->oversampling = p_font_data->oversampling; @@ -718,19 +752,19 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) { int best_match = 0; int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width)); - fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width; + fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width; for (int i = 1; i < fd->face->num_fixed_sizes; i++) { int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width)); if (ndiff < diff) { best_match = i; diff = ndiff; - fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width; + fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width; } } FT_Select_Size(fd->face, best_match); } else { FT_Set_Pixel_Sizes(fd->face, 0, Math::round(fd->size.x * fd->oversampling)); - fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem; + fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem; } fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale; @@ -764,7 +798,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback for (FT_UInt i = 0; i < amaster->num_axis; i++) { p_font_data->supported_varaitions[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536); } - FT_Done_MM_Var(library, amaster); + FT_Done_MM_Var(ft_library, amaster); } p_font_data->face_init = true; } @@ -783,22 +817,22 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback for (FT_UInt i = 0; i < amaster->num_axis; i++) { // Reset to default. int32_t var_tag = amaster->axis[i].tag; - float var_value = (double)amaster->axis[i].def / 65536.f; + double var_value = (double)amaster->axis[i].def / 65536.0; coords.write[i] = amaster->axis[i].def; if (p_font_data->variation_coordinates.has(var_tag)) { var_value = p_font_data->variation_coordinates[var_tag]; - coords.write[i] = CLAMP(var_value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum); + coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } if (p_font_data->variation_coordinates.has(tag_to_name(var_tag))) { var_value = p_font_data->variation_coordinates[tag_to_name(var_tag)]; - coords.write[i] = CLAMP(var_value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum); + coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } } FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw()); - FT_Done_MM_Var(library, amaster); + FT_Done_MM_Var(ft_library, amaster); } #else ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); @@ -824,7 +858,7 @@ RID TextServerFallback::create_font() { return font_owner.make_rid(fd); } -void TextServerFallback::font_set_data(RID p_font_rid, const PackedByteArray &p_data) { +void TextServerFallback::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -835,18 +869,18 @@ void TextServerFallback::font_set_data(RID p_font_rid, const PackedByteArray &p_ fd->data_size = fd->data.size(); } -void TextServerFallback::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) { +void TextServerFallback::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); _font_clear_cache(fd); - fd->data.clear(); + fd->data.resize(0); fd->data_ptr = p_data_ptr; fd->data_size = p_data_size; } -void TextServerFallback::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) { +void TextServerFallback::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -856,7 +890,7 @@ void TextServerFallback::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p fd->style_flags = p_style; } -uint32_t /*FontStyle*/ TextServerFallback::font_get_style(RID p_font_rid) const { +int64_t /*FontStyle*/ TextServerFallback::font_get_style(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -866,7 +900,7 @@ uint32_t /*FontStyle*/ TextServerFallback::font_get_style(RID p_font_rid) const return fd->style_flags; } -void TextServerFallback::font_set_style_name(RID p_font_rid, const String &p_name) { +void TextServerFallback::font_set_style_name(const RID &p_font_rid, const String &p_name) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -876,7 +910,7 @@ void TextServerFallback::font_set_style_name(RID p_font_rid, const String &p_nam fd->style_name = p_name; } -String TextServerFallback::font_get_style_name(RID p_font_rid) const { +String TextServerFallback::font_get_style_name(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -886,7 +920,7 @@ String TextServerFallback::font_get_style_name(RID p_font_rid) const { return fd->style_name; } -void TextServerFallback::font_set_name(RID p_font_rid, const String &p_name) { +void TextServerFallback::font_set_name(const RID &p_font_rid, const String &p_name) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -896,7 +930,7 @@ void TextServerFallback::font_set_name(RID p_font_rid, const String &p_name) { fd->font_name = p_name; } -String TextServerFallback::font_get_name(RID p_font_rid) const { +String TextServerFallback::font_get_name(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -906,7 +940,7 @@ String TextServerFallback::font_get_name(RID p_font_rid) const { return fd->font_name; } -void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased) { +void TextServerFallback::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -917,7 +951,7 @@ void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased } } -bool TextServerFallback::font_is_antialiased(RID p_font_rid) const { +bool TextServerFallback::font_is_antialiased(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -925,7 +959,30 @@ bool TextServerFallback::font_is_antialiased(RID p_font_rid) const { return fd->antialiased; } -void TextServerFallback::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) { +void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->mipmaps != p_generate_mipmaps) { + for (KeyValue<Vector2i, FontDataForSizeFallback *> &E : fd->cache) { + for (int i = 0; i < E.value->textures.size(); i++) { + E.value->textures.write[i].dirty = true; + } + } + fd->mipmaps = p_generate_mipmaps; + } +} + +bool TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, false); + + MutexLock lock(fd->mutex); + return fd->mipmaps; +} + +void TextServerFallback::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -936,7 +993,7 @@ void TextServerFallback::font_set_multichannel_signed_distance_field(RID p_font_ } } -bool TextServerFallback::font_is_multichannel_signed_distance_field(RID p_font_rid) const { +bool TextServerFallback::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -944,7 +1001,7 @@ bool TextServerFallback::font_is_multichannel_signed_distance_field(RID p_font_r return fd->msdf; } -void TextServerFallback::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) { +void TextServerFallback::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -955,7 +1012,7 @@ void TextServerFallback::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi } } -int TextServerFallback::font_get_msdf_pixel_range(RID p_font_rid) const { +int64_t TextServerFallback::font_get_msdf_pixel_range(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -963,7 +1020,7 @@ int TextServerFallback::font_get_msdf_pixel_range(RID p_font_rid) const { return fd->msdf_range; } -void TextServerFallback::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { +void TextServerFallback::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -974,7 +1031,7 @@ void TextServerFallback::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { } } -int TextServerFallback::font_get_msdf_size(RID p_font_rid) const { +int64_t TextServerFallback::font_get_msdf_size(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -982,17 +1039,15 @@ int TextServerFallback::font_get_msdf_size(RID p_font_rid) const { return fd->msdf_source_size; } -void TextServerFallback::font_set_fixed_size(RID p_font_rid, int p_fixed_size) { +void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->fixed_size != p_fixed_size) { - fd->fixed_size = p_fixed_size; - } + fd->fixed_size = p_fixed_size; } -int TextServerFallback::font_get_fixed_size(RID p_font_rid) const { +int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1000,7 +1055,7 @@ int TextServerFallback::font_get_fixed_size(RID p_font_rid) const { return fd->fixed_size; } -void TextServerFallback::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) { +void TextServerFallback::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1011,7 +1066,7 @@ void TextServerFallback::font_set_force_autohinter(RID p_font_rid, bool p_force_ } } -bool TextServerFallback::font_is_force_autohinter(RID p_font_rid) const { +bool TextServerFallback::font_is_force_autohinter(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1019,7 +1074,7 @@ bool TextServerFallback::font_is_force_autohinter(RID p_font_rid) const { return fd->force_autohinter; } -void TextServerFallback::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) { +void TextServerFallback::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1030,7 +1085,7 @@ void TextServerFallback::font_set_hinting(RID p_font_rid, TextServer::Hinting p_ } } -TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font_rid) const { +TextServer::Hinting TextServerFallback::font_get_hinting(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, HINTING_NONE); @@ -1038,7 +1093,61 @@ TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font_rid) const { return fd->hinting; } -void TextServerFallback::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) { +void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + fd->subpixel_positioning = p_subpixel; +} + +TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED); + + MutexLock lock(fd->mutex); + return fd->subpixel_positioning; +} + +void TextServerFallback::font_set_embolden(const RID &p_font_rid, double p_strength) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->embolden != p_strength) { + _font_clear_cache(fd); + fd->embolden = p_strength; + } +} + +double TextServerFallback::font_get_embolden(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0.0); + + MutexLock lock(fd->mutex); + return fd->embolden; +} + +void TextServerFallback::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->transform != p_transform) { + _font_clear_cache(fd); + fd->transform = p_transform; + } +} + +Transform2D TextServerFallback::font_get_transform(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Transform2D()); + + MutexLock lock(fd->mutex); + return fd->transform; +} + +void TextServerFallback::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1049,7 +1158,7 @@ void TextServerFallback::font_set_variation_coordinates(RID p_font_rid, const Di } } -Dictionary TextServerFallback::font_get_variation_coordinates(RID p_font_rid) const { +Dictionary TextServerFallback::font_get_variation_coordinates(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -1057,7 +1166,7 @@ Dictionary TextServerFallback::font_get_variation_coordinates(RID p_font_rid) co return fd->variation_coordinates; } -void TextServerFallback::font_set_oversampling(RID p_font_rid, float p_oversampling) { +void TextServerFallback::font_set_oversampling(const RID &p_font_rid, double p_oversampling) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1068,15 +1177,15 @@ void TextServerFallback::font_set_oversampling(RID p_font_rid, float p_oversampl } } -float TextServerFallback::font_get_oversampling(RID p_font_rid) const { +double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); return fd->oversampling; } -Array TextServerFallback::font_get_size_cache_list(RID p_font_rid) const { +Array TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); @@ -1088,7 +1197,7 @@ Array TextServerFallback::font_get_size_cache_list(RID p_font_rid) const { return ret; } -void TextServerFallback::font_clear_size_cache(RID p_font_rid) { +void TextServerFallback::font_clear_size_cache(const RID &p_font_rid) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1099,7 +1208,7 @@ void TextServerFallback::font_clear_size_cache(RID p_font_rid) { fd->cache.clear(); } -void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) { +void TextServerFallback::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1110,7 +1219,7 @@ void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i & } } -void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) { +void TextServerFallback::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1121,23 +1230,23 @@ void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, float p_asc fd->cache[size]->ascent = p_ascent; } -float TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const { +double TextServerFallback::font_get_ascent(const RID &p_font_rid, int64_t p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->ascent; } } -void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, float p_descent) { +void TextServerFallback::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1147,23 +1256,23 @@ void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, float p_de fd->cache[size]->descent = p_descent; } -float TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const { +double TextServerFallback::font_get_descent(const RID &p_font_rid, int64_t p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->descent; } } -void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) { +void TextServerFallback::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1174,23 +1283,23 @@ void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, fd->cache[size]->underline_position = p_underline_position; } -float TextServerFallback::font_get_underline_position(RID p_font_rid, int p_size) const { +double TextServerFallback::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->underline_position; } } -void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) { +void TextServerFallback::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1201,23 +1310,23 @@ void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size fd->cache[size]->underline_thickness = p_underline_thickness; } -float TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_size) const { +double TextServerFallback::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->underline_thickness; } } -void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, float p_scale) { +void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1225,26 +1334,31 @@ void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, float p_scal Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); +#ifdef MODULE_FREETYPE_ENABLED + if (fd->cache[size]->face) { + return; // Do not override scale for dynamic fonts, it's calculated automatically. + } +#endif fd->cache[size]->scale = p_scale; } -float TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const { +double TextServerFallback::font_get_scale(const RID &p_font_rid, int64_t p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, 0.f); + ERR_FAIL_COND_V(!fd, 0.0); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0); if (fd->msdf) { - return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->scale / fd->cache[size]->oversampling; } } -void TextServerFallback::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) { +void TextServerFallback::font_set_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing, int64_t p_value) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1260,12 +1374,12 @@ void TextServerFallback::font_set_spacing(RID p_font_rid, int p_size, TextServer fd->cache[size]->spacing_space = p_value; } break; default: { - ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing)); + ERR_FAIL_MSG("Invalid spacing type: " + String::num_int64(p_spacing)); } break; } } -int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const { +int64_t TextServerFallback::font_get_spacing(const RID &p_font_rid, int64_t p_size, TextServer::SpacingType p_spacing) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1277,26 +1391,26 @@ int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer: switch (p_spacing) { case TextServer::SPACING_GLYPH: { if (fd->msdf) { - return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->spacing_glyph * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->spacing_glyph; } } break; case TextServer::SPACING_SPACE: { if (fd->msdf) { - return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size; + return fd->cache[size]->spacing_space * (double)p_size / (double)fd->msdf_source_size; } else { return fd->cache[size]->spacing_space; } } break; default: { - ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing)); + ERR_FAIL_V_MSG(0, "Invalid spacing type: " + String::num_int64(p_spacing)); } break; } return 0; } -int TextServerFallback::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const { +int64_t TextServerFallback::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1308,7 +1422,7 @@ int TextServerFallback::font_get_texture_count(RID p_font_rid, const Vector2i &p return fd->cache[size]->textures.size(); } -void TextServerFallback::font_clear_textures(RID p_font_rid, const Vector2i &p_size) { +void TextServerFallback::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1318,7 +1432,7 @@ void TextServerFallback::font_clear_textures(RID p_font_rid, const Vector2i &p_s fd->cache[size]->textures.clear(); } -void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) { +void TextServerFallback::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1330,7 +1444,7 @@ void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_s fd->cache[size]->textures.remove_at(p_texture_index); } -void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) { +void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND(p_image.is_null()); @@ -1350,13 +1464,20 @@ void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i & tex.texture_h = p_image->get_height(); tex.format = p_image->get_format(); - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata)); + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + tex.texture = Ref<ImageTexture>(); tex.texture.instantiate(); tex.texture->create_from_image(img); + tex.dirty = false; } -Ref<Image> TextServerFallback::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { +Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Ref<Image>()); @@ -1365,13 +1486,15 @@ Ref<Image> TextServerFallback::font_get_texture_image(RID p_font_rid, const Vect ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>()); ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>()); - const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index]; - Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata)); + const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); return img; } -void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) { +void TextServerFallback::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1387,7 +1510,7 @@ void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i tex.offsets = p_offset; } -PackedInt32Array TextServerFallback::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { +PackedInt32Array TextServerFallback::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -1396,11 +1519,11 @@ PackedInt32Array TextServerFallback::font_get_texture_offsets(RID p_font_rid, co ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array()); - const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; return tex.offsets; } -Array TextServerFallback::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const { +Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); @@ -1417,7 +1540,7 @@ Array TextServerFallback::font_get_glyph_list(RID p_font_rid, const Vector2i &p_ return ret; } -void TextServerFallback::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) { +void TextServerFallback::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1428,7 +1551,7 @@ void TextServerFallback::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz fd->cache[size]->glyph_map.clear(); } -void TextServerFallback::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) { +void TextServerFallback::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1439,7 +1562,7 @@ void TextServerFallback::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz fd->cache[size]->glyph_map.erase(p_glyph); } -Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const { +Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1453,14 +1576,21 @@ Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, i const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + Vector2 ea; + if (fd->embolden != 0.0) { + ea.x = fd->embolden * double(size.x) / 64.0; + } + if (fd->msdf) { - return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size; + return (gl[p_glyph].advance + ea) * (double)p_size / (double)fd->msdf_source_size; + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + return (gl[p_glyph].advance + ea).round(); } else { - return gl[p_glyph].advance; + return gl[p_glyph].advance + ea; } } -void TextServerFallback::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) { +void TextServerFallback::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1475,7 +1605,7 @@ void TextServerFallback::font_set_glyph_advance(RID p_font_rid, int p_size, int3 gl[p_glyph].found = true; } -Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1490,13 +1620,13 @@ Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size; + return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size; } else { return gl[p_glyph].rect.position; } } -void TextServerFallback::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) { +void TextServerFallback::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1511,7 +1641,7 @@ void TextServerFallback::font_set_glyph_offset(RID p_font_rid, const Vector2i &p gl[p_glyph].found = true; } -Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1526,13 +1656,13 @@ Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i & const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size; + return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size; } else { return gl[p_glyph].rect.size; } } -void TextServerFallback::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) { +void TextServerFallback::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1547,7 +1677,7 @@ void TextServerFallback::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s gl[p_glyph].found = true; } -Rect2 TextServerFallback::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Rect2()); @@ -1563,7 +1693,7 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i return gl[p_glyph].uv_rect; } -void TextServerFallback::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) { +void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1578,7 +1708,7 @@ void TextServerFallback::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i & gl[p_glyph].found = true; } -int TextServerFallback::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { +int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, -1); @@ -1594,7 +1724,7 @@ int TextServerFallback::font_get_glyph_texture_idx(RID p_font_rid, const Vector2 return gl[p_glyph].texture_idx; } -void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) { +void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1609,7 +1739,87 @@ void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector gl[p_glyph].found = true; } -Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const { +RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, RID()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size_outline(fd, p_size); + + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID()); + if (!_ensure_glyph(fd, size, p_glyph)) { + return RID(); // Invalid or non graphicl glyph, do not display errors. + } + + const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID()); + + if (RenderingServer::get_singleton() != nullptr) { + if (gl[p_glyph].texture_idx != -1) { + if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } + return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid(); + } + } + + return RID(); +} + +Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Size2()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size_outline(fd, p_size); + + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2()); + if (!_ensure_glyph(fd, size, p_glyph)) { + return Size2(); // Invalid or non graphicl glyph, do not display errors. + } + + const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; + ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2()); + + if (RenderingServer::get_singleton() != nullptr) { + if (gl[p_glyph].texture_idx != -1) { + if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } + return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size(); + } + } + + return Size2(); +} + +Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -1618,20 +1828,19 @@ Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_siz ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); - Vector<Vector3> points; - Vector<int32_t> contours; - bool orientation; #ifdef MODULE_FREETYPE_ENABLED - int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, p_index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); - ERR_FAIL_COND_V(error, Dictionary()); + PackedVector3Array points; + PackedInt32Array contours; - points.clear(); - contours.clear(); + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. - float h = fd->cache[size]->ascent; - float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; + int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + ERR_FAIL_COND_V(error, Dictionary()); + + double h = fd->cache[size]->ascent; + double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; if (fd->msdf) { - scale = scale * (float)p_size / (float)fd->msdf_source_size; + scale = scale * (double)p_size / (double)fd->msdf_source_size; } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); @@ -1639,19 +1848,19 @@ Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_siz for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); } - orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); -#else - return Dictionary(); -#endif + bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); Dictionary out; out["points"] = points; out["contours"] = contours; out["orientation"] = orientation; return out; +#else + return Dictionary(); +#endif } -Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) const { +Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); @@ -1667,7 +1876,7 @@ Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) cons return ret; } -void TextServerFallback::font_clear_kerning_map(RID p_font_rid, int p_size) { +void TextServerFallback::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1678,7 +1887,7 @@ void TextServerFallback::font_clear_kerning_map(RID p_font_rid, int p_size) { fd->cache[size]->kerning_map.clear(); } -void TextServerFallback::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) { +void TextServerFallback::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1689,7 +1898,7 @@ void TextServerFallback::font_remove_kerning(RID p_font_rid, int p_size, const V fd->cache[size]->kerning_map.erase(p_glyph_pair); } -void TextServerFallback::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { +void TextServerFallback::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1700,7 +1909,7 @@ void TextServerFallback::font_set_kerning(RID p_font_rid, int p_size, const Vect fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; } -Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const { +Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1713,7 +1922,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V if (kern.has(p_glyph_pair)) { if (fd->msdf) { - return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size; + return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size; } else { return kern[p_glyph_pair]; } @@ -1725,7 +1934,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V int32_t glyph_b = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.y); FT_Get_Kerning(fd->cache[size]->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta); if (fd->msdf) { - return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size; + return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size; } else { return Vector2(delta.x, delta.y); } @@ -1735,12 +1944,12 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V return Vector2(); } -int32_t TextServerFallback::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const { +int64_t TextServerFallback::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); - return (int32_t)p_char; + return (int64_t)p_char; } -bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const { +bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); @@ -1759,7 +1968,7 @@ bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const { return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; } -String TextServerFallback::font_get_supported_chars(RID p_font_rid) const { +String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1776,7 +1985,7 @@ String TextServerFallback::font_get_supported_chars(RID p_font_rid) const { FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex); while (gindex != 0) { if (charcode != 0) { - chars += char32_t(charcode); + chars = chars + String::chr(charcode); } charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex); } @@ -1787,13 +1996,13 @@ String TextServerFallback::font_get_supported_chars(RID p_font_rid) const { const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map; const int32_t *E = nullptr; while ((E = gl.next(E))) { - chars += char32_t(*E); + chars = chars + String::chr(*E); } } return chars; } -void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) { +void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + "."); @@ -1802,33 +2011,86 @@ void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_siz MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - for (char32_t i = p_start; i <= p_end; i++) { - _ensure_glyph(fd, size, (int32_t)i); + for (int64_t i = p_start; i <= p_end; i++) { +#ifdef MODULE_FREETYPE_ENABLED + int32_t idx = i; + if (fd->cache[size]->face) { + if (fd->msdf) { + _ensure_glyph(fd, size, (int32_t)idx); + } else { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + } else { + _ensure_glyph(fd, size, (int32_t)idx); + } + } + } +#endif } } -void TextServerFallback::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) { +void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - ERR_FAIL_COND(!_ensure_glyph(fd, size, p_index)); +#ifdef MODULE_FREETYPE_ENABLED + int32_t idx = p_index & 0xffffff; // Remove subpixel shifts. + if (fd->cache[size]->face) { + if (fd->msdf) { + _ensure_glyph(fd, size, (int32_t)idx); + } else { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (2 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (3 << 27)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + _ensure_glyph(fd, size, (int32_t)idx | (1 << 27)); + _ensure_glyph(fd, size, (int32_t)idx | (0 << 27)); + } else { + _ensure_glyph(fd, size, (int32_t)idx); + } + } + } +#endif } -void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { +void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - if (!_ensure_glyph(fd, size, p_index)) { + + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + +#ifdef MODULE_FREETYPE_ENABLED + if (!fd->msdf && fd->cache[size]->face) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); + index = index | (xshift << 27); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25)); + index = index | (xshift << 27); + } + } +#endif + + if (!_ensure_glyph(fd, size, index)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[p_index]; + const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); @@ -1840,14 +2102,38 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size; - Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size; + cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range); } else { - Point2 cpos = p_pos.floor(); + Point2 cpos = p_pos; + cpos.y = Math::floor(cpos.y); + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.125)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.25)); + } else { + cpos.x = Math::floor(cpos.x); + } cpos += gl.rect.position; Size2 csize = gl.rect.size; RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); @@ -1857,18 +2143,33 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz } } -void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { +void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size)); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); - if (!_ensure_glyph(fd, size, p_index)) { + + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. + +#ifdef MODULE_FREETYPE_ENABLED + if (!fd->msdf && fd->cache[size]->face) { + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125)); + index = index | (xshift << 27); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25)); + index = index | (xshift << 27); + } + } +#endif + + if (!_ensure_glyph(fd, size, index)) { return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } - const FontGlyph &gl = fd->cache[size]->glyph_map[p_index]; + const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); @@ -1880,14 +2181,38 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (fd->mipmaps) { + img->generate_mipmaps(); + } + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size; - Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size; + cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; + Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range); } else { - Point2 cpos = p_pos.floor(); + Point2 cpos = p_pos; + cpos.y = Math::floor(cpos.y); + if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.125)); + } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + cpos.x = ((int)Math::floor(cpos.x + 0.25)); + } else { + cpos.x = Math::floor(cpos.x); + } cpos += gl.rect.position; Size2 csize = gl.rect.size; RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false); @@ -1897,7 +2222,7 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i } } -bool TextServerFallback::font_is_language_supported(RID p_font_rid, const String &p_language) const { +bool TextServerFallback::font_is_language_supported(const RID &p_font_rid, const String &p_language) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1909,7 +2234,7 @@ bool TextServerFallback::font_is_language_supported(RID p_font_rid, const String } } -void TextServerFallback::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) { +void TextServerFallback::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1917,7 +2242,7 @@ void TextServerFallback::font_set_language_support_override(RID p_font_rid, cons fd->language_support_overrides[p_language] = p_supported; } -bool TextServerFallback::font_get_language_support_override(RID p_font_rid, const String &p_language) { +bool TextServerFallback::font_get_language_support_override(const RID &p_font_rid, const String &p_language) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1925,7 +2250,7 @@ bool TextServerFallback::font_get_language_support_override(RID p_font_rid, cons return fd->language_support_overrides[p_language]; } -void TextServerFallback::font_remove_language_support_override(RID p_font_rid, const String &p_language) { +void TextServerFallback::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1933,19 +2258,19 @@ void TextServerFallback::font_remove_language_support_override(RID p_font_rid, c fd->language_support_overrides.erase(p_language); } -Vector<String> TextServerFallback::font_get_language_support_overrides(RID p_font_rid) { +PackedStringArray TextServerFallback::font_get_language_support_overrides(const RID &p_font_rid) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Vector<String>()); + ERR_FAIL_COND_V(!fd, PackedStringArray()); MutexLock lock(fd->mutex); - Vector<String> out; + PackedStringArray out; for (const KeyValue<String, bool> &E : fd->language_support_overrides) { out.push_back(E.key); } return out; } -bool TextServerFallback::font_is_script_supported(RID p_font_rid, const String &p_script) const { +bool TextServerFallback::font_is_script_supported(const RID &p_font_rid, const String &p_script) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1957,7 +2282,7 @@ bool TextServerFallback::font_is_script_supported(RID p_font_rid, const String & } } -void TextServerFallback::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) { +void TextServerFallback::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1965,7 +2290,7 @@ void TextServerFallback::font_set_script_support_override(RID p_font_rid, const fd->script_support_overrides[p_script] = p_supported; } -bool TextServerFallback::font_get_script_support_override(RID p_font_rid, const String &p_script) { +bool TextServerFallback::font_get_script_support_override(const RID &p_font_rid, const String &p_script) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1973,7 +2298,7 @@ bool TextServerFallback::font_get_script_support_override(RID p_font_rid, const return fd->script_support_overrides[p_script]; } -void TextServerFallback::font_remove_script_support_override(RID p_font_rid, const String &p_script) { +void TextServerFallback::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1983,23 +2308,41 @@ void TextServerFallback::font_remove_script_support_override(RID p_font_rid, con fd->script_support_overrides.erase(p_script); } -Vector<String> TextServerFallback::font_get_script_support_overrides(RID p_font_rid) { +PackedStringArray TextServerFallback::font_get_script_support_overrides(const RID &p_font_rid) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Vector<String>()); + ERR_FAIL_COND_V(!fd, PackedStringArray()); MutexLock lock(fd->mutex); - Vector<String> out; + PackedStringArray out; for (const KeyValue<String, bool> &E : fd->script_support_overrides) { out.push_back(E.key); } return out; } -Dictionary TextServerFallback::font_supported_feature_list(RID p_font_rid) const { +void TextServerFallback::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->feature_overrides = p_overrides; +} + +Dictionary TextServerFallback::font_get_opentype_feature_overrides(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Dictionary()); + + MutexLock lock(fd->mutex); + return fd->feature_overrides; +} + +Dictionary TextServerFallback::font_supported_feature_list(const RID &p_font_rid) const { return Dictionary(); } -Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) const { +Dictionary TextServerFallback::font_supported_variation_list(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2009,11 +2352,11 @@ Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) con return fd->supported_varaitions; } -float TextServerFallback::font_get_global_oversampling() const { +double TextServerFallback::font_get_global_oversampling() const { return oversampling; } -void TextServerFallback::font_set_global_oversampling(float p_oversampling) { +void TextServerFallback::font_set_global_oversampling(double p_oversampling) { _THREAD_SAFE_METHOD_ if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -2041,31 +2384,31 @@ void TextServerFallback::font_set_global_oversampling(float p_oversampling) { /* Shaped text buffer interface */ /*************************************************************************/ -void TextServerFallback::invalidate(ShapedTextData *p_shaped) { +void TextServerFallback::invalidate(ShapedTextDataFallback *p_shaped) { p_shaped->valid = false; p_shaped->sort_valid = false; p_shaped->line_breaks_valid = false; p_shaped->justification_ops_valid = false; - p_shaped->ascent = 0.f; - p_shaped->descent = 0.f; - p_shaped->width = 0.f; - p_shaped->upos = 0.f; - p_shaped->uthk = 0.f; + p_shaped->ascent = 0.0; + p_shaped->descent = 0.0; + p_shaped->width = 0.0; + p_shaped->upos = 0.0; + p_shaped->uthk = 0.0; p_shaped->glyphs.clear(); p_shaped->glyphs_logical.clear(); } -void TextServerFallback::full_copy(ShapedTextData *p_shaped) { - ShapedTextData *parent = shaped_owner.get_or_null(p_shaped->parent); +void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) { + ShapedTextDataFallback *parent = shaped_owner.get_or_null(p_shaped->parent); - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : parent->objects) { + for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : parent->objects) { if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) { p_shaped->objects[E.key] = E.value; } } for (int k = 0; k < parent->spans.size(); k++) { - ShapedTextData::Span span = parent->spans[k]; + ShapedTextDataFallback::Span span = parent->spans[k]; if (span.start >= p_shaped->end || span.end <= p_shaped->start) { continue; } @@ -2079,15 +2422,15 @@ void TextServerFallback::full_copy(ShapedTextData *p_shaped) { RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ - ShapedTextData *sd = memnew(ShapedTextData); + ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback); sd->direction = p_direction; sd->orientation = p_orientation; return shaped_owner.make_rid(sd); } -void TextServerFallback::shaped_text_clear(RID p_shaped) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +void TextServerFallback::shaped_text_clear(const RID &p_shaped) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2100,19 +2443,23 @@ void TextServerFallback::shaped_text_clear(RID p_shaped) { invalidate(sd); } -void TextServerFallback::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) { +void TextServerFallback::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { if (p_direction == DIRECTION_RTL) { ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server."); } } -TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped) const { +TextServer::Direction TextServerFallback::shaped_text_get_direction(const RID &p_shaped) const { + return TextServer::DIRECTION_LTR; +} + +TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(const RID &p_shaped) const { return TextServer::DIRECTION_LTR; } -void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { +void TextServerFallback::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); if (sd->custom_punct != p_punct) { @@ -2124,15 +2471,15 @@ void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const } } -String TextServerFallback::shaped_text_get_custom_punctuation(RID p_shaped) const { +String TextServerFallback::shaped_text_get_custom_punctuation(const RID &p_shaped) const { _THREAD_SAFE_METHOD_ - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, String()); return sd->custom_punct; } -void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +void TextServerFallback::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2145,20 +2492,20 @@ void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::O } } -void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { +void TextServerFallback::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { // No BiDi support, ignore. } -TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +TextServer::Orientation TextServerFallback::shaped_text_get_orientation(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL); MutexLock lock(sd->mutex); return sd->orientation; } -void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +void TextServerFallback::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); MutexLock lock(sd->mutex); ERR_FAIL_COND(!sd); @@ -2171,16 +2518,16 @@ void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e } } -bool TextServerFallback::shaped_text_get_preserve_invalid(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_get_preserve_invalid(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); return sd->preserve_invalid; } -void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +void TextServerFallback::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2193,16 +2540,53 @@ void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_e } } -bool TextServerFallback::shaped_text_get_preserve_control(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_get_preserve_control(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); return sd->preserve_control; } -bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +int64_t TextServerFallback::shaped_get_span_count(const RID &p_shaped) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0); + return sd->spans.size(); +} + +Variant TextServerFallback::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, Variant()); + ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant()); + return sd->spans[p_index].meta; +} + +void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + ERR_FAIL_INDEX(p_index, sd->spans.size()); + + ShapedTextDataFallback::Span &span = sd->spans.ptrw()[p_index]; + span.fonts.clear(); + // Pre-sort fonts, push fonts with the language support first. + Array 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], span.language)) { + span.fonts.push_back(p_fonts[i]); + } else { + fonts_no_match.push_back(p_fonts[i]); + } + } + span.fonts.append_array(fonts_no_match); + span.font_size = p_size; + span.features = p_opentype_features; + + sd->valid = false; +} + +bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2220,12 +2604,12 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te full_copy(sd); } - ShapedTextData::Span span; + ShapedTextDataFallback::Span span; span.start = sd->text.length(); span.end = span.start + p_text.length(); // Pre-sort fonts, push fonts with the language support first. - Vector<RID> fonts_no_match; + Array 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)) { @@ -2239,17 +2623,18 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te ERR_FAIL_COND_V(span.fonts.is_empty(), false); span.font_size = p_size; span.language = p_language; + span.meta = p_meta; sd->spans.push_back(span); - sd->text += p_text; + sd->text = sd->text + p_text; sd->end += p_text.length(); invalidate(sd); return true; } -bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2260,18 +2645,18 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con full_copy(sd); } - ShapedTextData::Span span; + ShapedTextDataFallback::Span span; span.start = sd->start + sd->text.length(); span.end = span.start + p_length; span.embedded_key = p_key; - ShapedTextData::EmbeddedObject obj; + ShapedTextDataFallback::EmbeddedObject obj; obj.inline_align = p_inline_align; obj.rect.size = p_size; obj.pos = span.start; sd->spans.push_back(span); - sd->text += String::chr(0xfffc).repeat(p_length); + sd->text = sd->text + String::chr(0xfffc).repeat(p_length); sd->end += p_length; sd->objects[p_key] = obj; invalidate(sd); @@ -2279,8 +2664,8 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con return true; } -bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2300,7 +2685,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) { if (E.value.pos == gl.start) { key = E.key; break; @@ -2333,86 +2718,89 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { - sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); - sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); } } sd->width += gl.advance * gl.repeat; } } + _realign(sd); + } + return true; +} - // Align embedded objects to baseline. - float full_ascent = sd->ascent; - float full_descent = sd->descent; - for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { - if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) { - if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.y = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.y = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.y = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.y = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.y -= E.value.rect.size.y; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.y -= E.value.rect.size.y / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.y); - full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); - } else { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.x = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.x = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.x = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.x = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.x -= E.value.rect.size.x; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.x -= E.value.rect.size.x / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.x); - full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); +void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const { + // Align embedded objects to baseline. + double full_ascent = p_sd->ascent; + double full_descent = p_sd->descent; + for (KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : p_sd->objects) { + if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) { + if (p_sd->orientation == ORIENTATION_HORIZONTAL) { + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.y = -p_sd->ascent; + } break; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2; + } break; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.y = 0; + } break; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.y = p_sd->descent; + } break; } + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.y -= E.value.rect.size.y; + } break; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.y -= E.value.rect.size.y / 2; + } break; + case INLINE_ALIGNMENT_TOP_TO: { + // NOP + } break; + } + full_ascent = MAX(full_ascent, -E.value.rect.position.y); + full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); + } else { + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.x = -p_sd->ascent; + } break; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2; + } break; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.x = 0; + } break; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.x = p_sd->descent; + } break; + } + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.x -= E.value.rect.size.x; + } break; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.x -= E.value.rect.size.x / 2; + } break; + case INLINE_ALIGNMENT_TOP_TO: { + // NOP + } break; + } + full_ascent = MAX(full_ascent, -E.value.rect.position.x); + full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); } } - sd->ascent = full_ascent; - sd->descent = full_descent; } - return true; + p_sd->ascent = full_ascent; + p_sd->descent = full_descent; } -RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_length) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); MutexLock lock(sd->mutex); @@ -2426,7 +2814,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID()); ERR_FAIL_COND_V(sd->end < p_start + p_length, RID()); - ShapedTextData *new_sd = memnew(ShapedTextData); + ShapedTextDataFallback *new_sd = memnew(ShapedTextDataFallback); new_sd->parent = p_shaped; new_sd->start = p_start; new_sd->end = p_start + p_length; @@ -2452,7 +2840,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng Variant key; bool find_embedded = false; if (gl.count == 1) { - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) { if (E.value.pos == gl.start) { find_embedded = true; key = E.key; @@ -2483,8 +2871,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { - new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); - new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); } } new_sd->width += gl.advance * gl.repeat; @@ -2493,89 +2881,24 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng } } - // Align embedded objects to baseline. - float full_ascent = new_sd->ascent; - float full_descent = new_sd->descent; - for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) { - if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) { - if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.y = -new_sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.y = (-new_sd->ascent + new_sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.y = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.y = new_sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.y -= E.value.rect.size.y; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.y -= E.value.rect.size.y / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.y); - full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); - } else { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.x = -new_sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.x = (-new_sd->ascent + new_sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.x = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.x = new_sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.x -= E.value.rect.size.x; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.x -= E.value.rect.size.x / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.x); - full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); - } - } - } - new_sd->ascent = full_ascent; - new_sd->descent = full_descent; + _realign(new_sd); } new_sd->valid = true; return shaped_owner.make_rid(new_sd); } -RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +RID TextServerFallback::shaped_text_get_parent(const RID &p_shaped) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); MutexLock lock(sd->mutex); return sd->parent; } -float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -2613,17 +2936,38 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, } } + double justification_width; + if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) { + if (sd->overrun_trim_data.trim_pos >= 0) { + end_pos = sd->overrun_trim_data.trim_pos; + justification_width = sd->width_trimmed; + } else { + return Math::ceil(sd->width); + } + } else { + justification_width = sd->width; + } + if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) { + // Trim spaces. while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { - sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat; + justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat; sd->glyphs.write[start_pos].advance = 0; start_pos += sd->glyphs[start_pos].count; } while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { - sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat; + justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat; sd->glyphs.write[end_pos].advance = 0; end_pos -= sd->glyphs[end_pos].count; } + } else { + // Skip breaks, but do not reset size. + while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD)) { + start_pos += sd->glyphs[start_pos].count; + } + while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD)) { + end_pos -= sd->glyphs[end_pos].count; + } } int space_count = 0; @@ -2637,25 +2981,33 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, } if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) { - float delta_width_per_space = (p_width - sd->width) / space_count; + double delta_width_per_space = (p_width - justification_width) / space_count; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { - float old_adv = gl.advance; + double old_adv = gl.advance; gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size)); - sd->width += (gl.advance - old_adv); + justification_width += (gl.advance - old_adv); } } } } - return sd->width; + if (Math::floor(p_width) < Math::floor(justification_width)) { + sd->fit_width_minimum_reached = true; + } + + if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) != JUSTIFICATION_CONSTRAIN_ELLIPSIS) { + sd->width = justification_width; + } + + return Math::ceil(justification_width); } -float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -2665,8 +3017,14 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3 const_cast<TextServerFallback *>(this)->shaped_text_update_breaks(p_shaped); } + for (int i = 0; i < p_tab_stops.size(); i++) { + if (p_tab_stops[i] <= 0) { + return 0.0; + } + } + int tab_index = 0; - float off = 0.f; + double off = 0.0; int start, end, delta; if (sd->para_direction == DIRECTION_LTR) { @@ -2683,7 +3041,7 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3 for (int i = start; i != end; i += delta) { if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { - float tab_off = 0.f; + double tab_off = 0.0; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; tab_index++; @@ -2691,7 +3049,7 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3 tab_index = 0; } } - float old_adv = gl[i].advance; + double old_adv = gl[i].advance; gl[i].advance = tab_off - off; sd->width += gl[i].advance - old_adv; off = 0; @@ -2700,11 +3058,11 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3 off += gl[i].advance * gl[i].repeat; } - return 0.f; + return 0.0; } -bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2726,7 +3084,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { if (sd_glyphs[i].count > 0) { char32_t c = sd->text[sd_glyphs[i].start - sd->start]; if (c_punct_size == 0) { - if (is_punct(c)) { + if (is_punct(c) && c != 0x005F) { sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; } } else { @@ -2745,6 +3103,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } if (is_linebreak(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; } if (c == 0x0009 || c == 0x000b) { @@ -2758,8 +3117,8 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { return sd->line_breaks_valid; } -bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_update_justification_ops(const RID &p_shaped) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2774,8 +3133,8 @@ 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, uint16_t p_trim_flags) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped_line); +void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, int64_t p_trim_flags) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); @@ -2803,21 +3162,54 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl return; } + Vector<ShapedTextDataFallback::Span> &spans = sd->spans; + if (sd->parent != RID()) { + ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent); + ERR_FAIL_COND(!parent_sd->valid); + spans = parent_sd->spans; + } + + if (spans.size() == 0) { + 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; - int32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, '.', 0); - Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, dot_gl_idx); - int32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ', 0); - Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, whitespace_gl_idx); + + // Find usable fonts, if fonts from the last glyph do not have required chars. + RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(dot_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (font_has_char(fonts[i], '.')) { + dot_gl_font_rid = fonts[i]; + break; + } + } + } + RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(whitespace_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (font_has_char(fonts[i], ' ')) { + whitespace_gl_font_rid = fonts[i]; + break; + } + } + } + + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; - if (add_ellipsis) { - ellipsis_width = 3 * dot_adv.x + font_get_spacing(last_gl_font_rid, last_gl_font_size, TextServer::SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { + ellipsis_width = 3 * dot_adv.x + font_get_spacing(whitespace_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; - float width = sd->width; + double width = sd->width; int trim_pos = 0; int ellipsis_pos = (enforce_ellipsis) ? 0 : -1; @@ -2867,23 +3259,25 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl gl.count = 1; gl.advance = whitespace_adv.x; gl.index = whitespace_gl_idx; - gl.font_rid = last_gl_font_rid; + gl.font_rid = whitespace_gl_font_rid; gl.font_size = last_gl_font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } // Add ellipsis dots. - Glyph gl; - gl.count = 1; - gl.repeat = 3; - 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; + if (dot_gl_idx != 0) { + Glyph gl; + gl.count = 1; + gl.repeat = 3; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = dot_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL; - sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + } } sd->text_trimmed = true; @@ -2891,40 +3285,40 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl } } -int TextServerFallback::shaped_text_get_trim_pos(RID p_shaped) const { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextData invalid."); +int64_t TextServerFallback::shaped_text_get_trim_pos(const RID &p_shaped) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); return sd->overrun_trim_data.trim_pos; } -int TextServerFallback::shaped_text_get_ellipsis_pos(RID p_shaped) const { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextData invalid."); +int64_t TextServerFallback::shaped_text_get_ellipsis_pos(const RID &p_shaped) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); return sd->overrun_trim_data.ellipsis_pos; } -const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(RID p_shaped) const { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextData invalid."); +const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); return sd->overrun_trim_data.ellipsis_glyph_buf.ptr(); } -int TextServerFallback::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextData invalid."); +int64_t TextServerFallback::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); return sd->overrun_trim_data.ellipsis_glyph_buf.size(); } -bool TextServerFallback::shaped_text_shape(RID p_shaped) { - ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_shape(const RID &p_shaped) { + ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2939,9 +3333,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { // Cleanup. sd->justification_ops_valid = false; sd->line_breaks_valid = false; - sd->ascent = 0.f; - sd->descent = 0.f; - sd->width = 0.f; + sd->ascent = 0.0; + sd->descent = 0.0; + sd->width = 0.0; sd->glyphs.clear(); if (sd->text.length() == 0) { @@ -2951,7 +3345,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { // "Shape" string. for (int i = 0; i < sd->spans.size(); i++) { - const ShapedTextData::Span &span = sd->spans[i]; + const ShapedTextDataFallback::Span &span = sd->spans[i]; if (span.embedded_key != Variant()) { // Embedded object. if (sd->orientation == ORIENTATION_HORIZONTAL) { @@ -2997,15 +3391,16 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { } if (gl.font_rid.is_valid()) { + bool subpos = (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x; + gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x); gl.x_off = 0; gl.y_off = 0; sd->ascent = MAX(sd->ascent, font_get_ascent(gl.font_rid, gl.font_size)); sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size)); } else { - gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y; + gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y); gl.x_off = -Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5); gl.y_off = font_get_ascent(gl.font_rid, gl.font_size); sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); @@ -3031,6 +3426,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { } } } + if (sd->orientation == ORIENTATION_HORIZONTAL && !subpos) { + gl.advance = Math::round(gl.advance); + } } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { @@ -3038,8 +3436,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y; - sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); - sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5)); } } sd->width += gl.advance; @@ -3049,83 +3447,22 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { } // Align embedded objects to baseline. - float full_ascent = sd->ascent; - float full_descent = sd->descent; - for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { - if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.y = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.y = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.y = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.y = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.y -= E.value.rect.size.y; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.y -= E.value.rect.size.y / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.y); - full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); - } else { - switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { - case INLINE_ALIGNMENT_TO_TOP: { - E.value.rect.position.x = -sd->ascent; - } break; - case INLINE_ALIGNMENT_TO_CENTER: { - E.value.rect.position.x = (-sd->ascent + sd->descent) / 2; - } break; - case INLINE_ALIGNMENT_TO_BASELINE: { - E.value.rect.position.x = 0; - } break; - case INLINE_ALIGNMENT_TO_BOTTOM: { - E.value.rect.position.x = sd->descent; - } break; - } - switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { - case INLINE_ALIGNMENT_BOTTOM_TO: { - E.value.rect.position.x -= E.value.rect.size.x; - } break; - case INLINE_ALIGNMENT_CENTER_TO: { - E.value.rect.position.x -= E.value.rect.size.x / 2; - } break; - case INLINE_ALIGNMENT_TOP_TO: { - // NOP - } break; - } - full_ascent = MAX(full_ascent, -E.value.rect.position.x); - full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); - } - } - sd->ascent = full_ascent; - sd->descent = full_descent; + _realign(sd); + sd->valid = true; return sd->valid; } -bool TextServerFallback::shaped_text_is_ready(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +bool TextServerFallback::shaped_text_is_ready(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); return sd->valid; } -const Glyph *TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +const Glyph *TextServerFallback::shaped_text_get_glyphs(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); @@ -3135,8 +3472,8 @@ const Glyph *TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const { return sd->glyphs.ptr(); } -int TextServerFallback::shaped_text_get_glyph_count(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +int64_t TextServerFallback::shaped_text_get_glyph_count(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); MutexLock lock(sd->mutex); @@ -3146,8 +3483,8 @@ int TextServerFallback::shaped_text_get_glyph_count(RID p_shaped) const { return sd->glyphs.size(); } -const Glyph *TextServerFallback::shaped_text_sort_logical(RID p_shaped) { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +const Glyph *TextServerFallback::shaped_text_sort_logical(const RID &p_shaped) { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); @@ -3158,29 +3495,29 @@ const Glyph *TextServerFallback::shaped_text_sort_logical(RID p_shaped) { return sd->glyphs.ptr(); // Already in the logical order, return as is. } -Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +Vector2i TextServerFallback::shaped_text_get_range(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Vector2i()); MutexLock lock(sd->mutex); return Vector2(sd->start, sd->end); } -Array TextServerFallback::shaped_text_get_objects(RID p_shaped) const { +Array TextServerFallback::shaped_text_get_objects(const RID &p_shaped) const { Array ret; - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, ret); MutexLock lock(sd->mutex); - for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) { ret.push_back(E.key); } return ret; } -Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +Rect2 TextServerFallback::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Rect2()); MutexLock lock(sd->mutex); @@ -3191,8 +3528,8 @@ Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_ke return sd->objects[p_key].rect; } -Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); +Size2 TextServerFallback::shaped_text_get_size(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Size2()); MutexLock lock(sd->mutex); @@ -3200,15 +3537,15 @@ Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const { const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { - return Size2(sd->width, sd->ascent + sd->descent); + return Size2(sd->width, sd->ascent + sd->descent).ceil(); } else { - return Size2(sd->ascent + sd->descent, sd->width); + return Size2(sd->ascent + sd->descent, sd->width).ceil(); } } -float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_get_ascent(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -3217,9 +3554,9 @@ float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const { return sd->ascent; } -float TextServerFallback::shaped_text_get_descent(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_get_descent(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -3228,20 +3565,20 @@ float TextServerFallback::shaped_text_get_descent(RID p_shaped) const { return sd->descent; } -float TextServerFallback::shaped_text_get_width(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_get_width(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); } - return sd->width; + return Math::ceil(sd->width); } -float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_get_underline_position(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -3251,9 +3588,9 @@ float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const return sd->upos; } -float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const { - const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); - ERR_FAIL_COND_V(!sd, 0.f); +double TextServerFallback::shaped_text_get_underline_thickness(const RID &p_shaped) const { + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -3263,14 +3600,65 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons return sd->uthk; } +String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const { + String upper = p_string; + + for (int i = 0; i <= upper.length(); i++) { + const char32_t s = upper[i]; + const char32_t t = _find_upper(s); + if (s != t) { // avoid copy on write + upper[i] = t; + } + } + + return upper; +} + +String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const { + String lower = p_string; + + for (int i = 0; i <= lower.length(); i++) { + const char32_t s = lower[i]; + const char32_t t = _find_lower(s); + if (s != t) { // avoid copy on write + lower[i] = t; + } + } + + return lower; +} + +PackedInt32Array TextServerFallback::string_get_word_breaks(const String &p_string, const String &p_language) const { + PackedInt32Array ret; + for (int i = 0; i < p_string.length(); i++) { + char32_t c = p_string[i]; + if (c == 0xfffc) { + continue; + } + if (is_punct(c) && c != 0x005F) { + ret.push_back(i); + continue; + } + if (is_underscore(c)) { + ret.push_back(i); + continue; + } + if (is_whitespace(c) || is_linebreak(c)) { + ret.push_back(i); + continue; + } + } + return ret; +} + TextServerFallback::TextServerFallback() { _insert_feature_sets(); }; TextServerFallback::~TextServerFallback() { #ifdef MODULE_FREETYPE_ENABLED - if (library != nullptr) { - FT_Done_FreeType(library); + if (ft_library != nullptr) { + FT_Done_FreeType(ft_library); } #endif }; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index f2b33c2afb..c837029623 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,7 +36,49 @@ /* BiDi, shaping and advanced font features support. */ /*************************************************************************/ -#include "servers/text_server.h" +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/godot.hpp> + +#include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/mutex_lock.hpp> + +#include <godot_cpp/variant/array.hpp> +#include <godot_cpp/variant/dictionary.hpp> +#include <godot_cpp/variant/packed_int32_array.hpp> +#include <godot_cpp/variant/packed_string_array.hpp> +#include <godot_cpp/variant/packed_vector2_array.hpp> +#include <godot_cpp/variant/rect2.hpp> +#include <godot_cpp/variant/rid.hpp> +#include <godot_cpp/variant/string.hpp> +#include <godot_cpp/variant/vector2.hpp> +#include <godot_cpp/variant/vector2i.hpp> + +#include <godot_cpp/classes/text_server.hpp> +#include <godot_cpp/classes/text_server_extension.hpp> +#include <godot_cpp/classes/text_server_manager.hpp> + +#include <godot_cpp/classes/caret_info.hpp> +#include <godot_cpp/classes/global_constants_binds.hpp> +#include <godot_cpp/classes/glyph.hpp> +#include <godot_cpp/classes/image.hpp> +#include <godot_cpp/classes/image_texture.hpp> +#include <godot_cpp/classes/ref.hpp> + +#include <godot_cpp/templates/hash_map.hpp> +#include <godot_cpp/templates/map.hpp> +#include <godot_cpp/templates/rid_owner.hpp> +#include <godot_cpp/templates/set.hpp> +#include <godot_cpp/templates/thread_work_pool.hpp> +#include <godot_cpp/templates/vector.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + +#include "servers/text/text_server_extension.h" #include "core/templates/rid_owner.h" #include "core/templates/thread_work_pool.h" @@ -44,6 +86,10 @@ #include "modules/modules_enabled.gen.h" // For freetype, msdfgen. +#endif + +// Thirdparty headers. + #ifdef MODULE_FREETYPE_ENABLED #include <ft2build.h> #include FT_FREETYPE_H @@ -54,26 +100,25 @@ #include FT_BBOX_H #endif -#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF))) +/*************************************************************************/ -class TextServerFallback : public TextServer { - GDCLASS(TextServerFallback, TextServer); +class TextServerFallback : public TextServerExtension { + GDCLASS(TextServerFallback, TextServerExtension); _THREAD_SAFE_CLASS_ - static String interface_name; - static uint32_t interface_features; - Map<StringName, int32_t> feature_sets; + Map<int32_t, StringName> feature_sets_inv; void _insert_feature_sets(); + _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag); // Font cache data. #ifdef MODULE_FREETYPE_ENABLED - mutable FT_Library library = nullptr; + mutable FT_Library ft_library = nullptr; #endif - const int rect_range = 2; + const int rect_range = 1; struct FontTexture { Image::Format format; @@ -82,6 +127,7 @@ class TextServerFallback : public TextServer { int texture_h = 0; PackedInt32Array offsets; Ref<ImageTexture> texture; + bool dirty = true; }; struct FontTexturePosition { @@ -99,12 +145,12 @@ class TextServerFallback : public TextServer { }; struct FontDataForSizeFallback { - float ascent = 0.f; - float descent = 0.f; - float underline_position = 0.f; - float underline_thickness = 0.f; - float scale = 1.f; - float oversampling = 1.f; + double ascent = 0.0; + double descent = 0.0; + double underline_position = 0.0; + double underline_thickness = 0.0; + double scale = 1.0; + double oversampling = 1.0; int spacing_glyph = 0; int spacing_space = 0; @@ -133,14 +179,18 @@ class TextServerFallback : public TextServer { Mutex mutex; bool antialiased = true; + bool mipmaps = false; bool msdf = false; int msdf_range = 14; int msdf_source_size = 48; int fixed_size = 0; bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; + TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; Dictionary variation_coordinates; - float oversampling = 0.f; + double oversampling = 0.0; + double embolden = 0.0; + Transform2D transform; uint32_t style_flags = 0; String font_name; @@ -150,6 +200,7 @@ class TextServerFallback : public TextServer { bool face_init = false; Dictionary supported_varaitions; + Dictionary feature_overrides; // Language/script support override. Map<String, bool> language_support_overrides; @@ -163,14 +214,14 @@ class TextServerFallback : public TextServer { ~FontDataFallback() { work_pool.finish(); - for (const Map<Vector2i, FontDataForSizeFallback *>::Element *E = cache.front(); E; E = E->next()) { - memdelete(E->get()); + for (const KeyValue<Vector2i, FontDataForSizeFallback *> &E : cache) { + memdelete(E.value); } cache.clear(); } }; - _FORCE_INLINE_ FontTexturePosition find_texture_pos_for_glyph(FontDataForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) const; + _FORCE_INLINE_ FontTexturePosition find_texture_pos_for_glyph(FontDataForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const; #ifdef MODULE_MSDFGEN_ENABLED _FORCE_INLINE_ FontGlyph rasterize_msdf(FontDataFallback *p_font_data, FontDataForSizeFallback *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const; #endif @@ -202,228 +253,330 @@ class TextServerFallback : public TextServer { } } + // Shaped text cache data. + struct TrimData { + int trim_pos = -1; + int ellipsis_pos = -1; + Vector<Glyph> ellipsis_glyph_buf; + }; + + struct ShapedTextDataFallback { + Mutex mutex; + + /* Source data */ + RID parent; // Substring parent ShapedTextData. + + int start = 0; // Substring start offset in the parent string. + int end = 0; // Substring end offset in the parent string. + + String text; + String custom_punct; + TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. + TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; + + struct Span { + int start = -1; + int end = -1; + + Array fonts; + int font_size = 0; + + Variant embedded_key; + + String language; + Dictionary features; + Variant meta; + }; + Vector<Span> spans; + + struct EmbeddedObject { + int pos = 0; + InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER; + Rect2 rect; + }; + Map<Variant, EmbeddedObject> objects; + + /* Shaped data */ + TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. + bool valid = false; // String is shaped. + bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). + bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. + bool sort_valid = false; + bool text_trimmed = false; + + bool preserve_invalid = true; // Draw hex code box instead of missing characters. + bool preserve_control = false; // Draw control characters. + + double ascent = 0.0; // Ascent for horizontal layout, 1/2 of width for vertical. + double descent = 0.0; // Descent for horizontal layout, 1/2 of width for vertical. + double width = 0.0; // Width for horizontal layout, height for vertical. + double width_trimmed = 0.0; + + double upos = 0.0; + double uthk = 0.0; + + TrimData overrun_trim_data; + bool fit_width_minimum_reached = false; + + Vector<Glyph> glyphs; + Vector<Glyph> glyphs_logical; + }; + // Common data. - float oversampling = 1.f; + double oversampling = 1.0; mutable RID_PtrOwner<FontDataFallback> font_owner; - mutable RID_PtrOwner<ShapedTextData> shaped_owner; + mutable RID_PtrOwner<ShapedTextDataFallback> shaped_owner; + + void _realign(ShapedTextDataFallback *p_sd) const; protected: static void _bind_methods(){}; - void full_copy(ShapedTextData *p_shaped); - void invalidate(ShapedTextData *p_shaped); + void full_copy(ShapedTextDataFallback *p_shaped); + void invalidate(ShapedTextDataFallback *p_shaped); public: virtual bool has_feature(Feature p_feature) const override; virtual String get_name() const override; - virtual uint32_t get_features() const override; + virtual int64_t get_features() const override; - virtual void free(RID p_rid) override; - virtual bool has(RID p_rid) override; + virtual void free_rid(const RID &p_rid) override; + virtual bool has(const RID &p_rid) override; virtual bool load_support_data(const String &p_filename) override; - virtual String get_support_data_filename() const override { return ""; }; - virtual String get_support_data_info() const override { return "Not supported"; }; + virtual String get_support_data_filename() const override { + return ""; + }; + virtual String get_support_data_info() const override { + return "Not supported"; + }; virtual bool save_support_data(const String &p_filename) const override; virtual bool is_locale_right_to_left(const String &p_locale) const override; - virtual int32_t name_to_tag(const String &p_name) const override; - virtual String tag_to_name(int32_t p_tag) const override; + virtual int64_t name_to_tag(const String &p_name) const override; + virtual String tag_to_name(int64_t p_tag) const override; /* Font interface */ virtual RID create_font() override; - virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override; - virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override; + virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; + virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + + virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override; + virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override; + + virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override; + virtual String font_get_style_name(const RID &p_font_rid) const override; + + virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; + virtual String font_get_name(const RID &p_font_rid) const override; - virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override; - virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override; + virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override; + virtual bool font_is_antialiased(const RID &p_font_rid) const override; - virtual void font_set_style_name(RID p_font_rid, const String &p_name) override; - virtual String font_get_style_name(RID p_font_rid) const override; + virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; + virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; - virtual void font_set_name(RID p_font_rid, const String &p_name) override; - virtual String font_get_name(RID p_font_rid) const override; + virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override; + virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override; - virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override; - virtual bool font_is_antialiased(RID p_font_rid) const override; + virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override; + virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override; - virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override; - virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override; + virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override; + virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override; - virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override; - virtual int font_get_msdf_pixel_range(RID p_font_rid) const override; + virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override; + virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override; - virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override; - virtual int font_get_msdf_size(RID p_font_rid) const override; + virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override; + virtual bool font_is_force_autohinter(const RID &p_font_rid) const override; - virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override; - virtual int font_get_fixed_size(RID p_font_rid) const override; + virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override; + virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override; - virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override; - virtual bool font_is_force_autohinter(RID p_font_rid) const override; + virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override; + virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override; - virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override; - virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override; + virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override; + virtual double font_get_embolden(const RID &p_font_rid) const override; - virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; - virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; + virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override; + virtual Transform2D font_get_transform(const RID &p_font_rid) const override; - virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override; - virtual float font_get_oversampling(RID p_font_rid) const override; + virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override; + virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override; - virtual Array font_get_size_cache_list(RID p_font_rid) const override; - virtual void font_clear_size_cache(RID p_font_rid) override; - virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override; + virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; + virtual double font_get_oversampling(const RID &p_font_rid) const override; - virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override; - virtual float font_get_ascent(RID p_font_rid, int p_size) const override; + virtual Array font_get_size_cache_list(const RID &p_font_rid) const override; + virtual void font_clear_size_cache(const RID &p_font_rid) override; + virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override; - virtual float font_get_descent(RID p_font_rid, int p_size) const override; + virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override; + virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override; - virtual float font_get_underline_position(RID p_font_rid, int p_size) const override; + virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override; + virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override; - virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override; + virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override; + virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override; - virtual float font_get_scale(RID p_font_rid, int p_size) const override; + virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override; + virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override; - virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override; + virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override; + virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override; - virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override; + virtual void font_set_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing, int64_t p_value) override; + virtual int64_t font_get_spacing(const RID &p_font_rid, int64_t p_size, SpacingType p_spacing) const override; - virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override; - virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override; + virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override; + virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override; - virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override; - virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override; + virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override; + virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; - virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override; + virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; + virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; - virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override; + virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; + virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; - virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override; + virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override; - virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override; + virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override; - virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override; + virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override; - virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; - virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override; + virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override; - virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override; + virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override; + virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override; - virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override; - virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override; + virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; - virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; - virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override; + virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; + virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; + virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; - virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override; + virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; + virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override; - virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override; - virtual String font_get_supported_chars(RID p_font_rid) const override; + virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override; - virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override; - virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override; + virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override; + virtual String font_get_supported_chars(const RID &p_font_rid) const override; - virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override; + virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override; - virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override; - virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override; - virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override; - virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override; - virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override; + virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override; - virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override; - virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override; - virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override; - virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override; + virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override; + virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override; + virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override; + virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override; + virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override; - virtual Dictionary font_supported_feature_list(RID p_font_rid) const override; - virtual Dictionary font_supported_variation_list(RID p_font_rid) const override; + virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override; + virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override; + virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override; + virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override; + virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override; - virtual float font_get_global_oversampling() const override; - virtual void font_set_global_oversampling(float p_oversampling) override; + virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override; + virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override; + + virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override; + virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override; + + virtual double font_get_global_oversampling() const override; + virtual void font_set_global_oversampling(double p_oversampling) override; /* Shaped text buffer interface */ virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual void shaped_text_clear(RID p_shaped) override; + virtual void shaped_text_clear(const RID &p_shaped) override; + + virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override; + virtual Direction shaped_text_get_direction(const RID &p_shaped) const override; + virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override; + + virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override; + + virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override; - virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override; - virtual Direction shaped_text_get_direction(RID p_shaped) const override; + virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override; - virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override; + virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override; - virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; - virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override; + virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override; - virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; + virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; + virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override; + virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; - virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override; + virtual int64_t shaped_get_span_count(const RID &p_shaped) const override; + virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override; + virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override; - virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; + virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override; + virtual RID shaped_text_get_parent(const RID &p_shaped) const override; - virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; + virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, int64_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; + virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override; - virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; - virtual RID shaped_text_get_parent(RID p_shaped) const override; + virtual bool shaped_text_shape(const RID &p_shaped) override; + virtual bool shaped_text_update_breaks(const RID &p_shaped) override; + virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override; - virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; - virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override; + virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override; + virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override; + virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override; + virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override; - virtual bool shaped_text_shape(RID p_shaped) override; - 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(const RID &p_shaped, double p_width, int64_t p_trim_flags) override; - virtual int shaped_text_get_trim_pos(RID p_shaped) const override; - virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override; - virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override; - virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override; + virtual bool shaped_text_is_ready(const RID &p_shaped) const override; - virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override; + virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override; + virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override; + virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override; - virtual bool shaped_text_is_ready(RID p_shaped) const override; + virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override; - virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override; - virtual int shaped_text_get_glyph_count(RID p_shaped) const override; + virtual Array shaped_text_get_objects(const RID &p_shaped) const override; + virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override; - virtual Vector2i shaped_text_get_range(RID p_shaped) const override; + virtual Size2 shaped_text_get_size(const RID &p_shaped) const override; + virtual double shaped_text_get_ascent(const RID &p_shaped) const override; + virtual double shaped_text_get_descent(const RID &p_shaped) const override; + virtual double shaped_text_get_width(const RID &p_shaped) const override; + virtual double shaped_text_get_underline_position(const RID &p_shaped) const override; + virtual double shaped_text_get_underline_thickness(const RID &p_shaped) 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; + virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override; - virtual Size2 shaped_text_get_size(RID p_shaped) const override; - virtual float shaped_text_get_ascent(RID p_shaped) const override; - virtual float shaped_text_get_descent(RID p_shaped) const override; - virtual float shaped_text_get_width(RID p_shaped) const override; - virtual float shaped_text_get_underline_position(RID p_shaped) const override; - virtual float shaped_text_get_underline_thickness(RID p_shaped) const override; + virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; + virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; TextServerFallback(); ~TextServerFallback(); diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index f0d7c335bd..08ad1ef9f8 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff return OK; } -Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -330,7 +330,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force } } - f->close(); return err; } @@ -339,12 +338,14 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const } static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) { - FileAccessMemory memfile; - Error open_memfile_error = memfile.open_custom(p_tga, p_size); + Ref<FileAccessMemory> memfile; + memfile.instantiate(); + 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.instantiate(); - Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f); + 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 e4463a322f..9b7cbbac77 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,9 +33,6 @@ #include "core/io/image_loader.h" -/** - @author SaracenOne -*/ class ImageLoaderTGA : public ImageFormatLoader { enum tga_type_e { TGA_TYPE_NO_DATA = 0, @@ -76,9 +73,9 @@ class ImageLoaderTGA : public ImageFormatLoader { 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); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTGA(); }; -#endif +#endif // IMAGE_LOADER_TGA_H diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp index 9e5fe124ef..520ed5f799 100644 --- a/modules/tga/register_types.cpp +++ b/modules/tga/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,19 @@ static ImageLoaderTGA *image_loader_tga = nullptr; -void register_tga_types() { +void initialize_tga_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + image_loader_tga = memnew(ImageLoaderTGA); ImageLoader::add_image_format_loader(image_loader_tga); } -void unregister_tga_types() { +void uninitialize_tga_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + memdelete(image_loader_tga); } diff --git a/modules/tga/register_types.h b/modules/tga/register_types.h index 0dcd750250..37cdab70dd 100644 --- a/modules/tga/register_types.h +++ b/modules/tga/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef TGA_REGISTER_TYPES_H #define TGA_REGISTER_TYPES_H -void register_tga_types(); -void unregister_tga_types(); +#include "modules/register_module_types.h" + +void initialize_tga_module(ModuleInitializationLevel p_level); +void uninitialize_tga_module(ModuleInitializationLevel p_level); #endif // TGA_REGISTER_TYPES_H diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml index 725f87b046..0f2dece8e7 100644 --- a/modules/theora/doc_classes/VideoStreamTheora.xml +++ b/modules/theora/doc_classes/VideoStreamTheora.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VideoStreamTheora" inherits="VideoStream" version="4.0"> +<class name="VideoStreamTheora" inherits="VideoStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> [VideoStream] resource for Ogg Theora videos. </brief_description> diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp index 55148a6b87..9ed8a86415 100644 --- a/modules/theora/register_types.cpp +++ b/modules/theora/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,14 +34,22 @@ static Ref<ResourceFormatLoaderTheora> resource_loader_theora; -void register_theora_types() { +void initialize_theora_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + resource_loader_theora.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_theora, true); GDREGISTER_CLASS(VideoStreamTheora); } -void unregister_theora_types() { +void uninitialize_theora_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + ResourceLoader::remove_resource_format_loader(resource_loader_theora); resource_loader_theora.unref(); } diff --git a/modules/theora/register_types.h b/modules/theora/register_types.h index 654d70e417..2529b09306 100644 --- a/modules/theora/register_types.h +++ b/modules/theora/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef THEORA_REGISTER_TYPES_H #define THEORA_REGISTER_TYPES_H -void register_theora_types(); -void unregister_theora_types(); +#include "modules/register_module_types.h" + +void initialize_theora_module(ModuleInitializationLevel p_level); +void uninitialize_theora_module(ModuleInitializationLevel p_level); #endif // THEORA_REGISTER_TYPES_H diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 4f5ae4afb0..77e370849f 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -114,7 +114,7 @@ void VideoStreamPlaybackTheora::video_write() { } void VideoStreamPlaybackTheora::clear() { - if (!file) { + if (file.is_null()) { return; } @@ -152,10 +152,7 @@ void VideoStreamPlaybackTheora::clear() { theora_eos = false; vorbis_eos = false; - if (file) { - memdelete(file); - } - file = nullptr; + file.unref(); playing = false; }; @@ -165,11 +162,8 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { th_setup_info *ts = nullptr; file_name = p_file; - if (file) { - memdelete(file); - } file = FileAccess::open(p_file, FileAccess::READ); - ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_file + "'."); + ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_file + "'."); #ifdef THEORA_USE_THREAD_STREAMING thread_exit = false; @@ -337,6 +331,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { Ref<Image> img; img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8); + texture->create_from_image(img); } else { /* tear down the partial theora setup */ @@ -374,7 +369,7 @@ Ref<Texture2D> VideoStreamPlaybackTheora::get_texture() const { } void VideoStreamPlaybackTheora::update(float p_delta) { - if (!file) { + if (file.is_null()) { return; } @@ -505,9 +500,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } #ifdef THEORA_USE_THREAD_STREAMING - if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) { + if (file.is_valid() && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) { #else - if (file && /*!videobuf_ready && */ no_theora && theora_eos) { + if (file.is_valid() && /*!videobuf_ready && */ no_theora && theora_eos) { #endif //printf("video done, stopping\n"); stop(); @@ -603,7 +598,7 @@ float VideoStreamPlaybackTheora::get_playback_position() const { }; void VideoStreamPlaybackTheora::seek(float p_time) { - WARN_PRINT_ONCE("Seeking in Theora videos is not implemented yet (it's only supported for GDNative-provided video streams)."); + WARN_PRINT_ONCE("Seeking in Theora videos is not implemented yet (it's only supported for GDExtension-provided video streams)."); } void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) { @@ -626,7 +621,7 @@ int VideoStreamPlaybackTheora::get_mix_rate() const { #ifdef THEORA_USE_THREAD_STREAMING void VideoStreamPlaybackTheora::_streaming_thread(void *ud) { - VideoStreamPlaybackTheora *vs = (VideoStreamPlaybackTheora *)ud; + VideoStreamPlaybackTheora *vs = static_cast<VideoStreamPlaybackTheora *>(ud); while (!vs->thread_exit) { //just fill back the buffer @@ -663,10 +658,6 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() { memdelete(thread_sem); #endif clear(); - - if (file) { - memdelete(file); - } }; void VideoStreamTheora::_bind_methods() { @@ -678,13 +669,13 @@ void VideoStreamTheora::_bind_methods() { //////////// -RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { +Ref<Resource> ResourceFormatLoaderTheora::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<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { if (r_error) { *r_error = ERR_CANT_OPEN; } - return RES(); + return Ref<Resource>(); } VideoStreamTheora *stream = memnew(VideoStreamTheora); @@ -696,8 +687,6 @@ RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_origi *r_error = OK; } - f->close(); - memdelete(f); return ogv_stream; } diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 760173d0df..8940ed6aff 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -56,7 +56,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { Image::Format format = Image::Format::FORMAT_L8; Vector<uint8_t> frame_data; int frames_pending = 0; - FileAccess *file = nullptr; + Ref<FileAccess> file; String file_name; int audio_frames_wrote = 0; Point2i size; @@ -99,7 +99,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { Ref<ImageTexture> texture; - AudioMixCallback mix_callback; + AudioMixCallback mix_callback = nullptr; void *mix_udata = nullptr; bool paused = false; @@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { RingBuffer<uint8_t> ring_buffer; Vector<uint8_t> read_buffer; bool thread_eof = false; - Semaphore *thread_sem; + Semaphore *thread_sem = nullptr; Thread thread; SafeFlag thread_exit; @@ -186,7 +186,7 @@ public: class ResourceFormatLoaderTheora : 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 Ref<Resource> 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; diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 6c4c06aab0..864df765ee 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,7 +37,7 @@ #include "thirdparty/tinyexr/tinyexr.h" -Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -47,8 +47,6 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f f->get_buffer(&w[0], src_image_len); - f->close(); - // Re-implementation of tinyexr's LoadEXRFromMemory using Godot types to store the Image data // and Godot's error codes. // When debugging after updating the thirdparty library, check that we're still in sync with @@ -232,7 +230,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f } if (p_force_linear) { - color = color.to_linear(); + color = color.srgb_to_linear(); } *row_w++ = Math::make_half_float(color.r); @@ -263,7 +261,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f } if (p_force_linear) { - color = color.to_linear(); + color = color.srgb_to_linear(); } *row_w++ = color.r; diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h index 34390fccb0..c147861c26 100644 --- a/modules/tinyexr/image_loader_tinyexr.h +++ b/modules/tinyexr/image_loader_tinyexr.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,7 +35,7 @@ class ImageLoaderTinyEXR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTinyEXR(); }; diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp index f64acf8395..5fa6ace827 100644 --- a/modules/tinyexr/image_saver_tinyexr.cpp +++ b/modules/tinyexr/image_saver_tinyexr.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -275,8 +275,8 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) print_error(String("Saving EXR failed. Error: {0}").format(varray(err))); return ERR_FILE_CANT_WRITE; } else { - FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE); + Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE); ref->store_buffer(mem, bytes); free(mem); } diff --git a/modules/tinyexr/image_saver_tinyexr.h b/modules/tinyexr/image_saver_tinyexr.h index e5060ef11c..5bf95b265e 100644 --- a/modules/tinyexr/image_saver_tinyexr.h +++ b/modules/tinyexr/image_saver_tinyexr.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp index ecbabc4951..d49ac23fea 100644 --- a/modules/tinyexr/register_types.cpp +++ b/modules/tinyexr/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,14 +35,22 @@ static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr; -void register_tinyexr_types() { +void initialize_tinyexr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + image_loader_tinyexr = memnew(ImageLoaderTinyEXR); ImageLoader::add_image_format_loader(image_loader_tinyexr); Image::save_exr_func = save_exr; } -void unregister_tinyexr_types() { +void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + memdelete(image_loader_tinyexr); Image::save_exr_func = nullptr; diff --git a/modules/tinyexr/register_types.h b/modules/tinyexr/register_types.h index e401f37066..bb50e024cb 100644 --- a/modules/tinyexr/register_types.h +++ b/modules/tinyexr/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef TINYEXR_REGISTER_TYPES_H #define TINYEXR_REGISTER_TYPES_H -void register_tinyexr_types(); -void unregister_tinyexr_types(); +#include "modules/register_module_types.h" + +void initialize_tinyexr_module(ModuleInitializationLevel p_level); +void uninitialize_tinyexr_module(ModuleInitializationLevel p_level); #endif // TINYEXR_REGISTER_TYPES_H diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml index 2cd0b8843a..066506922c 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="RefCounted" version="4.0"> +<class name="UPNP" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> UPNP network functions. </brief_description> diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index b7c2ff7dd7..7749ac18ab 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="RefCounted" version="4.0"> +<class name="UPNPDevice" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> UPNP device. </brief_description> diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp index 1e5edd3602..9e041a0c6e 100644 --- a/modules/upnp/register_types.cpp +++ b/modules/upnp/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,10 +35,17 @@ #include "upnp.h" #include "upnp_device.h" -void register_upnp_types() { +void initialize_upnp_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + GDREGISTER_CLASS(UPNP); GDREGISTER_CLASS(UPNPDevice); } -void unregister_upnp_types() { +void uninitialize_upnp_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/upnp/register_types.h b/modules/upnp/register_types.h index 768031c4d9..ef559cc4e8 100644 --- a/modules/upnp/register_types.h +++ b/modules/upnp/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef UPNP_REGISTER_TYPES_H #define UPNP_REGISTER_TYPES_H -void register_upnp_types(); -void unregister_upnp_types(); +#include "modules/register_module_types.h" + +void initialize_upnp_module(ModuleInitializationLevel p_level); +void uninitialize_upnp_module(ModuleInitializationLevel p_level); #endif // UPNP_REGISTER_TYPES_H diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 64823deaba..d762ca4f09 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h index 67df187f8c..6d87b42c56 100644 --- a/modules/upnp/upnp.h +++ b/modules/upnp/upnp.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp index 692a0f3509..4009a399f2 100644 --- a/modules/upnp/upnp_device.cpp +++ b/modules/upnp/upnp_device.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h index 0a66c36ab9..18491dce27 100644 --- a/modules/upnp/upnp_device.h +++ b/modules/upnp/upnp_device.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp index 54240e66fc..8bb7e780de 100644 --- a/modules/vhacd/register_types.cpp +++ b/modules/vhacd/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -89,10 +89,18 @@ static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_ return ret; } -void register_vhacd_types() { +void initialize_vhacd_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + Mesh::convex_decomposition_function = convex_decompose; } -void unregister_vhacd_types() { +void uninitialize_vhacd_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + Mesh::convex_decomposition_function = nullptr; } diff --git a/modules/vhacd/register_types.h b/modules/vhacd/register_types.h index 24ad9378f4..04ec180cd6 100644 --- a/modules/vhacd/register_types.h +++ b/modules/vhacd/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef VHACD_REGISTER_TYPES_H #define VHACD_REGISTER_TYPES_H -void register_vhacd_types(); -void unregister_vhacd_types(); +#include "modules/register_module_types.h" + +void initialize_vhacd_module(ModuleInitializationLevel p_level); +void uninitialize_vhacd_module(ModuleInitializationLevel p_level); #endif // VHACD_REGISTER_TYPES_H diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml index a452974014..5807c98d32 100644 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ b/modules/visual_script/doc_classes/VisualScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScript" inherits="Script" version="4.0"> +<class name="VisualScript" inherits="Script" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A script implemented in the Visual Script programming environment. </brief_description> @@ -316,7 +316,7 @@ </method> <method name="set_scroll"> <return type="void" /> - <argument index="0" name="ofs" type="Vector2" /> + <argument index="0" name="offset" type="Vector2" /> <description> Set the screen center to the given position. </description> diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml index ed5b814bb7..0ed66f44e1 100644 --- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node representing a constant from the base types. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml index b3fd678379..647b627d25 100644 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node used to call built-in functions. </brief_description> @@ -16,203 +16,205 @@ </members> <constants> <constant name="MATH_SIN" value="0" enum="BuiltinFunc"> - Return the sine of the input. + Returns the sine of the input. </constant> <constant name="MATH_COS" value="1" enum="BuiltinFunc"> - Return the cosine of the input. + Returns the cosine of the input. </constant> <constant name="MATH_TAN" value="2" enum="BuiltinFunc"> - Return the tangent of the input. + Returns the tangent of the input. </constant> <constant name="MATH_SINH" value="3" enum="BuiltinFunc"> - Return the hyperbolic sine of the input. + Returns the hyperbolic sine of the input. </constant> <constant name="MATH_COSH" value="4" enum="BuiltinFunc"> - Return the hyperbolic cosine of the input. + Returns the hyperbolic cosine of the input. </constant> <constant name="MATH_TANH" value="5" enum="BuiltinFunc"> - Return the hyperbolic tangent of the input. + Returns the hyperbolic tangent of the input. </constant> <constant name="MATH_ASIN" value="6" enum="BuiltinFunc"> - Return the arc sine of the input. + Returns the arc sine of the input. </constant> <constant name="MATH_ACOS" value="7" enum="BuiltinFunc"> - Return the arc cosine of the input. + Returns the arc cosine of the input. </constant> <constant name="MATH_ATAN" value="8" enum="BuiltinFunc"> - Return the arc tangent of the input. + Returns the arc tangent of the input. </constant> <constant name="MATH_ATAN2" value="9" enum="BuiltinFunc"> - Return the arc tangent of the input, using the signs of both parameters to determine the exact angle. + Returns the arc tangent of the input, using the signs of both parameters to determine the exact angle. </constant> <constant name="MATH_SQRT" value="10" enum="BuiltinFunc"> - Return the square root of the input. + Returns the square root of the input. </constant> <constant name="MATH_FMOD" value="11" enum="BuiltinFunc"> - Return the remainder of one input divided by the other, using floating-point numbers. + Returns the remainder of one input divided by the other, using floating-point numbers. </constant> <constant name="MATH_FPOSMOD" value="12" enum="BuiltinFunc"> - Return the positive remainder of one input divided by the other, using floating-point numbers. + Returns the positive remainder of one input divided by the other, using floating-point numbers. </constant> <constant name="MATH_FLOOR" value="13" enum="BuiltinFunc"> - Return the input rounded down. + Returns the input rounded down. </constant> <constant name="MATH_CEIL" value="14" enum="BuiltinFunc"> - Return the input rounded up. + Returns the input rounded up. </constant> <constant name="MATH_ROUND" value="15" enum="BuiltinFunc"> - Return the input rounded to the nearest integer. + Returns the input rounded to the nearest integer. </constant> <constant name="MATH_ABS" value="16" enum="BuiltinFunc"> - Return the absolute value of the input. + Returns the absolute value of the input. </constant> <constant name="MATH_SIGN" value="17" enum="BuiltinFunc"> - Return the sign of the input, turning it into 1, -1, or 0. Useful to determine if the input is positive or negative. + Returns the sign of the input, turning it into 1, -1, or 0. Useful to determine if the input is positive or negative. </constant> <constant name="MATH_POW" value="18" enum="BuiltinFunc"> - Return the input raised to a given power. + Returns the input raised to a given power. </constant> <constant name="MATH_LOG" value="19" enum="BuiltinFunc"> - Return the natural logarithm of the input. Note that this is not the typical base-10 logarithm function calculators use. + Returns the natural logarithm of the input. Note that this is not the typical base-10 logarithm function calculators use. </constant> <constant name="MATH_EXP" value="20" enum="BuiltinFunc"> - Return the mathematical constant [b]e[/b] raised to the specified power of the input. [b]e[/b] has an approximate value of 2.71828. + Returns the mathematical constant [b]e[/b] raised to the specified power of the input. [b]e[/b] has an approximate value of 2.71828. </constant> <constant name="MATH_ISNAN" value="21" enum="BuiltinFunc"> - Return whether the input is NaN (Not a Number) or not. NaN is usually produced by dividing 0 by 0, though other ways exist. + Returns whether the input is NaN (Not a Number) or not. NaN is usually produced by dividing 0 by 0, though other ways exist. </constant> <constant name="MATH_ISINF" value="22" enum="BuiltinFunc"> - Return whether the input is an infinite floating-point number or not. Infinity is usually produced by dividing a number by 0, though other ways exist. + Returns whether the input is an infinite floating-point number or not. Infinity is usually produced by dividing a number by 0, though other ways exist. </constant> <constant name="MATH_EASE" value="23" enum="BuiltinFunc"> Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in. </constant> <constant name="MATH_STEP_DECIMALS" value="24" enum="BuiltinFunc"> - Return the number of digit places after the decimal that the first non-zero digit occurs. + Returns the number of digit places after the decimal that the first non-zero digit occurs. </constant> <constant name="MATH_SNAPPED" value="25" enum="BuiltinFunc"> - Return the input snapped to a given step. + Returns the input snapped to a given step. </constant> <constant name="MATH_LERP" value="26" enum="BuiltinFunc"> - Return a number linearly interpolated between the first two inputs, based on the third input. Uses the formula [code]a + (a - b) * t[/code]. + Returns a number linearly interpolated between the first two inputs, based on the third input. Uses the formula [code]a + (a - b) * t[/code]. </constant> - <constant name="MATH_INVERSE_LERP" value="27" enum="BuiltinFunc"> + <constant name="MATH_CUBIC_INTERPOLATE" value="27" enum="BuiltinFunc"> </constant> - <constant name="MATH_RANGE_LERP" value="28" enum="BuiltinFunc"> + <constant name="MATH_INVERSE_LERP" value="28" enum="BuiltinFunc"> </constant> - <constant name="MATH_MOVE_TOWARD" value="29" enum="BuiltinFunc"> + <constant name="MATH_RANGE_LERP" value="29" enum="BuiltinFunc"> + </constant> + <constant name="MATH_MOVE_TOWARD" value="30" enum="BuiltinFunc"> Moves the number toward a value, based on the third input. </constant> - <constant name="MATH_RANDOMIZE" value="30" enum="BuiltinFunc"> + <constant name="MATH_RANDOMIZE" value="31" enum="BuiltinFunc"> Randomize the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time. </constant> - <constant name="MATH_RANDI" value="31" enum="BuiltinFunc"> - Return a random 32 bits integer value. To obtain a random value between 0 to N (where N is smaller than 2^32 - 1), you can use it with the remainder function. + <constant name="MATH_RANDI" value="32" enum="BuiltinFunc"> + Returns a random 32 bits integer value. To obtain a random value between 0 to N (where N is smaller than 2^32 - 1), you can use it with the remainder function. </constant> - <constant name="MATH_RANDF" value="32" enum="BuiltinFunc"> - Return a random floating-point value between 0 and 1. To obtain a random value between 0 to N, you can use it with multiplication. + <constant name="MATH_RANDF" value="33" enum="BuiltinFunc"> + Returns a random floating-point value between 0 and 1. To obtain a random value between 0 to N, you can use it with multiplication. </constant> - <constant name="MATH_RANDI_RANGE" value="33" enum="BuiltinFunc"> - Return a random 32-bit integer value between the two inputs. + <constant name="MATH_RANDI_RANGE" value="34" enum="BuiltinFunc"> + Returns a random 32-bit integer value between the two inputs. </constant> - <constant name="MATH_RANDF_RANGE" value="34" enum="BuiltinFunc"> - Return a random floating-point value between the two inputs. + <constant name="MATH_RANDF_RANGE" value="35" enum="BuiltinFunc"> + Returns a random floating-point value between the two inputs. </constant> - <constant name="MATH_RANDFN" value="35" enum="BuiltinFunc"> + <constant name="MATH_RANDFN" value="36" enum="BuiltinFunc"> Returns a normally-distributed pseudo-random number, using Box-Muller transform with the specified mean and a standard deviation. This is also called Gaussian distribution. </constant> - <constant name="MATH_SEED" value="36" enum="BuiltinFunc"> + <constant name="MATH_SEED" value="37" enum="BuiltinFunc"> Set the seed for the random number generator. </constant> - <constant name="MATH_RANDSEED" value="37" enum="BuiltinFunc"> - Return a random value from the given seed, along with the new seed. + <constant name="MATH_RANDSEED" value="38" enum="BuiltinFunc"> + Returns a random value from the given seed, along with the new seed. </constant> - <constant name="MATH_DEG2RAD" value="38" enum="BuiltinFunc"> + <constant name="MATH_DEG2RAD" value="39" enum="BuiltinFunc"> Convert the input from degrees to radians. </constant> - <constant name="MATH_RAD2DEG" value="39" enum="BuiltinFunc"> + <constant name="MATH_RAD2DEG" value="40" enum="BuiltinFunc"> Convert the input from radians to degrees. </constant> - <constant name="MATH_LINEAR2DB" value="40" enum="BuiltinFunc"> + <constant name="MATH_LINEAR2DB" value="41" enum="BuiltinFunc"> Convert the input from linear volume to decibel volume. </constant> - <constant name="MATH_DB2LINEAR" value="41" enum="BuiltinFunc"> + <constant name="MATH_DB2LINEAR" value="42" enum="BuiltinFunc"> Convert the input from decibel volume to linear volume. </constant> - <constant name="MATH_WRAP" value="42" enum="BuiltinFunc"> + <constant name="MATH_WRAP" value="43" enum="BuiltinFunc"> </constant> - <constant name="MATH_WRAPF" value="43" enum="BuiltinFunc"> + <constant name="MATH_WRAPF" value="44" enum="BuiltinFunc"> </constant> - <constant name="MATH_PINGPONG" value="44" enum="BuiltinFunc"> - Return the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). If [code]length[/code] is less than zero, it becomes positive. + <constant name="MATH_PINGPONG" value="45" enum="BuiltinFunc"> + Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). If [code]length[/code] is less than zero, it becomes positive. </constant> - <constant name="LOGIC_MAX" value="45" enum="BuiltinFunc"> - Return the greater of the two numbers, also known as their maximum. + <constant name="LOGIC_MAX" value="46" enum="BuiltinFunc"> + Returns the greater of the two numbers, also known as their maximum. </constant> - <constant name="LOGIC_MIN" value="46" enum="BuiltinFunc"> - Return the lesser of the two numbers, also known as their minimum. + <constant name="LOGIC_MIN" value="47" enum="BuiltinFunc"> + Returns the lesser of the two numbers, also known as their minimum. </constant> - <constant name="LOGIC_CLAMP" value="47" enum="BuiltinFunc"> - Return the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code]. + <constant name="LOGIC_CLAMP" value="48" enum="BuiltinFunc"> + Returns the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code]. </constant> - <constant name="LOGIC_NEAREST_PO2" value="48" enum="BuiltinFunc"> - Return the nearest power of 2 to the input. + <constant name="LOGIC_NEAREST_PO2" value="49" enum="BuiltinFunc"> + Returns the nearest power of 2 to the input. </constant> - <constant name="OBJ_WEAKREF" value="49" enum="BuiltinFunc"> + <constant name="OBJ_WEAKREF" value="50" enum="BuiltinFunc"> Create a [WeakRef] from the input. </constant> - <constant name="TYPE_CONVERT" value="50" enum="BuiltinFunc"> + <constant name="TYPE_CONVERT" value="51" enum="BuiltinFunc"> Convert between types. </constant> - <constant name="TYPE_OF" value="51" enum="BuiltinFunc"> - Return the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned. + <constant name="TYPE_OF" value="52" enum="BuiltinFunc"> + Returns the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned. </constant> - <constant name="TYPE_EXISTS" value="52" enum="BuiltinFunc"> + <constant name="TYPE_EXISTS" value="53" enum="BuiltinFunc"> Checks if a type is registered in the [ClassDB]. </constant> - <constant name="TEXT_CHAR" value="53" enum="BuiltinFunc"> - Return a character with the given ascii value. + <constant name="TEXT_CHAR" value="54" enum="BuiltinFunc"> + Returns a character with the given ascii value. </constant> - <constant name="TEXT_STR" value="54" enum="BuiltinFunc"> + <constant name="TEXT_STR" value="55" enum="BuiltinFunc"> Convert the input to a string. </constant> - <constant name="TEXT_PRINT" value="55" enum="BuiltinFunc"> + <constant name="TEXT_PRINT" value="56" enum="BuiltinFunc"> Print the given string to the output window. </constant> - <constant name="TEXT_PRINTERR" value="56" enum="BuiltinFunc"> + <constant name="TEXT_PRINTERR" value="57" enum="BuiltinFunc"> Print the given string to the standard error output. </constant> - <constant name="TEXT_PRINTRAW" value="57" enum="BuiltinFunc"> + <constant name="TEXT_PRINTRAW" value="58" enum="BuiltinFunc"> Print the given string to the standard output, without adding a newline. </constant> - <constant name="TEXT_PRINT_VERBOSE" value="58" enum="BuiltinFunc"> + <constant name="TEXT_PRINT_VERBOSE" value="59" enum="BuiltinFunc"> </constant> - <constant name="VAR_TO_STR" value="59" enum="BuiltinFunc"> + <constant name="VAR_TO_STR" value="60" enum="BuiltinFunc"> Serialize a [Variant] to a string. </constant> - <constant name="STR_TO_VAR" value="60" enum="BuiltinFunc"> + <constant name="STR_TO_VAR" value="61" enum="BuiltinFunc"> Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR]. </constant> - <constant name="VAR_TO_BYTES" value="61" enum="BuiltinFunc"> + <constant name="VAR_TO_BYTES" value="62" enum="BuiltinFunc"> Serialize a [Variant] to a [PackedByteArray]. </constant> - <constant name="BYTES_TO_VAR" value="62" enum="BuiltinFunc"> + <constant name="BYTES_TO_VAR" value="63" enum="BuiltinFunc"> Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES]. </constant> - <constant name="MATH_SMOOTHSTEP" value="63" enum="BuiltinFunc"> - Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula: + <constant name="MATH_SMOOTHSTEP" value="64" enum="BuiltinFunc"> + Returns a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula: [codeblock] var t = clamp((weight - from) / (to - from), 0.0, 1.0) return t * t * (3.0 - 2.0 * t) [/codeblock] </constant> - <constant name="MATH_POSMOD" value="64" enum="BuiltinFunc"> + <constant name="MATH_POSMOD" value="65" enum="BuiltinFunc"> </constant> - <constant name="MATH_LERP_ANGLE" value="65" enum="BuiltinFunc"> + <constant name="MATH_LERP_ANGLE" value="66" enum="BuiltinFunc"> </constant> - <constant name="TEXT_ORD" value="66" enum="BuiltinFunc"> + <constant name="TEXT_ORD" value="67" enum="BuiltinFunc"> </constant> - <constant name="FUNC_MAX" value="67" enum="BuiltinFunc"> + <constant name="FUNC_MAX" value="68" enum="BuiltinFunc"> Represents the size of the [enum BuiltinFunc] enum. </constant> </constants> diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml index ae32500d2f..2509084f0e 100644 --- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptClassConstant" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptClassConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Gets a constant from a given class. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml index 5024aae384..cf4b57ca19 100644 --- a/modules/visual_script/doc_classes/VisualScriptComment.xml +++ b/modules/visual_script/doc_classes/VisualScriptComment.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptComment" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptComment" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node used to annotate the script. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml b/modules/visual_script/doc_classes/VisualScriptComposeArray.xml index ed065759c5..ea73867c4b 100644 --- a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml +++ b/modules/visual_script/doc_classes/VisualScriptComposeArray.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptComposeArray" inherits="VisualScriptLists" version="4.0"> +<class name="VisualScriptComposeArray" inherits="VisualScriptLists" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script Node used to create array from a list of items. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml index a5dd8c7c1b..a29388569f 100644 --- a/modules/visual_script/doc_classes/VisualScriptCondition.xml +++ b/modules/visual_script/doc_classes/VisualScriptCondition.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCondition" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptCondition" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node which branches the flow. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml index 388c2bddde..645ede9001 100644 --- a/modules/visual_script/doc_classes/VisualScriptConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptConstant" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Gets a contant's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml index 4a3d10aa8e..5ec17350bd 100644 --- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml +++ b/modules/visual_script/doc_classes/VisualScriptConstructor.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptConstructor" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptConstructor" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node which calls a base type constructor. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml index 2c6313c80a..97b89fb987 100644 --- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCustomNode" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptCustomNode" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A scripted Visual Script node. </brief_description> @@ -12,112 +12,112 @@ <method name="_get_caption" qualifiers="virtual const"> <return type="String" /> <description> - Return the node's title. + Returns the node's title. </description> </method> <method name="_get_category" qualifiers="virtual const"> <return type="String" /> <description> - Return the node's category. + Returns the node's category. </description> </method> <method name="_get_input_value_port_count" qualifiers="virtual const"> <return type="int" /> <description> - Return the count of input value ports. + Returns the count of input value ports. </description> </method> <method name="_get_input_value_port_hint" qualifiers="virtual const"> <return type="int" /> <argument index="0" name="input_idx" type="int" /> <description> - Return the specified input port's hint. See the [enum @GlobalScope.PropertyHint] hints. + Returns the specified input port's hint. See the [enum @GlobalScope.PropertyHint] hints. </description> </method> <method name="_get_input_value_port_hint_string" qualifiers="virtual const"> <return type="String" /> <argument index="0" name="input_idx" type="int" /> <description> - Return the specified input port's hint string. + Returns the specified input port's hint string. </description> </method> <method name="_get_input_value_port_name" qualifiers="virtual const"> <return type="String" /> <argument index="0" name="input_idx" type="int" /> <description> - Return the specified input port's name. + Returns the specified input port's name. </description> </method> <method name="_get_input_value_port_type" qualifiers="virtual const"> <return type="int" /> <argument index="0" name="input_idx" type="int" /> <description> - Return the specified input port's type. See the [enum Variant.Type] values. + Returns the specified input port's type. See the [enum Variant.Type] values. </description> </method> <method name="_get_output_sequence_port_count" qualifiers="virtual const"> <return type="int" /> <description> - Return the amount of output [b]sequence[/b] ports. + Returns the amount of output [b]sequence[/b] ports. </description> </method> <method name="_get_output_sequence_port_text" qualifiers="virtual const"> <return type="String" /> <argument index="0" name="seq_idx" type="int" /> <description> - Return the specified [b]sequence[/b] output's name. + Returns the specified [b]sequence[/b] output's name. </description> </method> <method name="_get_output_value_port_count" qualifiers="virtual const"> <return type="int" /> <description> - Return the amount of output value ports. + Returns the amount of output value ports. </description> </method> <method name="_get_output_value_port_hint" qualifiers="virtual const"> <return type="int" /> <argument index="0" name="output_idx" type="int" /> <description> - Return the specified output port's hint. See the [enum @GlobalScope.PropertyHint] hints. + Returns the specified output port's hint. See the [enum @GlobalScope.PropertyHint] hints. </description> </method> <method name="_get_output_value_port_hint_string" qualifiers="virtual const"> <return type="String" /> <argument index="0" name="output_idx" type="int" /> <description> - Return the specified output port's hint string. + Returns the specified output port's hint string. </description> </method> <method name="_get_output_value_port_name" qualifiers="virtual const"> <return type="String" /> <argument index="0" name="output_idx" type="int" /> <description> - Return the specified output port's name. + Returns the specified output port's name. </description> </method> <method name="_get_output_value_port_type" qualifiers="virtual const"> <return type="int" /> <argument index="0" name="output_idx" type="int" /> <description> - Return the specified output port's type. See the [enum Variant.Type] values. + Returns the specified output port's type. See the [enum Variant.Type] values. </description> </method> <method name="_get_text" qualifiers="virtual const"> <return type="String" /> <description> - Return the custom node's text, which is shown right next to the input [b]sequence[/b] port (if there is none, on the place that is usually taken by it). + Returns the custom node's text, which is shown right next to the input [b]sequence[/b] port (if there is none, on the place that is usually taken by it). </description> </method> <method name="_get_working_memory_size" qualifiers="virtual const"> <return type="int" /> <description> - Return the size of the custom node's working memory. See [method _step] for more details. + Returns the size of the custom node's working memory. See [method _step] for more details. </description> </method> <method name="_has_input_sequence_port" qualifiers="virtual const"> <return type="bool" /> <description> - Return whether the custom node has an input [b]sequence[/b] port. + Returns whether the custom node has an input [b]sequence[/b] port. </description> </method> <method name="_step" qualifiers="virtual const"> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml index 1681da7653..f04c862174 100644 --- a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml +++ b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCustomNodes" inherits="Object" version="4.0"> +<class name="VisualScriptCustomNodes" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Manages custom nodes for the Visual Script editor. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml index fd9a91c2a5..b544fd9d90 100644 --- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml +++ b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node which deconstructs a base type instance into its parts. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml index e102e02aa9..c0cefa0ab7 100644 --- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Emits a specified signal. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml index 468cae852f..f60a048845 100644 --- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml +++ b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node returning a singleton from [@GlobalScope]. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml index 15e16a15f0..14750e7c8d 100644 --- a/modules/visual_script/doc_classes/VisualScriptExpression.xml +++ b/modules/visual_script/doc_classes/VisualScriptExpression.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptExpression" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptExpression" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node that can execute a custom expression. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml index e0ca9eb280..74d9f194eb 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunction.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunction.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunction" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptFunction" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node representing a function. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml index a98cb79106..543263ff8e 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node for calling a function. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml index 0d7833446d..ef09c9d4a0 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0"> +<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node representing a function state. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml index c6b5b22590..42ada99257 100644 --- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node returning a constant from [@GlobalScope]. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml index 78fd17c5fc..8828bf9039 100644 --- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIndexGet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptIndexGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node for getting a value from an array or a dictionary. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml index 0e5e832c65..5c81dcd339 100644 --- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIndexSet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptIndexSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node for setting a value in an array or a dictionary. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml index eb06d52314..51c2eaf353 100644 --- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml +++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptInputAction" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptInputAction" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node returning a state of an action. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml index d8305728c6..ef6846deba 100644 --- a/modules/visual_script/doc_classes/VisualScriptIterator.xml +++ b/modules/visual_script/doc_classes/VisualScriptIterator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIterator" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptIterator" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Steps through items in a given input. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml index 373e3c7191..27a81fce2f 100644 --- a/modules/visual_script/doc_classes/VisualScriptLists.xml +++ b/modules/visual_script/doc_classes/VisualScriptLists.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLists" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptLists" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script virtual class for in-graph editable nodes. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml index 29dbddcdf4..dbf9049f0a 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLocalVar" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptLocalVar" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Gets a local variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml index 96de8ebfdd..1ae4e20f97 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Changes a local variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml index f559083c80..01c36e763b 100644 --- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptMathConstant" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptMathConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Commonly used mathematical constants. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml index d080d9eac1..2eb99dc25f 100644 --- a/modules/visual_script/doc_classes/VisualScriptNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptNode" inherits="Resource" version="4.0"> +<class name="VisualScriptNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A node which is part of a [VisualScript]. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml index 73d28899f6..47ca6ddb90 100644 --- a/modules/visual_script/doc_classes/VisualScriptOperator.xml +++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptOperator" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptOperator" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node that performs an operation on two values. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml index e3d60c77bb..146d6cd9c3 100644 --- a/modules/visual_script/doc_classes/VisualScriptPreload.xml +++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPreload" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptPreload" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Creates a new [Resource] or loads one from the filesystem. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml index e9f30cb605..77cd6393a9 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node returning a value of a property from an [Object]. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml index 96261d2c5e..6cffa328c7 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPropertySet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptPropertySet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node that sets a property of an [Object]. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml index 77e97a7219..6ca8260ade 100644 --- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml +++ b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptResourcePath" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptResourcePath" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml index 2193f45dc8..1d59392782 100644 --- a/modules/visual_script/doc_classes/VisualScriptReturn.xml +++ b/modules/visual_script/doc_classes/VisualScriptReturn.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptReturn" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptReturn" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Exits a function and returns an optional value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml index ac672d9b3f..a769d11d94 100644 --- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSceneNode" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSceneNode" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Node reference. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml index fc383593c5..84ab90892f 100644 --- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml +++ b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSceneTree" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSceneTree" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node for accessing [SceneTree] methods. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml index d536e623f7..1aa916f779 100644 --- a/modules/visual_script/doc_classes/VisualScriptSelect.xml +++ b/modules/visual_script/doc_classes/VisualScriptSelect.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSelect" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSelect" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Chooses between two input values. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml index 3c2bd16302..8cc59dbccd 100644 --- a/modules/visual_script/doc_classes/VisualScriptSelf.xml +++ b/modules/visual_script/doc_classes/VisualScriptSelf.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSelf" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSelf" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Outputs a reference to the current instance. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml index 32dcbb9837..9adbc30e0d 100644 --- a/modules/visual_script/doc_classes/VisualScriptSequence.xml +++ b/modules/visual_script/doc_classes/VisualScriptSequence.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSequence" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSequence" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Executes a series of Sequence ports. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml index fdf0e24d3e..535e89fc82 100644 --- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSubCall" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSubCall" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Calls a method called [code]_subcall[/code] in this object. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml index 8e176b56f0..7befe89f50 100644 --- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml +++ b/modules/visual_script/doc_classes/VisualScriptSwitch.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSwitch" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptSwitch" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Branches program flow based on a given input's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml index ee8e2ad31e..ec84a75601 100644 --- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml +++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptTypeCast" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptTypeCast" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node that casts the given value to another type. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml index e29765d616..8d99b4b9d0 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptVariableGet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptVariableGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Gets a variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml index b2cc70d62e..4f568cc0f6 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptVariableSet" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptVariableSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Changes a variable's value. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml index f090568608..4e7cccef17 100644 --- a/modules/visual_script/doc_classes/VisualScriptWhile.xml +++ b/modules/visual_script/doc_classes/VisualScriptWhile.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptWhile" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptWhile" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Conditional loop. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml index bb7fd8bfb5..ec757a3ac4 100644 --- a/modules/visual_script/doc_classes/VisualScriptYield.xml +++ b/modules/visual_script/doc_classes/VisualScriptYield.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptYield" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptYield" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node used to pause a function execution. </brief_description> diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml index ad6a7fb4e2..c3f4bc49c5 100644 --- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" version="4.0"> +<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A Visual Script node yielding for a signal. </brief_description> diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 991d258054..3e6680d8d8 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -42,6 +42,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "scene/gui/view_panner.h" #include "scene/main/window.h" #ifdef TOOLS_ENABLED @@ -271,7 +272,7 @@ protected: if (String(p_name) == "export") { script->set_variable_export(var, p_value); - EditorNode::get_singleton()->get_inspector()->update_tree(); + InspectorDock::get_inspector_singleton()->update_tree(); return true; } @@ -652,7 +653,6 @@ void VisualScriptEditor::_update_graph(int p_only_id) { List<int> ids; script->get_node_list(&ids); - StringName editor_icons = "EditorIcons"; for (int &E : ids) { if (p_only_id >= 0 && p_only_id != E) { @@ -1081,6 +1081,7 @@ void VisualScriptEditor::_update_members() { Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")), + Control::get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")), @@ -1090,7 +1091,9 @@ void VisualScriptEditor::_update_members() { Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")), + Control::get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")), + Control::get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")), Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")), @@ -1099,6 +1102,7 @@ void VisualScriptEditor::_update_members() { List<StringName> var_names; script->get_variable_list(&var_names); + var_names.sort_custom<StringName::AlphCompare>(); for (const StringName &E : var_names) { TreeItem *ti = members->create_item(variables); @@ -1366,7 +1370,7 @@ void VisualScriptEditor::_create_function() { } void VisualScriptEditor::_add_node_dialog() { - _generic_search(script->get_instance_base_type(), graph->get_global_position() + Vector2(55, 80), true); + _generic_search(graph->get_global_position() + Vector2(55, 80), true); } void VisualScriptEditor::_add_func_input() { @@ -1442,7 +1446,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt if (p_button == 1) { // Ensure script base exists otherwise use custom base type. ERR_FAIL_COND(script.is_null()); - new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), String(), true); + new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), true); return; } else if (p_button == 0) { String name = _validate_name("new_function"); @@ -1510,6 +1514,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt function_name_edit->popup(); function_name_box->set_text(selected); function_name_box->select_all(); + function_name_box->grab_focus(); } } @@ -1616,7 +1621,7 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) { conn_map.get_key_list(&keys); for (const int &E : keys) { for (const Set<int>::Element *F = conn_map[E].front(); F; F = F->next()) { - undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E, F); + undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E, F->get()); } } @@ -1948,14 +1953,14 @@ void VisualScriptEditor::_on_nodes_duplicate() { } } -void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool node_centered) { +void VisualScriptEditor::_generic_search(Vector2 pos, bool node_centered) { if (node_centered) { port_action_pos = graph->get_size() / 2.0f; } else { port_action_pos = graph->get_viewport()->get_mouse_position() - graph->get_global_position(); } - new_connect_node_select->select_from_visual_script(p_base_type, false, false); // neither connecting nor reset text + new_connect_node_select->select_from_visual_script(script, false); // do not reset text // Ensure that the dialog fits inside the graph. Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size(); @@ -1973,7 +1978,7 @@ void VisualScriptEditor::input(const Ref<InputEvent> &p_event) { // GUI input for VS Editor Plugin Ref<InputEventMouseButton> key = p_event; - if (key.is_valid() && !key->is_pressed()) { + if (key.is_valid() && key->is_pressed()) { mouse_up_position = get_screen_position() + get_local_mouse_position(); } } @@ -1982,10 +1987,28 @@ void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> key = p_event; if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MouseButton::RIGHT) { - saved_position = graph->get_local_mouse_position(); + bool is_empty_selection = true; + + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn && gn->is_selected()) { + is_empty_selection = false; + break; + } + } + if (is_empty_selection && clipboard->nodes.is_empty()) { + _generic_search(); + } else { + popup_menu->set_item_disabled(int(EDIT_CUT_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_COPY_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_PASTE_NODES), clipboard->nodes.is_empty()); + popup_menu->set_item_disabled(int(EDIT_DELETE_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_DUPLICATE_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_CLEAR_COPY_BUFFER), clipboard->nodes.is_empty()); - Point2 gpos = get_screen_position() + get_local_mouse_position(); - _generic_search(script->get_instance_base_type(), gpos); + popup_menu->set_position(mouse_up_position); + popup_menu->popup(); + } } } @@ -2080,11 +2103,15 @@ void VisualScriptEditor::_fn_name_box_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> key = p_event; if (key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ENTER) { function_name_edit->hide(); - _rename_function(selected, function_name_box->get_text()); + _on_fn_name_box_confirmed(); function_name_box->clear(); } } +void VisualScriptEditor::_on_fn_name_box_confirmed() { + _rename_function(selected, function_name_box->get_text()); +} + Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { if (p_from == members) { TreeItem *it = members->get_item_at_position(p_point); @@ -2428,7 +2455,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da drop_position = pos; drop_node = node; drop_path = sn->get_path_to(node); - new_connect_node_select->select_from_instance(node, "", false, node->get_class()); + new_connect_node_select->select_from_instance(node, false); } undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2584,11 +2611,11 @@ void VisualScriptEditor::_button_resource_previewed(const String &p_path, const void VisualScriptEditor::apply_code() { } -RES VisualScriptEditor::get_edited_resource() const { +Ref<Resource> VisualScriptEditor::get_edited_resource() const { return script; } -void VisualScriptEditor::set_edited_resource(const RES &p_res) { +void VisualScriptEditor::set_edited_resource(const Ref<Resource> &p_res) { ERR_FAIL_COND(script.is_valid()); ERR_FAIL_COND(p_res.is_null()); script = p_res; @@ -2637,6 +2664,15 @@ String VisualScriptEditor::get_name() { } Ref<Texture2D> VisualScriptEditor::get_theme_icon() { + String icon_name = "VisualScript"; + if (script->is_built_in()) { + icon_name += "Internal"; + } + + if (Control::has_theme_icon(icon_name, "EditorIcons")) { + return Control::get_theme_icon(icon_name, SNAME("EditorIcons")); + } + return Control::get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); } @@ -2691,7 +2727,7 @@ void VisualScriptEditor::_center_on_node(int p_id) { if (gn) { gn->set_selected(true); - Vector2 new_scroll = gn->get_position_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5; + Vector2 new_scroll = gn->get_position_offset() * graph->get_zoom() - graph->get_size() * 0.5 + gn->get_size() * 0.5; graph->set_scroll_ofs(new_scroll); script->set_scroll(new_scroll / EDSCALE); script->set_edited(true); @@ -2775,7 +2811,7 @@ void VisualScriptEditor::add_callback(const String &p_function, PackedStringArra String name = p_args[i]; Variant::Type type = Variant::NIL; - if (name.find(":") != -1) { + if (name.contains(":")) { String tt = name.get_slice(":", 1); name = name.get_slice(":", 0); for (int j = 0; j < Variant::VARIANT_MAX; j++) { @@ -2819,7 +2855,7 @@ Control *VisualScriptEditor::get_base_editor() const { return graph; } -void VisualScriptEditor::set_tooltip_request_func(String p_method, Object *p_obj) { +void VisualScriptEditor::set_tooltip_request_func(const Callable &p_toolip_callback) { } Control *VisualScriptEditor::get_edit_menu() { @@ -3207,19 +3243,34 @@ void VisualScriptEditor::_port_action_menu(int p_option) { n->set_base_type("Object"); } String type_string; + String base_script = ""; if (script->get_node(port_action_node)->get_output_value_port_count() > 0) { type_string = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string; + VisualScriptFunctionCall *vsfc = Object::cast_to<VisualScriptFunctionCall>(*script->get_node(port_action_node)); + if (vsfc) { + base_script = vsfc->get_base_script(); + } else { + VisualScriptPropertyGet *vspg = Object::cast_to<VisualScriptPropertyGet>(*script->get_node(port_action_node)); + if (vspg) { + base_script = vspg->get_base_script(); + } else { + VisualScriptPropertySet *vsps = Object::cast_to<VisualScriptPropertySet>(*script->get_node(port_action_node)); + if (vsps) { + base_script = vsps->get_base_script(); + } + } + } } if (tg.type == Variant::OBJECT) { if (tg.script.is_valid()) { - new_connect_node_select->select_from_script(tg.script, ""); - } else if (!type_string.is_empty()) { - new_connect_node_select->select_from_base_type(type_string); + new_connect_node_select->select_from_script(tg.script); + } else if (type_string != String()) { + new_connect_node_select->select_from_base_type(type_string, base_script); } else { - new_connect_node_select->select_from_base_type(n->get_base_type()); + new_connect_node_select->select_from_base_type(n->get_base_type(), base_script); } } else if (tg.type == Variant::NIL) { - new_connect_node_select->select_from_base_type(""); + new_connect_node_select->select_from_base_type("", base_script); } else { new_connect_node_select->select_from_basic_type(tg.type); } @@ -3282,66 +3333,54 @@ 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) { +#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::CTRL); +#endif Vector2 pos = _get_pos_in_graph(port_action_pos); Set<int> vn; + bool port_node_exists = true; if (drop_position != Vector2()) { pos = drop_position; } drop_position = Vector2(); - bool port_node_exists = true; - - // if (func == StringName()) { - // func = default_func; - // port_node_exists = false; - // } - - if (p_category == "visualscript") { - Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text); - Ref<VisualScriptNode> vnode_old; - if (port_node_exists && p_connecting) { - vnode_old = script->get_node(port_action_node); - } - int new_id = script->get_available_id(); + Ref<VisualScriptNode> vnode; + Ref<VisualScriptNode> vnode_old; + if (port_node_exists && p_connecting) { + vnode_old = script->get_node(port_action_node); + } - if (Object::cast_to<VisualScriptOperator>(vnode_new.ptr()) && vnode_old.is_valid()) { - Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type; - Object::cast_to<VisualScriptOperator>(vnode_new.ptr())->set_typed(type); - } + if (p_category.begins_with("VisualScriptNode")) { + Ref<VisualScriptNode> n = VisualScriptLanguage::singleton->create_node_from_name(p_text); - if (Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr()) && vnode_old.is_valid()) { + if (Object::cast_to<VisualScriptTypeCast>(n.ptr()) && vnode_old.is_valid()) { Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type; String hint_name = vnode_old->get_output_value_port_info(port_action_output).hint_string; if (type == Variant::OBJECT) { - Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(hint_name); + Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(hint_name); } else if (type == Variant::NIL) { - Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(""); + Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(""); } else { - Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(Variant::get_type_name(type)); + Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(Variant::get_type_name(type)); } } - - undo_redo->create_action(TTR("Add Node")); - 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); - } - - 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"); - undo_redo->commit_action(); - return; + vnode = n; } - Ref<VisualScriptNode> vnode; - Ref<VisualScriptPropertySet> script_prop_set; - - if (p_category == String("method")) { + if (p_category == String("Class") && !p_connecting) { + Ref<VisualScriptFunctionCall> n; + n.instantiate(); + n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SINGLETON); + n->set_singleton("ClassDB"); + n->set_function("instantiate"); + // Did not find a way to edit the input port value + vnode = n; + } else if (p_category == String("class_method")) { Ref<VisualScriptFunctionCall> n; n.instantiate(); if (!drop_path.is_empty()) { @@ -3351,6 +3390,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH); n->set_base_path(drop_path); } + } else { + n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); } if (drop_node) { n->set_base_type(drop_node->get_class()); @@ -3359,96 +3400,151 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } } vnode = n; - } else if (p_category == String("set")) { - Ref<VisualScriptPropertySet> n; - n.instantiate(); - if (!drop_path.is_empty()) { - if (drop_path == ".") { - n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); - } else { - n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); - n->set_base_path(drop_path); + } else if (p_category == String("class_property")) { + Vector<String> property_path = p_text.split(":"); + if (held_ctrl) { + Ref<VisualScriptPropertySet> n; + n.instantiate(); + n->set_property(property_path[1]); + if (!drop_path.is_empty()) { + if (drop_path == ".") { + n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); + } else { + n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); + n->set_base_path(drop_path); + } } - } - if (drop_node) { - n->set_base_type(drop_node->get_class()); - if (drop_node->get_script_instance()) { - n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); + if (drop_node) { + n->set_base_type(drop_node->get_class()); + if (drop_node->get_script_instance()) { + n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); + } } - } - vnode = n; - script_prop_set = n; - } else if (p_category == String("get")) { - Ref<VisualScriptPropertyGet> n; - n.instantiate(); - n->set_property(p_text); - if (!drop_path.is_empty()) { - if (drop_path == ".") { - n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); - } else { - n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); - n->set_base_path(drop_path); + vnode = n; + } else { + Ref<VisualScriptPropertyGet> n; + n.instantiate(); + n->set_property(property_path[1]); + if (!drop_path.is_empty()) { + if (drop_path == ".") { + n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); + } else { + n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); + n->set_base_path(drop_path); + } } - } - if (drop_node) { - n->set_base_type(drop_node->get_class()); - if (drop_node->get_script_instance()) { - n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); + if (drop_node) { + n->set_base_type(drop_node->get_class()); + if (drop_node->get_script_instance()) { + n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); + } } - } - vnode = n; - } - drop_path = String(); - drop_node = nullptr; - - if (p_category == String("action")) { - if (p_text == "VisualScriptCondition") { - Ref<VisualScriptCondition> n; - n.instantiate(); vnode = n; } - if (p_text == "VisualScriptSwitch") { - Ref<VisualScriptSwitch> n; + } else if (p_category == String("class_constant")) { + Vector<String> property_path = p_text.split(":"); + if (ClassDB::class_exists(property_path[0])) { + Ref<VisualScriptClassConstant> n; n.instantiate(); + n->set_base_type(property_path[0]); + n->set_class_constant(property_path[1]); vnode = n; - } else if (p_text == "VisualScriptSequence") { - Ref<VisualScriptSequence> n; - n.instantiate(); - vnode = n; - } else if (p_text == "VisualScriptIterator") { - Ref<VisualScriptIterator> n; - n.instantiate(); - vnode = n; - } else if (p_text == "VisualScriptWhile") { - Ref<VisualScriptWhile> n; - n.instantiate(); - vnode = n; - } else if (p_text == "VisualScriptReturn") { - Ref<VisualScriptReturn> n; + } else { + Ref<VisualScriptBasicTypeConstant> n; n.instantiate(); + if (property_path[0] == "Nil") { + n->set_basic_type(Variant::NIL); + } else if (property_path[0] == "bool") { + n->set_basic_type(Variant::BOOL); + } else if (property_path[0] == "int") { + n->set_basic_type(Variant::INT); + } else if (property_path[0] == "float") { + n->set_basic_type(Variant::FLOAT); + } else if (property_path[0] == "String") { + n->set_basic_type(Variant::STRING); + } else if (property_path[0] == "Vector2") { + n->set_basic_type(Variant::VECTOR2); + } else if (property_path[0] == "Vector2i") { + n->set_basic_type(Variant::VECTOR2I); + } else if (property_path[0] == "Rect2") { + n->set_basic_type(Variant::RECT2); + } else if (property_path[0] == "Rect2i") { + n->set_basic_type(Variant::RECT2I); + } else if (property_path[0] == "Transform2D") { + n->set_basic_type(Variant::TRANSFORM2D); + } else if (property_path[0] == "Vector3") { + n->set_basic_type(Variant::VECTOR3); + } else if (property_path[0] == "Vector3i") { + n->set_basic_type(Variant::VECTOR3I); + } else if (property_path[0] == "Plane") { + n->set_basic_type(Variant::PLANE); + } else if (property_path[0] == "ABB") { + n->set_basic_type(Variant::AABB); + } else if (property_path[0] == "Quaternion") { + n->set_basic_type(Variant::QUATERNION); + } else if (property_path[0] == "Basis") { + n->set_basic_type(Variant::BASIS); + } else if (property_path[0] == "Transform3D") { + n->set_basic_type(Variant::TRANSFORM3D); + } else if (property_path[0] == "Color") { + n->set_basic_type(Variant::COLOR); + } else if (property_path[0] == "RID") { + n->set_basic_type(Variant::RID); + } else if (property_path[0] == "Object") { + n->set_basic_type(Variant::OBJECT); + } else if (property_path[0] == "Callable") { + n->set_basic_type(Variant::CALLABLE); + } else if (property_path[0] == "Signal") { + n->set_basic_type(Variant::SIGNAL); + } else if (property_path[0] == "StringName") { + n->set_basic_type(Variant::STRING_NAME); + } else if (property_path[0] == "NodePath") { + n->set_basic_type(Variant::NODE_PATH); + } else if (property_path[0] == "Dictionary") { + n->set_basic_type(Variant::DICTIONARY); + } else if (property_path[0] == "Array") { + n->set_basic_type(Variant::ARRAY); + } else if (property_path[0] == "PackedByteArray") { + n->set_basic_type(Variant::PACKED_BYTE_ARRAY); + } else if (property_path[0] == "PackedInt32Array") { + n->set_basic_type(Variant::PACKED_INT32_ARRAY); + } else if (property_path[0] == "PackedInt64Array") { + n->set_basic_type(Variant::PACKED_INT64_ARRAY); + } else if (property_path[0] == "PackedFloat32Array") { + n->set_basic_type(Variant::PACKED_FLOAT32_ARRAY); + } else if (property_path[0] == "PackedStringArray") { + n->set_basic_type(Variant::PACKED_STRING_ARRAY); + } else if (property_path[0] == "PackedVector2Array") { + n->set_basic_type(Variant::PACKED_VECTOR2_ARRAY); + } else if (property_path[0] == "PackedVector3Array") { + n->set_basic_type(Variant::PACKED_VECTOR3_ARRAY); + } else if (property_path[0] == "PackedColorArray") { + n->set_basic_type(Variant::PACKED_COLOR_ARRAY); + } + n->set_basic_type_constant(property_path[1]); 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, 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); - undo_redo->commit_action(); + } else if (p_category == String("class_signal")) { + Vector<String> property_path = p_text.split(":"); + ERR_FAIL_COND(!(script->has_custom_signal(property_path[1]) || ClassDB::has_signal(script->get_instance_base_type(), property_path[1]))); - if (script_prop_set.is_valid()) { - script_prop_set->set_property(p_text); + Ref<VisualScriptEmitSignal> n; + n.instantiate(); + n->set_signal(property_path[1]); + vnode = n; + } + if (vnode == nullptr) { + print_error("Category not handled: " + p_category.quote()); } - port_action_new_node = new_id; - - Ref<VisualScriptNode> vsn = script->get_node(port_action_new_node); + if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr()) && p_category != "Class" && p_category != "VisualScriptNode") { + Vector<String> property_path = p_text.split(":"); + String class_of_method = property_path[0]; + String method_name = property_path[1]; - if (Object::cast_to<VisualScriptFunctionCall>(vsn.ptr())) { - Ref<VisualScriptFunctionCall> vsfc = vsn; - vsfc->set_function(p_text); + Ref<VisualScriptFunctionCall> vsfc = vnode; + vsfc->set_function(method_name); if (port_node_exists && p_connecting) { VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); @@ -3465,7 +3561,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) { vsfc->set_base_type(base_type); } - if (p_text == "call" || p_text == "call_deferred") { + if (method_name == "call" || method_name == "call_deferred") { vsfc->set_function(String("")); } } @@ -3483,8 +3579,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } if (port_node_exists && p_connecting) { - if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) { - Ref<VisualScriptPropertySet> vsp = vsn; + if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) { + Ref<VisualScriptPropertySet> vsp = vnode; VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); if (tg.type == Variant::OBJECT) { @@ -3513,8 +3609,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } } - if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) { - Ref<VisualScriptPropertyGet> vsp = vsn; + if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) { + Ref<VisualScriptPropertyGet> vsp = vnode; VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); if (tg.type == Variant::OBJECT) { @@ -3542,13 +3638,90 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } } } + if (vnode == nullptr) { + print_error("Not able to create node from category: \"" + p_category + "\" and text \"" + p_text + "\" Not created"); + return; + } + + 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, 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); + undo_redo->commit_action(); + + port_action_new_node = new_id; + + String base_script = ""; + String base_type = ""; if (port_node_exists) { - Ref<VisualScriptNode> vnode_old = script->get_node(port_action_node); + if (vnode_old.is_valid()) { + if (Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())) { + base_type = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_type(); + base_script = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_script(); + } else if (Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())) { + base_type = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_type(); + base_script = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_script(); + } else if (Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())) { + base_type = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_type(); + base_script = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_script(); + } else if (Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())) { + base_type = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_type(); + base_script = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_script(); + } + } + + Vector<String> property_path = p_text.split(":"); + if (ClassDB::is_parent_class(script->get_instance_base_type(), property_path[0]) || script->get_path().ends_with(property_path[0].unquote())) { + if (!p_connecting) { + base_type = script->get_instance_base_type(); + base_script = script->get_path(); + } + } else { + base_type = property_path[0]; + base_script = ""; + } + + if (drop_node) { + Ref<Script> script = drop_node->get_script(); + if (script != nullptr) { + base_script = script->get_path(); + } + } + if (vnode_old.is_valid() && p_connecting) { + if (base_type == "") { + base_type = property_path[0]; + } else if (ClassDB::is_parent_class(property_path[0], base_type)) { + base_type = property_path[0]; + } connect_seq(vnode_old, vnode, port_action_new_node); connect_data(vnode_old, vnode, port_action_new_node); } } + if (Object::cast_to<VisualScriptTypeCast>(vnode.ptr())) { + Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_type(base_type); + Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_script(base_script); + } else if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())) { + if (base_type_map.has(base_type)) { + Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_basic_type(base_type_map[base_type]); + Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); + } else { + Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type); + Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script); + } + } else if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) { + Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_type(base_type); + Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_script(base_script); + } else if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) { + Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_type(base_type); + Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_script(base_script); + } + + drop_path = String(); + drop_node = nullptr; + _update_graph(port_action_new_node); } @@ -3598,7 +3771,7 @@ void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<Visual } void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting) { - String name = p_text; + String name = p_text.substr(p_text.find_char(':') + 1); if (script->has_function(name)) { EditorNode::get_singleton()->show_warning(vformat(TTR("Script already has function '%s'"), name)); return; @@ -3753,6 +3926,12 @@ void VisualScriptEditor::_toggle_scripts_pressed() { void VisualScriptEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); + graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"))); + } break; + case NOTIFICATION_READY: { variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED); @@ -3810,6 +3989,7 @@ void VisualScriptEditor::_notification(int p_what) { _update_graph(); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { update_toggle_scripts_button(); members_section->set_visible(is_visible_in_tree()); @@ -3868,6 +4048,9 @@ void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_ void VisualScriptEditor::_menu_option(int p_what) { switch (p_what) { + case EDIT_ADD_NODE: { + _generic_search(); + } break; case EDIT_DELETE_NODES: { _on_nodes_delete(); } break; @@ -3896,7 +4079,7 @@ void VisualScriptEditor::_menu_option(int p_what) { } break; case EDIT_FIND_NODE_TYPE: { - _generic_search(script->get_instance_base_type()); + _generic_search(); } break; case EDIT_COPY_NODES: { _on_nodes_copy(); @@ -3908,6 +4091,9 @@ void VisualScriptEditor::_menu_option(int p_what) { case EDIT_PASTE_NODES: { _on_nodes_paste(); } break; + case EDIT_DUPLICATE_NODES: { + _on_nodes_duplicate(); + } break; case EDIT_CREATE_FUNCTION: { // Create Function. Map<int, Ref<VisualScriptNode>> nodes; @@ -4135,6 +4321,12 @@ void VisualScriptEditor::_menu_option(int p_what) { case REFRESH_GRAPH: { _update_graph(); } break; + case EDIT_CLEAR_COPY_BUFFER: { + clipboard->nodes.clear(); + clipboard->nodes_positions.clear(); + clipboard->data_connections.clear(); + clipboard->sequence_connections.clear(); + } break; } } @@ -4240,6 +4432,7 @@ void VisualScriptEditor::_member_option(int p_option) { function_name_edit->popup(); function_name_box->set_text(selected); function_name_box->select_all(); + function_name_box->grab_focus(); } } break; case MEMBER_VARIABLE: { @@ -4322,9 +4515,6 @@ VisualScriptEditor::VisualScriptEditor() { if (!clipboard) { clipboard = memnew(Clipboard); } - updating_graph = false; - saved_pos_dirty = false; - saved_position = Vector2(0, 0); edit_menu = memnew(MenuButton); edit_menu->set_shortcut_context(this); @@ -4373,9 +4563,11 @@ VisualScriptEditor::VisualScriptEditor() { member_popup->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_member_option)); function_name_edit = memnew(AcceptDialog); + function_name_edit->set_title(TTR("Rename Function")); 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_edit->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_on_fn_name_box_confirmed)); function_name_box->set_expand_to_text_length_enabled(true); add_child(function_name_edit); @@ -4540,8 +4732,6 @@ VisualScriptEditor::VisualScriptEditor() { undo_redo = EditorNode::get_singleton()->get_undo_redo(); - updating_members = false; - set_process_input(true); default_value_edit = memnew(CustomPropertyEditor); @@ -4556,6 +4746,47 @@ VisualScriptEditor::VisualScriptEditor() { new_virtual_method_select = memnew(VisualScriptPropertySelector); add_child(new_virtual_method_select); new_virtual_method_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_new_virtual_method)); + + popup_menu = memnew(PopupMenu); + add_child(popup_menu); + popup_menu->add_item(TTR("Add Node"), EDIT_ADD_NODE); + popup_menu->add_separator(); + popup_menu->add_item(TTR("Cut"), EDIT_CUT_NODES); + popup_menu->add_item(TTR("Copy"), EDIT_COPY_NODES); + popup_menu->add_item(TTR("Paste"), EDIT_PASTE_NODES); + popup_menu->add_item(TTR("Delete"), EDIT_DELETE_NODES); + popup_menu->add_item(TTR("Duplicate"), EDIT_DUPLICATE_NODES); + popup_menu->add_item(TTR("Clear Copy Buffer"), EDIT_CLEAR_COPY_BUFFER); + popup_menu->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option)); + + base_type_map.insert("String", Variant::STRING); + base_type_map.insert("Vector2", Variant::VECTOR2); + base_type_map.insert("Vector2i", Variant::VECTOR2I); + base_type_map.insert("Rect2", Variant::RECT2); + base_type_map.insert("Rect2i", Variant::RECT2I); + base_type_map.insert("Vector3", Variant::VECTOR3); + base_type_map.insert("Vector3i", Variant::VECTOR3I); + base_type_map.insert("Transform2D", Variant::TRANSFORM2D); + base_type_map.insert("Plane", Variant::PLANE); + base_type_map.insert("Quaternion", Variant::QUATERNION); + base_type_map.insert("AABB", Variant::AABB); + base_type_map.insert("Basis", Variant::BASIS); + base_type_map.insert("Transform3D", Variant::TRANSFORM3D); + base_type_map.insert("Color", Variant::COLOR); + base_type_map.insert("NodePath", Variant::NODE_PATH); + base_type_map.insert("RID", Variant::RID); + base_type_map.insert("Callable", Variant::CALLABLE); + base_type_map.insert("Dictionary", Variant::DICTIONARY); + base_type_map.insert("Array", Variant::ARRAY); + base_type_map.insert("PackedByteArray", Variant::PACKED_BYTE_ARRAY); + base_type_map.insert("PackedInt32Array", Variant::PACKED_INT32_ARRAY); + base_type_map.insert("PackedFloat32Array", Variant::PACKED_FLOAT32_ARRAY); + base_type_map.insert("PackedInt64Array", Variant::PACKED_INT64_ARRAY); + base_type_map.insert("PackedFloat64Array", Variant::PACKED_FLOAT64_ARRAY); + base_type_map.insert("PackedStringArray", Variant::PACKED_STRING_ARRAY); + base_type_map.insert("PackedVector2Array", Variant::PACKED_VECTOR2_ARRAY); + base_type_map.insert("PackedVector3Array", Variant::PACKED_VECTOR3_ARRAY); + base_type_map.insert("PackedColorArray", Variant::PACKED_COLOR_ARRAY); } VisualScriptEditor::~VisualScriptEditor() { @@ -4564,7 +4795,7 @@ VisualScriptEditor::~VisualScriptEditor() { memdelete(variable_editor); } -static ScriptEditorBase *create_editor(const RES &p_resource) { +static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) { if (Object::cast_to<VisualScript>(*p_resource)) { return memnew(VisualScriptEditor); } @@ -4608,7 +4839,7 @@ Ref<VisualScriptNode> VisualScriptCustomNodes::create_node_custom(const String & } VisualScriptCustomNodes *VisualScriptCustomNodes::singleton = nullptr; -Map<String, REF> VisualScriptCustomNodes::custom_nodes; +Map<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes; VisualScriptCustomNodes::VisualScriptCustomNodes() { singleton = this; diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h index fd1db2bc43..e63539ac5b 100644 --- a/modules/visual_script/editor/visual_script_editor.h +++ b/modules/visual_script/editor/visual_script_editor.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -54,13 +54,18 @@ class VisualScriptEditor : public ScriptEditorBase { }; enum { - EDIT_DELETE_NODES, - EDIT_TOGGLE_BREAKPOINT, - EDIT_FIND_NODE_TYPE, - EDIT_COPY_NODES, + EDIT_ADD_NODE, + EDIT_SEPARATOR, // popup menu separator - ignored EDIT_CUT_NODES, + EDIT_COPY_NODES, EDIT_PASTE_NODES, + EDIT_DELETE_NODES, + EDIT_DUPLICATE_NODES, + EDIT_CLEAR_COPY_BUFFER, + EDIT_CREATE_FUNCTION, + EDIT_TOGGLE_BREAKPOINT, + EDIT_FIND_NODE_TYPE, REFRESH_GRAPH, }; @@ -80,55 +85,55 @@ class VisualScriptEditor : public ScriptEditorBase { MEMBER_SIGNAL }; - VBoxContainer *members_section; - MenuButton *edit_menu; + VBoxContainer *members_section = nullptr; + MenuButton *edit_menu = nullptr; Ref<VisualScript> script; - Button *base_type_select; + Button *base_type_select = nullptr; - LineEdit *func_name_box; - ScrollContainer *func_input_scroll; - VBoxContainer *func_input_vbox; - ConfirmationDialog *function_create_dialog; + LineEdit *func_name_box = nullptr; + ScrollContainer *func_input_scroll = nullptr; + VBoxContainer *func_input_vbox = nullptr; + ConfirmationDialog *function_create_dialog = nullptr; - GraphEdit *graph; - HBoxContainer *status_bar; - Button *toggle_scripts_button; + GraphEdit *graph = nullptr; + HBoxContainer *status_bar = nullptr; + Button *toggle_scripts_button = nullptr; - VisualScriptEditorSignalEdit *signal_editor; + VisualScriptEditorSignalEdit *signal_editor = nullptr; - AcceptDialog *edit_signal_dialog; - EditorInspector *edit_signal_edit; + AcceptDialog *edit_signal_dialog = nullptr; + EditorInspector *edit_signal_edit = nullptr; - VisualScriptPropertySelector *method_select; - VisualScriptPropertySelector *new_connect_node_select; - VisualScriptPropertySelector *new_virtual_method_select; + VisualScriptPropertySelector *method_select = nullptr; + VisualScriptPropertySelector *new_connect_node_select = nullptr; + VisualScriptPropertySelector *new_virtual_method_select = nullptr; - VisualScriptEditorVariableEdit *variable_editor; + VisualScriptEditorVariableEdit *variable_editor = nullptr; - AcceptDialog *edit_variable_dialog; - EditorInspector *edit_variable_edit; + AcceptDialog *edit_variable_dialog = nullptr; + EditorInspector *edit_variable_edit = nullptr; - CustomPropertyEditor *default_value_edit; + CustomPropertyEditor *default_value_edit = nullptr; - UndoRedo *undo_redo; + UndoRedo *undo_redo = nullptr; - Tree *members; - AcceptDialog *function_name_edit; - LineEdit *function_name_box; + Tree *members = nullptr; + AcceptDialog *function_name_edit = nullptr; + LineEdit *function_name_box = nullptr; - Label *hint_text; - Timer *hint_text_timer; + Label *hint_text = nullptr; + Timer *hint_text_timer = nullptr; - Label *select_func_text; + Label *select_func_text = nullptr; - bool updating_graph; + bool updating_graph = false; void _show_hint(const String &p_hint); void _hide_timer(); - CreateDialog *select_base_type; + CreateDialog *select_base_type = nullptr; struct VirtualInMenu { String name; @@ -139,11 +144,12 @@ class VisualScriptEditor : public ScriptEditorBase { Map<StringName, Color> node_colors; HashMap<StringName, Ref<StyleBox>> node_styles; + Map<StringName, Variant::Type> base_type_map; void _update_graph_connections(); void _update_graph(int p_only_id = -1); - bool updating_members; + bool updating_members = false; void _update_members(); String _sanitized_variant_text(const StringName &property_name); @@ -162,18 +168,18 @@ class VisualScriptEditor : public ScriptEditorBase { static Clipboard *clipboard; - PopupMenu *member_popup; + PopupMenu *popup_menu = nullptr; + PopupMenu *member_popup = nullptr; MemberType member_type; String member_name; PortAction port_action; - int port_action_node; - int port_action_output; + int port_action_node = 0; + int port_action_output = 0; Vector2 port_action_pos; - int port_action_new_node; + int port_action_new_node = 0; - bool saved_pos_dirty; - Vector2 saved_position; + bool saved_pos_dirty = false; Vector2 mouse_up_position; @@ -191,7 +197,7 @@ class VisualScriptEditor : public ScriptEditorBase { int _create_new_node_from_name(const String &p_text, const Vector2 &p_point); void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting); - int error_line; + int error_line = -1; void _node_selected(Node *p_node); void _center_on_node(int p_id); @@ -236,12 +242,13 @@ class VisualScriptEditor : public ScriptEditorBase { bool node_has_sequence_connections(int p_id); - void _generic_search(String p_base_type = "", Vector2 pos = Vector2(), bool node_centered = false); + void _generic_search(Vector2 pos = Vector2(), bool node_centered = false); virtual void input(const Ref<InputEvent> &p_event) override; void _graph_gui_input(const Ref<InputEvent> &p_event); void _members_gui_input(const Ref<InputEvent> &p_event); void _fn_name_box_input(const Ref<InputEvent> &p_event); + void _on_fn_name_box_confirmed(); void _rename_function(const String &p_name, const String &p_new_name); void _create_function_dialog(); @@ -262,12 +269,12 @@ class VisualScriptEditor : public ScriptEditorBase { bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); - int editing_id; - int editing_input; + int editing_id = 0; + int editing_input = 0; - bool can_swap; - int data_disconnect_node; - int data_disconnect_port; + bool can_swap = false; + int data_disconnect_node = 0; + int data_disconnect_port = 0; void _default_value_changed(); void _default_value_edited(Node *p_button, int p_id, int p_input_port); @@ -296,8 +303,8 @@ public: virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; virtual void apply_code() override; - virtual RES get_edited_resource() const override; - virtual void set_edited_resource(const RES &p_res) override; + virtual Ref<Resource> get_edited_resource() const override; + virtual void set_edited_resource(const Ref<Resource> &p_res) override; virtual void enable_editor() override; virtual Vector<String> get_functions() override; virtual void reload_text() override; @@ -323,7 +330,7 @@ public: virtual void update_settings() override; virtual bool show_members_overview() override; virtual void set_debugger_active(bool p_active) override; - virtual void set_tooltip_request_func(String p_method, Object *p_obj) override; + virtual void set_tooltip_request_func(const Callable &p_toolip_callback) 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. @@ -352,7 +359,7 @@ protected: static void _bind_methods(); static VisualScriptCustomNodes *singleton; - static Map<String, REF> custom_nodes; + static Map<String, Ref<RefCounted>> custom_nodes; static Ref<VisualScriptNode> create_node_custom(const String &p_name); public: diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp index 9fa35d4453..c8549ddb53 100644 --- a/modules/visual_script/editor/visual_script_property_selector.cpp +++ b/modules/visual_script/editor/visual_script_property_selector.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,13 +37,27 @@ #include "../visual_script_nodes.h" #include "core/os/keyboard.h" #include "editor/doc_tools.h" -#include "editor/editor_node.h" +#include "editor/editor_feature_profile.h" #include "editor/editor_scale.h" #include "scene/main/node.h" #include "scene/main/window.h" -void VisualScriptPropertySelector::_text_changed(const String &p_newtext) { - _update_search(); +void VisualScriptPropertySelector::_update_icons() { + search_box->set_right_icon(results_tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + search_box->set_clear_button_enabled(true); + search_box->add_theme_icon_override("right_icon", results_tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + + search_visual_script_nodes->set_icon(results_tree->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"))); + search_classes->set_icon(results_tree->get_theme_icon(SNAME("Object"), SNAME("EditorIcons"))); + search_methods->set_icon(results_tree->get_theme_icon(SNAME("MemberMethod"), SNAME("EditorIcons"))); + search_operators->set_icon(results_tree->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + search_signals->set_icon(results_tree->get_theme_icon(SNAME("MemberSignal"), SNAME("EditorIcons"))); + search_constants->set_icon(results_tree->get_theme_icon(SNAME("MemberConstant"), SNAME("EditorIcons"))); + search_properties->set_icon(results_tree->get_theme_icon(SNAME("MemberProperty"), SNAME("EditorIcons"))); + search_theme_items->set_icon(results_tree->get_theme_icon(SNAME("MemberTheme"), SNAME("EditorIcons"))); + + case_sensitive_button->set_icon(results_tree->get_theme_icon(SNAME("MatchCase"), SNAME("EditorIcons"))); + hierarchy_button->set_icon(results_tree->get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons"))); } void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) { @@ -55,24 +69,8 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) { case Key::DOWN: case Key::PAGEUP: case Key::PAGEDOWN: { - search_options->gui_input(k); + results_tree->gui_input(k); search_box->accept_event(); - - TreeItem *root = search_options->get_root(); - if (!root->get_first_child()) { - break; - } - - TreeItem *current = search_options->get_selected(); - - TreeItem *item = search_options->get_next_selected(root); - while (item) { - item->deselect(0); - item = search_options->get_next_selected(item); - } - - current->select(0); - } break; default: break; @@ -80,654 +78,1190 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) { } } -void VisualScriptPropertySelector::_update_search() { - set_title(TTR("Search VisualScript")); - - search_options->clear(); - help_bit->set_text(""); - - TreeItem *root = search_options->create_item(); - bool found = false; - StringName base = base_type; - List<StringName> base_list; - while (base) { - base_list.push_back(base); - base = ClassDB::get_parent_class_nocheck(base); - } - - for (const StringName &E : base_list) { - List<MethodInfo> methods; - List<PropertyInfo> props; - TreeItem *category = nullptr; - Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = { - vbc->get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("int"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("float"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("String"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("RID"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")), - vbc->get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons")) - }; - { - String b = String(E); - category = search_options->create_item(root); - if (category) { - category->set_text(0, b.replace_first("*", "")); - category->set_selectable(0, false); - Ref<Texture2D> icon; - String rep = b.replace("*", ""); - icon = EditorNode::get_singleton()->get_class_icon(rep); - category->set_icon(0, icon); - } - } - if (properties || seq_connect) { - if (instance) { - instance->get_property_list(&props, true); - } else { - Object *obj = ObjectDB::get_instance(script); - if (Object::cast_to<Script>(obj)) { - Object::cast_to<Script>(obj)->get_script_property_list(&props); - } else { - ClassDB::get_property_list(E, &props, true); - } - } - for (const PropertyInfo &F : props) { - if (!(F.usage & PROPERTY_USAGE_EDITOR) && !(F.usage & PROPERTY_USAGE_SCRIPT_VARIABLE)) { - continue; - } +void VisualScriptPropertySelector::_update_results_i(int p_int) { + _update_results(); +} - if (type_filter.size() && type_filter.find(F.type) == -1) { - continue; - } +void VisualScriptPropertySelector::_update_results_s(String p_string) { + _update_results(); +} - // capitalize() also converts underscore to space, we'll match again both possible styles - String get_text_raw = String(vformat(TTR("Get %s"), F.name)); - String get_text = get_text_raw.capitalize(); - String set_text_raw = String(vformat(TTR("Set %s"), F.name)); - String set_text = set_text_raw.capitalize(); - String input = search_box->get_text().capitalize(); - - if (input.is_empty() || get_text_raw.findn(input) != -1 || get_text.findn(input) != -1) { - TreeItem *item = search_options->create_item(category ? category : root); - item->set_text(0, get_text); - item->set_metadata(0, F.name); - item->set_icon(0, type_icons[F.type]); - item->set_metadata(1, "get"); - item->set_collapsed(true); - item->set_selectable(0, true); - item->set_selectable(1, false); - item->set_selectable(2, false); - item->set_metadata(2, connecting); - } +void VisualScriptPropertySelector::_update_results_search_all() { + if (search_classes->is_pressed()) { + scope_combo->select(COMBO_ALL); + } + _update_results(); +} - if (input.is_empty() || set_text_raw.findn(input) != -1 || set_text.findn(input) != -1) { - TreeItem *item = search_options->create_item(category ? category : root); - item->set_text(0, set_text); - item->set_metadata(0, F.name); - item->set_icon(0, type_icons[F.type]); - item->set_metadata(1, "set"); - item->set_selectable(0, true); - item->set_selectable(1, false); - item->set_selectable(2, false); - item->set_metadata(2, connecting); - } - } - } - { - if (type != Variant::NIL) { - Variant v; - Callable::CallError ce; - Variant::construct(type, v, nullptr, 0, ce); - v.get_method_list(&methods); - } else { - Object *obj = ObjectDB::get_instance(script); - if (Object::cast_to<Script>(obj)) { - Object::cast_to<Script>(obj)->get_script_method_list(&methods); - } +void VisualScriptPropertySelector::_update_results() { + _update_icons(); + search_runner = Ref<SearchRunner>(memnew(SearchRunner(this, results_tree))); + set_process(true); +} - ClassDB::get_method_list(E, &methods, true, true); - } - } - for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) { - String name = M->get().name.get_slice(":", 0); - if (name.begins_with("_") && !(M->get().flags & METHOD_FLAG_VIRTUAL)) { - continue; - } +void VisualScriptPropertySelector::_confirmed() { + TreeItem *ti = results_tree->get_selected(); + if (!ti) { + return; + } + emit_signal(SNAME("selected"), ti->get_metadata(0), ti->get_metadata(1), connecting); + set_visible(false); +} - if (virtuals_only && !(M->get().flags & METHOD_FLAG_VIRTUAL)) { - continue; - } +void VisualScriptPropertySelector::_item_selected() { + help_bit->set_text(results_tree->get_selected()->get_meta("description", "No description available")); +} - if (!virtuals_only && (M->get().flags & METHOD_FLAG_VIRTUAL)) { - continue; - } +void VisualScriptPropertySelector::_hide_requested() { + _cancel_pressed(); // From AcceptDialog. +} - MethodInfo mi = M->get(); - String desc_arguments; - if (mi.arguments.size() > 0) { - desc_arguments = "("; - for (int i = 0; i < mi.arguments.size(); i++) { - if (i > 0) { - desc_arguments += ", "; - } - if (mi.arguments[i].type == Variant::NIL) { - desc_arguments += "var"; - } else if (mi.arguments[i].name.find(":") != -1) { - desc_arguments += mi.arguments[i].name.get_slice(":", 1); - mi.arguments[i].name = mi.arguments[i].name.get_slice(":", 0); - } else { - desc_arguments += Variant::get_type_name(mi.arguments[i].type); - } +void VisualScriptPropertySelector::_notification(int p_what) { + switch (p_what) { + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + _update_icons(); + } break; + + case NOTIFICATION_ENTER_TREE: { + connect("confirmed", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); + } break; + + case NOTIFICATION_PROCESS: { + // Update background search. + if (search_runner.is_valid()) { + if (search_runner->work()) { + // Search done. + get_ok_button()->set_disabled(!results_tree->get_selected()); + + search_runner = Ref<SearchRunner>(); + set_process(false); } - desc_arguments += ")"; + } else { + // if one is valid + set_process(false); } - String desc_raw = mi.name + desc_arguments; - String desc = desc_raw.capitalize().replace("( ", "("); + } break; + } +} - if (!search_box->get_text().is_empty() && - name.findn(search_box->get_text()) == -1 && - desc.findn(search_box->get_text()) == -1 && - desc_raw.findn(search_box->get_text()) == -1) { - continue; - } +void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const bool p_virtuals_only, const bool p_connecting, bool clear_text) { + set_title(TTR("Select method from base type")); + base_type = p_base; + base_script = ""; + type = Variant::NIL; + connecting = p_connecting; + + if (clear_text) { + if (p_virtuals_only) { + search_box->set_text("._"); // show all _methods + search_box->set_caret_column(2); + } else { + search_box->set_text("."); // show all methods + search_box->set_caret_column(1); + } + } - TreeItem *item = search_options->create_item(category ? category : root); - item->set_text(0, desc); - item->set_icon(0, vbc->get_theme_icon(SNAME("MemberMethod"), SNAME("EditorIcons"))); - item->set_metadata(0, name); - item->set_selectable(0, true); + search_visual_script_nodes->set_pressed(false); + search_classes->set_pressed(false); + search_methods->set_pressed(true); + search_operators->set_pressed(false); + search_signals->set_pressed(false); + search_constants->set_pressed(false); + search_properties->set_pressed(false); + search_theme_items->set_pressed(false); - item->set_metadata(1, "method"); - item->set_collapsed(true); - item->set_selectable(1, false); + scope_combo->select(COMBO_BASE); - item->set_selectable(2, false); - item->set_metadata(2, connecting); - } + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + + _update_results(); +} + +void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_base_script, bool p_virtuals_only, const bool p_connecting, bool clear_text) { + set_title(TTR("Select from base type")); + base_type = p_base; + base_script = p_base_script.lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + type = Variant::NIL; + connecting = p_connecting; - if (category && category->get_first_child() == nullptr) { - memdelete(category); //old category was unused + if (clear_text) { + if (p_virtuals_only) { + search_box->set_text("_"); + } else { + search_box->set_text(" "); } } - if (properties) { - if (!seq_connect && !visual_script_generic) { - get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box); - get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box); - get_visual_node_names("functions/by_type/" + Variant::get_type_name(type), Set<String>(), found, root, search_box); - get_visual_node_names("functions/deconstruct/" + Variant::get_type_name(type), Set<String>(), found, root, search_box); - get_visual_node_names("operators/compare/", Set<String>(), found, root, search_box); - if (type == Variant::INT) { - get_visual_node_names("operators/bitwise/", Set<String>(), found, root, search_box); - } - if (type == Variant::BOOL) { - get_visual_node_names("operators/logic/", Set<String>(), found, root, search_box); - } - if (type == Variant::BOOL || type == Variant::INT || type == Variant::FLOAT || type == Variant::VECTOR2 || type == Variant::VECTOR3) { - get_visual_node_names("operators/math/", Set<String>(), found, root, search_box); - } - } + search_box->select_all(); + + search_visual_script_nodes->set_pressed(false); + search_classes->set_pressed(false); + search_methods->set_pressed(true); + search_operators->set_pressed(false); + search_signals->set_pressed(true); + search_constants->set_pressed(false); + search_properties->set_pressed(true); + search_theme_items->set_pressed(false); + + scope_combo->select(COMBO_RELATED); + + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + _update_results(); +} + +void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const bool p_connecting, bool clear_text) { + set_title(TTR("Select from script")); + ERR_FAIL_COND(p_script.is_null()); + + base_type = p_script->get_instance_base_type(); + base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + type = Variant::NIL; + script = p_script->get_instance_id(); + connecting = p_connecting; + + if (clear_text) { + search_box->set_text(""); } + search_box->select_all(); + + search_visual_script_nodes->set_pressed(false); + search_classes->set_pressed(true); + search_methods->set_pressed(true); + search_operators->set_pressed(true); + search_signals->set_pressed(true); + search_constants->set_pressed(true); + search_properties->set_pressed(true); + search_theme_items->set_pressed(false); + + scope_combo->select(COMBO_BASE); + + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + _update_results(); +} - if (seq_connect && !visual_script_generic) { - String text = search_box->get_text(); - create_visualscript_item(String("VisualScriptCondition"), root, text, String("Condition")); - create_visualscript_item(String("VisualScriptSwitch"), root, text, String("Switch")); - create_visualscript_item(String("VisualScriptSequence"), root, text, String("Sequence")); - create_visualscript_item(String("VisualScriptIterator"), root, text, String("Iterator")); - create_visualscript_item(String("VisualScriptWhile"), root, text, String("While")); - create_visualscript_item(String("VisualScriptReturn"), root, text, String("Return")); - get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box); - get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box); +void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const bool p_connecting, bool clear_text) { + set_title(TTR("Select from basic type")); + ERR_FAIL_COND(p_type == Variant::NIL); + base_type = Variant::get_type_name(p_type); + base_script = ""; + type = p_type; + connecting = p_connecting; + + if (clear_text) { + search_box->set_text(" "); } + search_box->select_all(); + + search_visual_script_nodes->set_pressed(false); + search_classes->set_pressed(false); + search_methods->set_pressed(true); + search_operators->set_pressed(true); + search_signals->set_pressed(false); + search_constants->set_pressed(true); + search_properties->set_pressed(true); + search_theme_items->set_pressed(false); + + scope_combo->select(COMBO_BASE); + + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + + _update_results(); +} - if ((properties || seq_connect) && visual_script_generic) { - get_visual_node_names("", Set<String>(), found, root, search_box); +void VisualScriptPropertySelector::select_from_action(const String &p_type, const bool p_connecting, bool clear_text) { + set_title(TTR("Select from action")); + base_type = p_type; + base_script = ""; + type = Variant::NIL; + connecting = p_connecting; + + if (clear_text) { + search_box->set_text(""); } + search_box->select_all(); + + search_visual_script_nodes->set_pressed(true); + search_classes->set_pressed(false); + search_methods->set_pressed(false); + search_operators->set_pressed(false); + search_signals->set_pressed(false); + search_constants->set_pressed(false); + search_properties->set_pressed(false); + search_theme_items->set_pressed(false); + + scope_combo->select(COMBO_RELATED); + + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + _update_results(); +} - TreeItem *selected_item = search_options->search_item_text(search_box->get_text()); - if (!found && selected_item != nullptr) { - selected_item->select(0); - found = true; +void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const bool p_connecting, bool clear_text) { + set_title(TTR("Select from instance")); + base_type = p_instance->get_class(); + + const Ref<Script> &p_script = p_instance->get_script(); + if (p_script == nullptr) { + base_script = ""; + } else { + base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + } + + type = Variant::NIL; + connecting = p_connecting; + + if (clear_text) { + search_box->set_text(" "); } + search_box->select_all(); + + search_visual_script_nodes->set_pressed(false); + search_classes->set_pressed(false); + search_methods->set_pressed(true); + search_operators->set_pressed(false); + search_signals->set_pressed(true); + search_constants->set_pressed(true); + search_properties->set_pressed(true); + search_theme_items->set_pressed(false); - get_ok_button()->set_disabled(root->get_first_child() == nullptr); + scope_combo->select(COMBO_BASE); + + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + _update_results(); } -void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) { - if (search_input.is_empty() || text.findn(search_input) != -1) { - TreeItem *item = search_options->create_item(root); - item->set_text(0, text); - item->set_icon(0, vbc->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"))); - item->set_metadata(0, name); - item->set_metadata(1, "action"); - item->set_selectable(0, true); - item->set_collapsed(true); - item->set_selectable(1, false); - item->set_selectable(2, false); - item->set_metadata(2, connecting); +void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> &p_script, bool clear_text) { + set_title(TTR("Select from visual script")); + base_type = p_script->get_instance_base_type(); + if (p_script == nullptr) { + base_script = ""; + } else { + base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + } + type = Variant::NIL; + connecting = false; + + if (clear_text) { + search_box->set_text(" "); } + search_box->select_all(); + + search_visual_script_nodes->set_pressed(true); + search_classes->set_pressed(false); + search_methods->set_pressed(true); + search_operators->set_pressed(false); + search_signals->set_pressed(true); + search_constants->set_pressed(true); + search_properties->set_pressed(true); + search_theme_items->set_pressed(false); + + scope_combo->select(COMBO_BASE); + + results_tree->clear(); + show_window(.5f); + search_box->grab_focus(); + _update_results(); } -void VisualScriptPropertySelector::get_visual_node_names(const String &root_filter, const Set<String> &p_modifiers, bool &found, TreeItem *const root, LineEdit *const search_box) { - Map<String, TreeItem *> path_cache; +void VisualScriptPropertySelector::show_window(float p_screen_ratio) { + popup_centered_ratio(p_screen_ratio); +} - List<String> fnodes; - VisualScriptLanguage::singleton->get_registered_node_names(&fnodes); +void VisualScriptPropertySelector::_bind_methods() { + ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "category"), PropertyInfo(Variant::BOOL, "connecting"))); +} - for (const String &E : fnodes) { - if (!E.begins_with(root_filter)) { - continue; - } - Vector<String> path = E.split("/"); - - // check if the name has the filter - bool in_filter = false; - Vector<String> tx_filters = search_box->get_text().split(" "); - for (int i = 0; i < tx_filters.size(); i++) { - if (tx_filters[i].is_empty()) { - in_filter = true; - } else { - in_filter = false; - } - if (E.findn(tx_filters[i]) != -1) { - in_filter = true; - break; - } - } - if (!in_filter) { - continue; - } +VisualScriptPropertySelector::VisualScriptPropertySelector() { + vbox = memnew(VBoxContainer); + add_child(vbox); + + HBoxContainer *hbox = memnew(HBoxContainer); + hbox->set_alignment(hbox->ALIGNMENT_CENTER); + vbox->add_child(hbox); + + case_sensitive_button = memnew(Button); + case_sensitive_button->set_flat(true); + case_sensitive_button->set_tooltip(TTR("Case Sensitive")); + case_sensitive_button->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + case_sensitive_button->set_toggle_mode(true); + case_sensitive_button->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(case_sensitive_button); + + hierarchy_button = memnew(Button); + hierarchy_button->set_flat(true); + hierarchy_button->set_tooltip(TTR("Show Hierarchy")); + hierarchy_button->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + hierarchy_button->set_toggle_mode(true); + hierarchy_button->set_pressed(true); + hierarchy_button->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(hierarchy_button); + + hbox->add_child(memnew(VSeparator)); + + search_visual_script_nodes = memnew(Button); + search_visual_script_nodes->set_flat(true); + search_visual_script_nodes->set_tooltip(TTR("Search Visual Script Nodes")); + search_visual_script_nodes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_visual_script_nodes->set_toggle_mode(true); + search_visual_script_nodes->set_pressed(true); + search_visual_script_nodes->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_visual_script_nodes); + + search_classes = memnew(Button); + search_classes->set_flat(true); + search_classes->set_tooltip(TTR("Search Classes")); + search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results_search_all)); + search_classes->set_toggle_mode(true); + search_classes->set_pressed(true); + search_classes->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_classes); + + search_operators = memnew(Button); + search_operators->set_flat(true); + search_operators->set_tooltip(TTR("Search Operators")); + search_operators->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_operators->set_toggle_mode(true); + search_operators->set_pressed(true); + search_operators->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_operators); + + hbox->add_child(memnew(VSeparator)); + + search_methods = memnew(Button); + search_methods->set_flat(true); + search_methods->set_tooltip(TTR("Search Methods")); + search_methods->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_methods->set_toggle_mode(true); + search_methods->set_pressed(true); + search_methods->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_methods); + + search_signals = memnew(Button); + search_signals->set_flat(true); + search_signals->set_tooltip(TTR("Search Signals")); + search_signals->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_signals->set_toggle_mode(true); + search_signals->set_pressed(true); + search_signals->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_signals); + + search_constants = memnew(Button); + search_constants->set_flat(true); + search_constants->set_tooltip(TTR("Search Constants")); + search_constants->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_constants->set_toggle_mode(true); + search_constants->set_pressed(true); + search_constants->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_constants); + + search_properties = memnew(Button); + search_properties->set_flat(true); + search_properties->set_tooltip(TTR("Search Properties")); + search_properties->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_properties->set_toggle_mode(true); + search_properties->set_pressed(true); + search_properties->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_properties); + + search_theme_items = memnew(Button); + search_theme_items->set_flat(true); + search_theme_items->set_tooltip(TTR("Search Theme Items")); + search_theme_items->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); + search_theme_items->set_toggle_mode(true); + search_theme_items->set_pressed(true); + search_theme_items->set_focus_mode(Control::FOCUS_NONE); + hbox->add_child(search_theme_items); + + scope_combo = memnew(OptionButton); + scope_combo->set_custom_minimum_size(Size2(200, 0) * EDSCALE); + scope_combo->set_tooltip(TTR("Select the search limits")); + scope_combo->set_stretch_ratio(0); // Fixed width. + scope_combo->add_item(TTR("Search Related"), SCOPE_RELATED); + scope_combo->add_separator(); + scope_combo->add_item(TTR("Search Base"), SCOPE_BASE); + scope_combo->add_item(TTR("Search Inheriters"), SCOPE_INHERITERS); + scope_combo->add_item(TTR("Search Unrelated"), SCOPE_UNRELATED); + scope_combo->add_item(TTR("Search All"), SCOPE_ALL); + scope_combo->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_update_results_i)); + hbox->add_child(scope_combo); - bool in_modifier = p_modifiers.is_empty(); - for (Set<String>::Element *F = p_modifiers.front(); F && in_modifier; F = F->next()) { - if (E.findn(F->get()) != -1) { - in_modifier = true; - } - } - if (!in_modifier) { - continue; - } + search_box = memnew(LineEdit); + search_box->set_tooltip(TTR("Enter \" \" to show all filtered options\nEnter \".\" to show all filtered methods, operators and constructors\nUse CTRL_KEY to drop property setters")); + search_box->set_custom_minimum_size(Size2(200, 0) * EDSCALE); + search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); + search_box->connect("text_changed", callable_mp(this, &VisualScriptPropertySelector::_update_results_s)); + search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input)); + register_text_enter(search_box); + vbox->add_child(search_box); + + results_tree = memnew(Tree); + results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); + results_tree->set_hide_root(true); + results_tree->set_hide_folding(false); + results_tree->set_columns(2); + results_tree->set_column_title(0, TTR("Name")); + results_tree->set_column_clip_content(0, true); + results_tree->set_column_title(1, TTR("Member Type")); + results_tree->set_column_expand(1, false); + results_tree->set_column_custom_minimum_width(1, 150 * EDSCALE); + results_tree->set_column_clip_content(1, true); + results_tree->set_custom_minimum_size(Size2(0, 100) * EDSCALE); + results_tree->set_select_mode(Tree::SELECT_ROW); + results_tree->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); + results_tree->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_item_selected)); + vbox->add_child(results_tree); - TreeItem *item = search_options->create_item(root); - Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(E); - Ref<VisualScriptOperator> vnode_operator = vnode; - String type_name; - if (vnode_operator.is_valid()) { - String type; - if (path.size() >= 2) { - type = path[1]; - } - type_name = type.capitalize() + " "; + help_bit = memnew(EditorHelpBit); + vbox->add_child(help_bit); + help_bit->connect("request_hide", callable_mp(this, &VisualScriptPropertySelector::_hide_requested)); + get_ok_button()->set_text(TTR("Open")); + get_ok_button()->set_disabled(true); + set_hide_on_ok(false); +} + +bool VisualScriptPropertySelector::SearchRunner::_is_class_disabled_by_feature_profile(const StringName &p_class) { + Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile(); + if (profile.is_null()) { + return false; + } + + StringName class_name = p_class; + while (class_name != StringName()) { + if (!ClassDB::class_exists(class_name)) { + return false; } - Ref<VisualScriptFunctionCall> vnode_function_call = vnode; - if (vnode_function_call.is_valid()) { - String basic_type = Variant::get_type_name(vnode_function_call->get_basic_type()); - type_name = basic_type.capitalize() + " "; + + if (profile->is_class_disabled(class_name)) { + return true; } - Ref<VisualScriptConstructor> vnode_constructor = vnode; - if (vnode_constructor.is_valid()) { - type_name = "Construct "; + class_name = ClassDB::get_parent_class(class_name); + } + + return false; +} + +bool VisualScriptPropertySelector::SearchRunner::_is_class_disabled_by_scope(const StringName &p_class) { + bool is_base_script = false; + if (p_class == selector_ui->base_script) { + is_base_script = true; + } + bool is_base = false; + if (selector_ui->base_type == p_class) { + is_base = true; + } + bool is_parent = false; + if ((ClassDB::is_parent_class(selector_ui->base_type, p_class)) && !is_base) { + is_parent = true; + } + + bool is_inheriter = false; + List<StringName> inheriters; + ClassDB::get_inheriters_from_class(selector_ui->base_type, &inheriters); + if (inheriters.find(p_class)) { + is_inheriter = true; + } + + if (scope_flags & SCOPE_BASE) { + if (is_base_script || is_base || is_parent) { + return false; } - Ref<VisualScriptDeconstruct> vnode_deconstruct = vnode; - if (vnode_deconstruct.is_valid()) { - type_name = "Deconstruct "; + } + if (scope_flags & SCOPE_INHERITERS) { + if (is_base_script || is_base || is_inheriter) { + return false; } - Vector<String> desc = path[path.size() - 1].replace("(", " ").replace(")", " ").replace(",", " ").split(" "); - for (int i = 0; i < desc.size(); i++) { - desc.write[i] = desc[i].capitalize(); - if (desc[i].ends_with(",")) { - desc.write[i] = desc[i].replace(",", ", "); - } + } + // if (scope_flags & SCOPE_RELATED) { + // /* code */ + // } + if (scope_flags & SCOPE_UNRELATED) { + if (!is_base_script && !is_base && !is_inheriter) { + return false; } - - item->set_text(0, type_name + String("").join(desc)); - item->set_icon(0, vbc->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"))); - item->set_selectable(0, true); - item->set_metadata(0, E); - item->set_selectable(0, true); - item->set_metadata(1, "visualscript"); - item->set_selectable(1, false); - item->set_selectable(2, false); - item->set_metadata(2, connecting); } + return true; } -void VisualScriptPropertySelector::_confirmed() { - TreeItem *ti = search_options->get_selected(); - if (!ti) { - return; +bool VisualScriptPropertySelector::SearchRunner::_slice() { + bool phase_done = false; + switch (phase) { + case PHASE_INIT: + phase_done = _phase_init(); + break; + case PHASE_MATCH_CLASSES_INIT: + phase_done = _phase_match_classes_init(); + break; + case PHASE_NODE_CLASSES_INIT: + phase_done = _phase_node_classes_init(); + break; + case PHASE_NODE_CLASSES_BUILD: + phase_done = _phase_node_classes_build(); + break; + case PHASE_MATCH_CLASSES: + phase_done = _phase_match_classes(); + break; + case PHASE_CLASS_ITEMS_INIT: + phase_done = _phase_class_items_init(); + break; + case PHASE_CLASS_ITEMS: + phase_done = _phase_class_items(); + break; + case PHASE_MEMBER_ITEMS_INIT: + phase_done = _phase_member_items_init(); + break; + case PHASE_MEMBER_ITEMS: + phase_done = _phase_member_items(); + break; + case PHASE_SELECT_MATCH: + phase_done = _phase_select_match(); + break; + case PHASE_MAX: + return true; + default: + WARN_PRINT("Invalid or unhandled phase in EditorHelpSearch::Runner, aborting search."); + return true; + }; + + if (phase_done) { + phase++; } - emit_signal(SNAME("selected"), ti->get_metadata(0), ti->get_metadata(1), ti->get_metadata(2)); - set_visible(false); + return false; } -void VisualScriptPropertySelector::_item_selected() { - help_bit->set_text(""); - - TreeItem *item = search_options->get_selected(); - if (!item) { - return; +bool VisualScriptPropertySelector::SearchRunner::_phase_init() { + search_flags = 0; // selector_ui->filter_combo->get_selected_id(); + if (selector_ui->search_visual_script_nodes->is_pressed()) { + search_flags |= SEARCH_VISUAL_SCRIPT_NODES; } - String name = item->get_metadata(0); - - String class_type; - if (type != Variant::NIL) { - class_type = Variant::get_type_name(type); - - } else { - class_type = base_type; + if (selector_ui->search_classes->is_pressed()) { + search_flags |= SEARCH_CLASSES; } + // if (selector_ui->search_constructors->is_pressed()) { + search_flags |= SEARCH_CONSTRUCTORS; + // } + if (selector_ui->search_methods->is_pressed()) { + search_flags |= SEARCH_METHODS; + } + if (selector_ui->search_operators->is_pressed()) { + search_flags |= SEARCH_OPERATORS; + } + if (selector_ui->search_signals->is_pressed()) { + search_flags |= SEARCH_SIGNALS; + } + if (selector_ui->search_constants->is_pressed()) { + search_flags |= SEARCH_CONSTANTS; + } + if (selector_ui->search_properties->is_pressed()) { + search_flags |= SEARCH_PROPERTIES; + } + if (selector_ui->search_theme_items->is_pressed()) { + search_flags |= SEARCH_THEME_ITEMS; + } + if (selector_ui->case_sensitive_button->is_pressed()) { + search_flags |= SEARCH_CASE_SENSITIVE; + } + if (selector_ui->hierarchy_button->is_pressed()) { + search_flags |= SEARCH_SHOW_HIERARCHY; + } + scope_flags = selector_ui->scope_combo->get_selected_id(); - DocTools *dd = EditorHelp::get_doc_data(); - String text; - - String at_class = class_type; + return true; +} - while (!at_class.is_empty()) { - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class); - if (E) { - for (int i = 0; i < E->get().properties.size(); i++) { - if (E->get().properties[i].name == name) { - text = DTR(E->get().properties[i].description); +bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes_init() { + combined_docs = EditorHelp::get_doc_data()->class_list; + matches.clear(); + matched_item = nullptr; + match_highest_score = 0; + + if ( + (selector_ui->base_script.unquote() != "") && + (selector_ui->base_script.unquote() != ".") && + !combined_docs.has(selector_ui->base_script)) { + String file_path = "res://" + selector_ui->base_script.unquote(); // EditorHelp::get_doc_data().name to filepath + Ref<Script> script; + script = ResourceLoader::load(file_path); + if (!script.is_null()) { + DocData::ClassDoc class_doc = DocData::ClassDoc(); + + class_doc.name = selector_ui->base_script; + + class_doc.inherits = script->get_instance_base_type(); + class_doc.brief_description = ".vs files not supported by EditorHelp::get_doc_data()"; + class_doc.description = ""; + + Object *obj = ObjectDB::get_instance(script->get_instance_id()); + if (Object::cast_to<Script>(obj)) { + List<MethodInfo> methods; + Object::cast_to<Script>(obj)->get_script_method_list(&methods); + for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) { + class_doc.methods.push_back(_get_method_doc(M->get())); } - } - } - at_class = ClassDB::get_parent_class_nocheck(at_class); - } - at_class = class_type; + List<MethodInfo> signals; + Object::cast_to<Script>(obj)->get_script_signal_list(&signals); + for (List<MethodInfo>::Element *S = signals.front(); S; S = S->next()) { + class_doc.signals.push_back(_get_method_doc(S->get())); + } - while (!at_class.is_empty()) { - Map<String, DocData::ClassDoc>::Element *C = dd->class_list.find(at_class); - if (C) { - for (int i = 0; i < C->get().methods.size(); i++) { - if (C->get().methods[i].name == name) { - text = DTR(C->get().methods[i].description); + List<PropertyInfo> properties; + Object::cast_to<Script>(obj)->get_script_property_list(&properties); + for (List<PropertyInfo>::Element *P = properties.front(); P; P = P->next()) { + DocData::PropertyDoc pd = DocData::PropertyDoc(); + pd.name = P->get().name; + pd.type = Variant::get_type_name(P->get().type); + class_doc.properties.push_back(pd); } } + combined_docs.insert(class_doc.name, class_doc); } + } + iterator_doc = combined_docs.front(); + return true; +} + +bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_init() { + VisualScriptLanguage::singleton->get_registered_node_names(&vs_nodes); + _add_class_doc("functions", "", ""); + _add_class_doc("operators", "", ""); + return true; +} - at_class = ClassDB::get_parent_class_nocheck(at_class); +bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_build() { + if (vs_nodes.is_empty()) { + return true; } - 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++) { - if (T->get().methods[i].name == functions[functions.size() - 1]) { - text = DTR(T->get().methods[i].description); - } + String registered_node_name = vs_nodes[0]; + vs_nodes.pop_front(); + + Vector<String> path = registered_node_name.split("/"); + if (path[0] == "constants") { + _add_class_doc(registered_node_name, "", "constants"); + } else if (path[0] == "custom") { + _add_class_doc(registered_node_name, "", "custom"); + } else if (path[0] == "data") { + _add_class_doc(registered_node_name, "", "data"); + } else if (path[0] == "flow_control") { + _add_class_doc(registered_node_name, "", "flow_control"); + } else if (path[0] == "functions") { + if (path[1] == "built_in") { + _add_class_doc(registered_node_name, "functions", "built_in"); + } else if (path[1] == "by_type") { + // No action is required. + // Using function references from ClassDB to remove confusion for users. + } else if (path[1] == "constructors") { + _add_class_doc(registered_node_name, "", "constructors"); + } else if (path[1] == "deconstruct") { + _add_class_doc(registered_node_name, "", "deconstruct"); + } else if (path[1] == "wait") { + _add_class_doc(registered_node_name, "functions", "yield"); + } else { + _add_class_doc(registered_node_name, "functions", ""); + } + } else if (path[0] == "index") { + _add_class_doc(registered_node_name, "", "index"); + } else if (path[0] == "operators") { + if (path[1] == "bitwise") { + _add_class_doc(registered_node_name, "operators", "bitwise"); + } else if (path[1] == "compare") { + _add_class_doc(registered_node_name, "operators", "compare"); + } else if (path[1] == "logic") { + _add_class_doc(registered_node_name, "operators", "logic"); + } else if (path[1] == "math") { + _add_class_doc(registered_node_name, "operators", "math"); + } else { + _add_class_doc(registered_node_name, "operators", ""); } } + return false; +} - List<String> *names = memnew(List<String>); - VisualScriptLanguage::singleton->get_registered_node_names(names); - if (names->find(name) != nullptr) { - Ref<VisualScriptOperator> operator_node = VisualScriptLanguage::singleton->create_node_from_name(name); - if (operator_node.is_valid()) { - Map<String, DocData::ClassDoc>::Element *F = dd->class_list.find(operator_node->get_class_name()); - if (F) { - text = Variant::get_operator_name(operator_node->get_operator()); +bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() { + DocData::ClassDoc &class_doc = iterator_doc->value(); + if ( + (!_is_class_disabled_by_feature_profile(class_doc.name) && !_is_class_disabled_by_scope(class_doc.name)) || + _match_visual_script(class_doc)) { + if (class_doc.inherits == "VisualScriptCustomNode") { + class_doc.script_path = "res://" + class_doc.name.unquote(); + Ref<Script> script = ResourceLoader::load(class_doc.script_path); + Ref<VisualScriptCustomNode> vsn; + vsn.instantiate(); + vsn->set_script(script); + class_doc.name = vsn->get_caption(); + if (combined_docs.has(vsn->get_category())) { + class_doc.inherits = vsn->get_category(); + } else if (combined_docs.has("VisualScriptNode/" + vsn->get_category())) { + class_doc.inherits = "VisualScriptNode/" + vsn->get_category(); + } else if (combined_docs.has("VisualScriptCustomNode/" + vsn->get_category())) { + class_doc.inherits = "VisualScriptCustomNode/" + vsn->get_category(); + } else { + class_doc.inherits = ""; } + class_doc.category = "VisualScriptCustomNode/" + vsn->get_category(); + class_doc.brief_description = ""; + class_doc.constructors.clear(); + class_doc.methods.clear(); + class_doc.operators.clear(); + class_doc.signals.clear(); + class_doc.constants.clear(); + class_doc.enums.clear(); + class_doc.properties.clear(); + class_doc.theme_properties.clear(); } - Ref<VisualScriptTypeCast> typecast_node = VisualScriptLanguage::singleton->create_node_from_name(name); - if (typecast_node.is_valid()) { - Map<String, DocData::ClassDoc>::Element *F = dd->class_list.find(typecast_node->get_class_name()); - if (F) { - text = DTR(F->get().description); + + matches[class_doc.name] = ClassMatch(); + ClassMatch &match = matches[class_doc.name]; + + match.category = class_doc.category; + match.doc = &class_doc; + // Match class name. + if (search_flags & SEARCH_CLASSES || _match_visual_script(class_doc)) { + if (term == "") { + match.name = !_match_is_hidden(class_doc); + } else { + match.name = _match_string(term, class_doc.name); } + // match.name = term == "" || _match_string(term, class_doc.name); } - Ref<VisualScriptBuiltinFunc> builtin_node = VisualScriptLanguage::singleton->create_node_from_name(name); - if (builtin_node.is_valid()) { - Map<String, DocData::ClassDoc>::Element *F = dd->class_list.find(builtin_node->get_class_name()); - if (F) { - for (int i = 0; i < F->get().constants.size(); i++) { - if (F->get().constants[i].value.to_int() == int(builtin_node->get_func())) { - text = DTR(F->get().constants[i].description); + // Match members if the term is long enough. + if (term.length() >= 0) { + if (search_flags & SEARCH_CONSTRUCTORS) { + for (int i = 0; i < class_doc.constructors.size(); i++) { + String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower(); + if (method_name.find(term) > -1 || + term == " " || + (term.begins_with(".") && method_name.begins_with(term.substr(1))) || + (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || + (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { + match.constructors.push_back(const_cast<DocData::MethodDoc *>(&class_doc.constructors[i])); + } + } + } + if (search_flags & SEARCH_METHODS) { + for (int i = 0; i < class_doc.methods.size(); i++) { + String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower(); + if (method_name.find(term) > -1 || + term == " " || + (term.begins_with(".") && method_name.begins_with(term.substr(1))) || + (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || + (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { + match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i])); + } + } + } + if (search_flags & SEARCH_OPERATORS) { + for (int i = 0; i < class_doc.operators.size(); i++) { + String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.operators[i].name : class_doc.operators[i].name.to_lower(); + if (method_name.find(term) > -1 || + term == " " || + (term.begins_with(".") && method_name.begins_with(term.substr(1))) || + (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || + (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { + match.operators.push_back(const_cast<DocData::MethodDoc *>(&class_doc.operators[i])); + } + } + } + if (search_flags & SEARCH_SIGNALS) { + for (int i = 0; i < class_doc.signals.size(); i++) { + if (_match_string(term, class_doc.signals[i].name) || + term == " ") { + match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i])); + } + } + } + if (search_flags & SEARCH_CONSTANTS) { + for (int i = 0; i < class_doc.constants.size(); i++) { + if (_match_string(term, class_doc.constants[i].name) || + term == " ") { + match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i])); + } + } + } + if (search_flags & SEARCH_PROPERTIES) { + for (int i = 0; i < class_doc.properties.size(); i++) { + if (_match_string(term, class_doc.properties[i].name) || + term == " " || + _match_string(term, class_doc.properties[i].getter) || + _match_string(term, class_doc.properties[i].setter)) { + match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i])); + } + } + } + if (search_flags & SEARCH_THEME_ITEMS) { + for (int i = 0; i < class_doc.theme_properties.size(); i++) { + if (_match_string(term, class_doc.theme_properties[i].name) || + term == " ") { + match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc.theme_properties[i])); } } } } } - memdelete(names); + iterator_doc = iterator_doc->next(); + return !iterator_doc; +} - if (text.is_empty()) { - return; - } +bool VisualScriptPropertySelector::SearchRunner::_phase_class_items_init() { + results_tree->clear(); + iterator_match = matches.front(); - help_bit->set_text(text); -} + root_item = results_tree->create_item(); + class_items.clear(); -void VisualScriptPropertySelector::_hide_requested() { - _cancel_pressed(); // From AcceptDialog. + return true; } -void VisualScriptPropertySelector::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - connect("confirmed", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); +bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() { + if (!iterator_match) { + return true; } -} -void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const String &p_current, const bool p_virtuals_only, const bool p_connecting, bool clear_text) { - base_type = p_base; - selected = p_current; - type = Variant::NIL; - properties = false; - instance = nullptr; - virtuals_only = p_virtuals_only; + ClassMatch &match = iterator_match->value(); - show_window(.5f); - if (clear_text) { - search_box->set_text(""); + if (search_flags & SEARCH_SHOW_HIERARCHY) { + if (match.required()) { + _create_class_hierarchy(match); + } } else { - search_box->select_all(); + if (match.name) { + _create_class_item(root_item, match.doc, true); + } } - search_box->grab_focus(); - connecting = p_connecting; - _update_search(); + iterator_match = iterator_match->next(); + return !iterator_match; } -void VisualScriptPropertySelector::set_type_filter(const Vector<Variant::Type> &p_type_filter) { - type_filter = p_type_filter; +bool VisualScriptPropertySelector::SearchRunner::_phase_member_items_init() { + iterator_match = matches.front(); + + return true; } -void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_current, bool p_virtuals_only, bool p_seq_connect, const bool p_connecting, bool clear_text) { - base_type = p_base; - selected = p_current; - type = Variant::NIL; - properties = true; - visual_script_generic = false; - instance = nullptr; - virtuals_only = p_virtuals_only; +bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() { + if (!iterator_match) { + return true; + } - show_window(.5f); - if (clear_text) { - search_box->set_text(""); + ClassMatch &match = iterator_match->value(); + + TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item; + bool constructor_created = false; + for (int i = 0; i < match.methods.size(); i++) { + String text = match.methods[i]->name; + if (!constructor_created) { + if (match.doc->name == match.methods[i]->name) { + text += " " + TTR("(constructors)"); + constructor_created = true; + } + } else { + if (match.doc->name == match.methods[i]->name) { + continue; + } + } + _create_method_item(parent, match.doc, text, match.methods[i]); + } + for (int i = 0; i < match.signals.size(); i++) { + _create_signal_item(parent, match.doc, match.signals[i]); + } + for (int i = 0; i < match.constants.size(); i++) { + _create_constant_item(parent, match.doc, match.constants[i]); + } + for (int i = 0; i < match.properties.size(); i++) { + _create_property_item(parent, match.doc, match.properties[i]); + } + for (int i = 0; i < match.theme_properties.size(); i++) { + _create_theme_property_item(parent, match.doc, match.theme_properties[i]); + } + + iterator_match = iterator_match->next(); + return !iterator_match; +} + +bool VisualScriptPropertySelector::SearchRunner::_phase_select_match() { + if (matched_item) { + matched_item->select(0); + } + return true; +} + +bool VisualScriptPropertySelector::SearchRunner::_match_string(const String &p_term, const String &p_string) const { + if (search_flags & SEARCH_CASE_SENSITIVE) { + return p_string.find(p_term) > -1; } else { - search_box->select_all(); + return p_string.findn(p_term) > -1; } - search_box->grab_focus(); - seq_connect = p_seq_connect; - connecting = p_connecting; +} - _update_search(); +bool VisualScriptPropertySelector::SearchRunner::_match_visual_script(DocData::ClassDoc &class_doc) { + if (class_doc.category.ends_with("_class")) { + if (class_doc.category.begins_with("VisualScript") && search_flags & SEARCH_CLASSES) { + if (matches.has(class_doc.inherits)) { + return true; + } + } + return false; + } + if (class_doc.category.begins_with("VisualScript") && search_flags & SEARCH_VISUAL_SCRIPT_NODES) { + return true; + } + if (class_doc.name.begins_with("operators") && search_flags & SEARCH_OPERATORS) { + return true; + } + if (class_doc.category.begins_with("VisualScriptNode/deconstruct")) { + if (class_doc.name.find(selector_ui->base_type, 0) > -1) { + return true; + } + } + + return false; } -void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const String &p_current, const bool p_connecting, bool clear_text) { - ERR_FAIL_COND(p_script.is_null()); +bool VisualScriptPropertySelector::SearchRunner::_match_is_hidden(DocData::ClassDoc &class_doc) { + if (class_doc.category.begins_with("VisualScript")) { + if (class_doc.name.begins_with("flow_control")) { + return false; + } else if (class_doc.name.begins_with("operators")) { + return !(search_flags & SEARCH_OPERATORS); + } else if (class_doc.name.begins_with("functions/built_in/print")) { + return false; + } + return true; + } + return false; +} - base_type = p_script->get_instance_base_type(); - selected = p_current; - type = Variant::NIL; - script = p_script->get_instance_id(); - properties = true; - visual_script_generic = false; - instance = nullptr; - virtuals_only = false; +void VisualScriptPropertySelector::SearchRunner::_match_item(TreeItem *p_item, const String &p_text) { + float inverse_length = 1.f / float(p_text.length()); - show_window(.5f); - if (clear_text) { - search_box->set_text(""); - } else { - search_box->select_all(); + // Favor types where search term is a substring close to the start of the type. + float w = 0.5f; + int pos = p_text.findn(term); + float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w); + + // Favor shorter items: they resemble the search term more. + w = 0.1f; + score *= (1 - w) + w * (term.length() * inverse_length); + + if (match_highest_score == 0 || score > match_highest_score) { + matched_item = p_item; + match_highest_score = score; } - search_box->grab_focus(); - seq_connect = false; - connecting = p_connecting; +} - _update_search(); +void VisualScriptPropertySelector::SearchRunner::_add_class_doc(String class_name, String inherits, String category) { + DocData::ClassDoc class_doc = DocData::ClassDoc(); + class_doc.name = class_name; + class_doc.inherits = inherits; + class_doc.category = "VisualScriptNode/" + category; + class_doc.brief_description = category; + combined_docs.insert(class_doc.name, class_doc); } -void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const String &p_current, const bool p_connecting, bool clear_text) { - ERR_FAIL_COND(p_type == Variant::NIL); - base_type = ""; - selected = p_current; - type = p_type; - properties = true; - visual_script_generic = false; - instance = nullptr; - virtuals_only = false; +DocData::MethodDoc VisualScriptPropertySelector::SearchRunner::_get_method_doc(MethodInfo method_info) { + DocData::MethodDoc method_doc = DocData::MethodDoc(); + method_doc.name = method_info.name; + method_doc.return_type = Variant::get_type_name(method_info.return_val.type); + method_doc.description = "No description available"; + for (List<PropertyInfo>::Element *P = method_info.arguments.front(); P; P = P->next()) { + DocData::ArgumentDoc argument_doc = DocData::ArgumentDoc(); + argument_doc.name = P->get().name; + argument_doc.type = Variant::get_type_name(P->get().type); + method_doc.arguments.push_back(argument_doc); + } + return method_doc; +} - show_window(.5f); - if (clear_text) { - search_box->set_text(""); - } else { - search_box->select_all(); +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_class_hierarchy(const ClassMatch &p_match) { + if (class_items.has(p_match.doc->name)) { + return class_items[p_match.doc->name]; } - search_box->grab_focus(); - seq_connect = false; - connecting = p_connecting; - _update_search(); + // Ensure parent nodes are created first. + TreeItem *parent = root_item; + if (p_match.doc->inherits != "") { + if (class_items.has(p_match.doc->inherits)) { + parent = class_items[p_match.doc->inherits]; + } else if (matches.has(p_match.doc->inherits)) { + ClassMatch &base_match = matches[p_match.doc->inherits]; + parent = _create_class_hierarchy(base_match); + } + } + + TreeItem *class_item = _create_class_item(parent, p_match.doc, !p_match.name); + class_items[p_match.doc->name] = class_item; + return class_item; } -void VisualScriptPropertySelector::select_from_action(const String &p_type, const String &p_current, const bool p_connecting, bool clear_text) { - base_type = p_type; - selected = p_current; - type = Variant::NIL; - properties = false; - visual_script_generic = false; - instance = nullptr; - virtuals_only = false; +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) { + Ref<Texture2D> icon = empty_icon; + String text_0 = p_doc->name; + String text_1 = "Class"; + + String what = "Class"; + String details = p_doc->name; + if (p_doc->category.begins_with("VisualScriptCustomNode/")) { + Vector<String> path = p_doc->name.split("/"); + icon = ui_service->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); + text_0 = path[path.size() - 1]; + text_1 = "VisualScriptCustomNode"; + what = "VisualScriptCustomNode"; + details = "CustomNode"; + } else if (p_doc->category.begins_with("VisualScriptNode/")) { + Vector<String> path = p_doc->name.split("/"); + icon = ui_service->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); + text_0 = path[path.size() - 1]; + if (p_doc->category.begins_with("VisualScriptNode/deconstruct")) { + text_0 = "deconstruct " + text_0; + } + text_1 = "VisualScriptNode"; + what = "VisualScriptNode"; + details = p_doc->name; + + if (path.size() == 1) { + if (path[0] == "functions" || path[0] == "operators") { + text_1 = "VisualScript"; + p_gray = true; + what = "no_result"; + details = ""; + } + } - show_window(.5f); - if (clear_text) { - search_box->set_text(""); } else { - search_box->select_all(); + if (p_doc->name.is_quoted()) { + text_0 = p_doc->name.unquote().get_file(); + if (ui_service->has_theme_icon(p_doc->inherits, "EditorIcons")) { + icon = ui_service->get_theme_icon(p_doc->inherits, "EditorIcons"); + } + } else if (ui_service->has_theme_icon(p_doc->name, "EditorIcons")) { + icon = ui_service->get_theme_icon(p_doc->name, "EditorIcons"); + } else if (ClassDB::class_exists(p_doc->name) && ClassDB::is_parent_class(p_doc->name, "Object")) { + icon = ui_service->get_theme_icon(SNAME("Object"), SNAME("EditorIcons")); + } + } + String tooltip = p_doc->brief_description.strip_edges(); + + TreeItem *item = results_tree->create_item(p_parent); + item->set_icon(0, icon); + item->set_text(0, text_0); + item->set_text(1, TTR(text_1)); + item->set_tooltip(0, tooltip); + item->set_tooltip(1, tooltip); + item->set_metadata(0, details); + item->set_metadata(1, what); + if (p_gray) { + item->set_custom_color(0, disabled_color); + item->set_custom_color(1, disabled_color); } - search_box->grab_focus(); - seq_connect = true; - connecting = p_connecting; - _update_search(); + _match_item(item, p_doc->name); + + return item; } -void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const String &p_current, const bool p_connecting, const String &p_basetype, bool clear_text) { - base_type = p_basetype; - selected = p_current; - type = Variant::NIL; - properties = true; - visual_script_generic = false; - instance = p_instance; - virtuals_only = false; +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) { + String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; + for (int i = 0; i < p_doc->arguments.size(); i++) { + const DocData::ArgumentDoc &arg = p_doc->arguments[i]; + tooltip += arg.type + " " + arg.name; + if (arg.default_value != "") { + tooltip += " = " + arg.default_value; + } + if (i < p_doc->arguments.size() - 1) { + tooltip += ", "; + } + } + tooltip += ")"; + return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->description); +} - show_window(.5f); - if (clear_text) { - search_box->set_text(""); - } else { - search_box->select_all(); +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) { + String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; + for (int i = 0; i < p_doc->arguments.size(); i++) { + const DocData::ArgumentDoc &arg = p_doc->arguments[i]; + tooltip += arg.type + " " + arg.name; + if (arg.default_value != "") { + tooltip += " = " + arg.default_value; + } + if (i < p_doc->arguments.size() - 1) { + tooltip += ", "; + } } - search_box->grab_focus(); - seq_connect = false; - connecting = p_connecting; + tooltip += ")"; + return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->description); +} - _update_search(); +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) { + String tooltip = p_class_doc->name + "." + p_doc->name; + return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->description); } -void VisualScriptPropertySelector::select_from_visual_script(const String &p_base, const bool p_connecting, bool clear_text) { - base_type = p_base; - selected = ""; - type = Variant::NIL; - properties = true; - visual_script_generic = true; - instance = nullptr; - virtuals_only = false; - show_window(.5f); - if (clear_text) { - search_box->set_text(""); +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) { + String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; + tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter"; + tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter"; + return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->description); +} + +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc) { + String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; + return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip, p_doc->description); +} + +TreeItem *VisualScriptPropertySelector::SearchRunner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description) { + Ref<Texture2D> icon; + String text; + if (search_flags & SEARCH_SHOW_HIERARCHY) { + icon = ui_service->get_theme_icon(p_icon, SNAME("EditorIcons")); + text = p_text; } else { - search_box->select_all(); + icon = ui_service->get_theme_icon(p_icon, SNAME("EditorIcons")); + text = p_class_name + "." + p_text; } - search_box->grab_focus(); - connecting = p_connecting; - _update_search(); -} + TreeItem *item = results_tree->create_item(p_parent); + item->set_icon(0, icon); + item->set_text(0, text); + item->set_text(1, TTRGET(p_type)); + item->set_tooltip(0, p_tooltip); + item->set_tooltip(1, p_tooltip); + item->set_metadata(0, p_class_name + ":" + p_name); + item->set_metadata(1, "class_" + p_metatype); + item->set_meta("description", p_description); -void VisualScriptPropertySelector::show_window(float p_screen_ratio) { - popup_centered_ratio(p_screen_ratio); + _match_item(item, p_name); + + return item; } -void VisualScriptPropertySelector::_bind_methods() { - ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "category"), PropertyInfo(Variant::BOOL, "connecting"))); +bool VisualScriptPropertySelector::SearchRunner::work(uint64_t slot) { + // Return true when the search has been completed, otherwise false. + const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; + while (!_slice()) { + if (OS::get_singleton()->get_ticks_usec() > until) { + return false; + } + } + return true; } -VisualScriptPropertySelector::VisualScriptPropertySelector() { - vbc = memnew(VBoxContainer); - add_child(vbc); - //set_child_rect(vbc); - search_box = memnew(LineEdit); - vbc->add_margin_child(TTR("Search:"), search_box); - search_box->connect("text_changed", callable_mp(this, &VisualScriptPropertySelector::_text_changed)); - search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input)); - search_options = memnew(Tree); - vbc->add_margin_child(TTR("Matches:"), search_options, true); - get_ok_button()->set_text(TTR("Open")); - get_ok_button()->set_disabled(true); - register_text_enter(search_box); - set_hide_on_ok(false); - search_options->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); - search_options->connect("cell_selected", callable_mp(this, &VisualScriptPropertySelector::_item_selected)); - search_options->set_hide_root(true); - search_options->set_hide_folding(true); - virtuals_only = false; - seq_connect = false; - help_bit = memnew(EditorHelpBit); - vbc->add_margin_child(TTR("Description:"), help_bit); - help_bit->connect("request_hide", callable_mp(this, &VisualScriptPropertySelector::_hide_requested)); - search_options->set_columns(3); - search_options->set_column_expand(1, false); - search_options->set_column_expand(2, false); +VisualScriptPropertySelector::SearchRunner::SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree) : + selector_ui(p_selector_ui), + ui_service(p_selector_ui->vbox), + results_tree(p_results_tree), + term(p_selector_ui->search_box->get_text()), + empty_icon(ui_service->get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"))), + disabled_color(ui_service->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))) { } diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h index 7a87f3d3ee..90a6265ab7 100644 --- a/modules/visual_script/editor/visual_script_property_selector.h +++ b/modules/visual_script/editor/visual_script_property_selector.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,6 +31,7 @@ #ifndef VISUALSCRIPT_PROPERTYSELECTOR_H #define VISUALSCRIPT_PROPERTYSELECTOR_H +#include "../visual_script.h" #include "editor/editor_help.h" #include "editor/property_editor.h" #include "scene/gui/rich_text_label.h" @@ -38,54 +39,191 @@ class VisualScriptPropertySelector : public ConfirmationDialog { GDCLASS(VisualScriptPropertySelector, ConfirmationDialog); - LineEdit *search_box; - Tree *search_options; + enum SearchFlags { + SEARCH_CLASSES = 1 << 0, + SEARCH_CONSTRUCTORS = 1 << 1, + SEARCH_METHODS = 1 << 2, + SEARCH_OPERATORS = 1 << 3, + SEARCH_SIGNALS = 1 << 4, + SEARCH_CONSTANTS = 1 << 5, + SEARCH_PROPERTIES = 1 << 6, + SEARCH_THEME_ITEMS = 1 << 7, + SEARCH_VISUAL_SCRIPT_NODES = 1 << 8, + SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS, + SEARCH_CASE_SENSITIVE = 1 << 29, + SEARCH_SHOW_HIERARCHY = 1 << 30, + }; + + enum ScopeFlags { + SCOPE_BASE = 1 << 0, + SCOPE_INHERITERS = 1 << 1, + SCOPE_UNRELATED = 1 << 2, + SCOPE_RELATED = SCOPE_BASE | SCOPE_INHERITERS, + SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED + }; + + enum ScopeCombo { + COMBO_RELATED, + COMBO_SEPARATOR, + COMBO_BASE, + COMBO_INHERITERS, + COMBO_UNRELATED, + COMBO_ALL, + }; + + LineEdit *search_box = nullptr; + + Button *case_sensitive_button = nullptr; + Button *hierarchy_button = nullptr; + + Button *search_visual_script_nodes = nullptr; + Button *search_classes = nullptr; + Button *search_operators = nullptr; + + Button *search_methods = nullptr; + Button *search_signals = nullptr; + Button *search_constants = nullptr; + Button *search_properties = nullptr; + Button *search_theme_items = nullptr; + + OptionButton *scope_combo = nullptr; + Tree *results_tree = nullptr; + + class SearchRunner; + Ref<SearchRunner> search_runner; + + void _update_icons(); - void _text_changed(const String &p_newtext); void _sbox_input(const Ref<InputEvent> &p_ie); - void _update_search(); - - void create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text); - void get_visual_node_names(const String &root_filter, const Set<String> &p_modifiers, bool &found, TreeItem *const root, LineEdit *const search_box); + void _update_results_i(int p_int); + void _update_results_s(String p_string); + void _update_results_search_all(); + void _update_results(); void _confirmed(); void _item_selected(); void _hide_requested(); - EditorHelpBit *help_bit; + EditorHelpBit *help_bit = nullptr; - bool properties; - bool visual_script_generic; - bool connecting; + bool properties = false; + bool visual_script_generic = false; + bool connecting = false; String selected; Variant::Type type; String base_type; + String base_script; ObjectID script; - Object *instance; - bool virtuals_only; - bool seq_connect; - VBoxContainer *vbc; - - Vector<Variant::Type> type_filter; + Object *instance = nullptr; + bool virtuals_only = false; + VBoxContainer *vbox = nullptr; protected: void _notification(int p_what); static void _bind_methods(); public: - void select_method_from_base_type(const String &p_base, const String &p_current = "", const bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true); - void select_from_base_type(const String &p_base, const String &p_current = "", bool p_virtuals_only = false, bool p_seq_connect = false, const bool p_connecting = true, bool clear_text = true); - void select_from_script(const Ref<Script> &p_script, const String &p_current = "", const bool p_connecting = true, bool clear_text = true); - void select_from_basic_type(Variant::Type p_type, const String &p_current = "", const bool p_connecting = true, bool clear_text = true); - void select_from_action(const String &p_type, const String &p_current = "", const bool p_connecting = true, bool clear_text = true); - void select_from_instance(Object *p_instance, const String &p_current = "", const bool p_connecting = true, const String &p_basetype = "", bool clear_text = true); - void select_from_visual_script(const String &p_base, const bool p_connecting = true, bool clear_text = true); + void select_method_from_base_type(const String &p_base, const bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true); + void select_from_base_type(const String &p_base, const String &p_base_script = "", bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true); + void select_from_script(const Ref<Script> &p_script, const bool p_connecting = true, bool clear_text = true); + void select_from_basic_type(Variant::Type p_type, const bool p_connecting = true, bool clear_text = true); + void select_from_action(const String &p_type, const bool p_connecting = true, bool clear_text = true); + void select_from_instance(Object *p_instance, const bool p_connecting = true, bool clear_text = true); + void select_from_visual_script(const Ref<Script> &p_script, bool clear_text = true); void show_window(float p_screen_ratio); - void set_type_filter(const Vector<Variant::Type> &p_type_filter); - VisualScriptPropertySelector(); }; +class VisualScriptPropertySelector::SearchRunner : public RefCounted { + enum Phase { + PHASE_INIT, + PHASE_MATCH_CLASSES_INIT, + PHASE_NODE_CLASSES_INIT, + PHASE_NODE_CLASSES_BUILD, + PHASE_MATCH_CLASSES, + PHASE_CLASS_ITEMS_INIT, + PHASE_CLASS_ITEMS, + PHASE_MEMBER_ITEMS_INIT, + PHASE_MEMBER_ITEMS, + PHASE_SELECT_MATCH, + PHASE_MAX + }; + int phase = 0; + + struct ClassMatch { + DocData::ClassDoc *doc; + bool name = false; + String category = ""; + Vector<DocData::MethodDoc *> constructors; + Vector<DocData::MethodDoc *> methods; + Vector<DocData::MethodDoc *> operators; + Vector<DocData::MethodDoc *> signals; + Vector<DocData::ConstantDoc *> constants; + Vector<DocData::PropertyDoc *> properties; + Vector<DocData::ThemeItemDoc *> theme_properties; + + bool required() { + return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size(); + } + }; + + VisualScriptPropertySelector *selector_ui = nullptr; + Control *ui_service = nullptr; + Tree *results_tree = nullptr; + String term; + int search_flags = 0; + int scope_flags = 0; + + Ref<Texture2D> empty_icon; + Color disabled_color; + + Map<String, DocData::ClassDoc>::Element *iterator_doc = nullptr; + Map<String, ClassMatch> matches; + Map<String, ClassMatch>::Element *iterator_match = nullptr; + TreeItem *root_item = nullptr; + Map<String, TreeItem *> class_items; + TreeItem *matched_item = nullptr; + float match_highest_score = 0; + + Map<String, DocData::ClassDoc> combined_docs; + List<String> vs_nodes; + + bool _is_class_disabled_by_feature_profile(const StringName &p_class); + bool _is_class_disabled_by_scope(const StringName &p_class); + + bool _slice(); + bool _phase_init(); + bool _phase_match_classes_init(); + bool _phase_node_classes_init(); + bool _phase_node_classes_build(); + bool _phase_match_classes(); + bool _phase_class_items_init(); + bool _phase_class_items(); + bool _phase_member_items_init(); + bool _phase_member_items(); + bool _phase_select_match(); + + bool _match_string(const String &p_term, const String &p_string) const; + bool _match_visual_script(DocData::ClassDoc &class_doc); + bool _match_is_hidden(DocData::ClassDoc &class_doc); + void _match_item(TreeItem *p_item, const String &p_text); + void _add_class_doc(String class_name, String inherits, String category); + DocData::MethodDoc _get_method_doc(MethodInfo method_info); + TreeItem *_create_class_hierarchy(const ClassMatch &p_match); + TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray); + TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc); + TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc); + TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc); + TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc); + TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc); + TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description); + +public: + bool work(uint64_t slot = 100000); + + SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree); +}; + #endif // VISUALSCRIPT_PROPERTYSELECTOR_H diff --git a/modules/visual_script/icons/VisualScript.svg b/modules/visual_script/icons/VisualScript.svg index 2352ba5d87..bc698247c9 100644 --- a/modules/visual_script/icons/VisualScript.svg +++ b/modules/visual_script/icons/VisualScript.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg> diff --git a/modules/visual_script/icons/VisualScriptInternal.svg b/modules/visual_script/icons/VisualScriptInternal.svg new file mode 100644 index 0000000000..8ab39ad929 --- /dev/null +++ b/modules/visual_script/icons/VisualScriptInternal.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="3" cy="3.000024" fill="#e0e0e0" r="0"/><path d="m11 10a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0"/><path d="m3 10v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2z" fill="none" stroke="#e0e0e0"/></svg> diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index 6f56fbbc70..04a7442d0a 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -47,95 +47,104 @@ VisualScriptLanguage *visual_script_language = nullptr; static VisualScriptCustomNodes *vs_custom_nodes_singleton = nullptr; #endif -void register_visual_script_types() { - visual_script_language = memnew(VisualScriptLanguage); - //script_language_gd->init(); - ScriptServer::register_language(visual_script_language); - - 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>(); - GDREGISTER_CLASS(VisualScriptEmitSignal); - - GDREGISTER_CLASS(VisualScriptReturn); - GDREGISTER_CLASS(VisualScriptCondition); - GDREGISTER_CLASS(VisualScriptWhile); - GDREGISTER_CLASS(VisualScriptIterator); - GDREGISTER_CLASS(VisualScriptSequence); - //GDREGISTER_CLASS(VisualScriptInputFilter); - GDREGISTER_CLASS(VisualScriptSwitch); - GDREGISTER_CLASS(VisualScriptSelect); - - GDREGISTER_CLASS(VisualScriptYield); - GDREGISTER_CLASS(VisualScriptYieldSignal); - - GDREGISTER_CLASS(VisualScriptBuiltinFunc); - - GDREGISTER_CLASS(VisualScriptExpression); - - register_visual_script_nodes(); - register_visual_script_func_nodes(); - register_visual_script_builtin_func_node(); - register_visual_script_flow_control_nodes(); - register_visual_script_yield_nodes(); - register_visual_script_expression_node(); +void initialize_visual_script_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + visual_script_language = memnew(VisualScriptLanguage); + //script_language_gd->init(); + ScriptServer::register_language(visual_script_language); + + GDREGISTER_CLASS(VisualScript); + GDREGISTER_ABSTRACT_CLASS(VisualScriptNode); + GDREGISTER_CLASS(VisualScriptFunctionState); + GDREGISTER_CLASS(VisualScriptFunction); + GDREGISTER_ABSTRACT_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>(); + GDREGISTER_CLASS(VisualScriptEmitSignal); + + GDREGISTER_CLASS(VisualScriptReturn); + GDREGISTER_CLASS(VisualScriptCondition); + GDREGISTER_CLASS(VisualScriptWhile); + GDREGISTER_CLASS(VisualScriptIterator); + GDREGISTER_CLASS(VisualScriptSequence); + //GDREGISTER_CLASS(VisualScriptInputFilter); + GDREGISTER_CLASS(VisualScriptSwitch); + GDREGISTER_CLASS(VisualScriptSelect); + + GDREGISTER_CLASS(VisualScriptYield); + GDREGISTER_CLASS(VisualScriptYieldSignal); + + GDREGISTER_CLASS(VisualScriptBuiltinFunc); + + GDREGISTER_CLASS(VisualScriptExpression); + + register_visual_script_nodes(); + register_visual_script_func_nodes(); + register_visual_script_builtin_func_node(); + register_visual_script_flow_control_nodes(); + register_visual_script_yield_nodes(); + register_visual_script_expression_node(); + } #ifdef TOOLS_ENABLED - ClassDB::set_current_api(ClassDB::API_EDITOR); - GDREGISTER_CLASS(VisualScriptCustomNodes); - ClassDB::set_current_api(ClassDB::API_CORE); - vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes); - Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton())); - - VisualScriptEditor::register_editor(); + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + ClassDB::set_current_api(ClassDB::API_EDITOR); + GDREGISTER_CLASS(VisualScriptCustomNodes); + ClassDB::set_current_api(ClassDB::API_CORE); + vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes); + Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton())); + + VisualScriptEditor::register_editor(); + } #endif } -void unregister_visual_script_types() { - unregister_visual_script_nodes(); +void uninitialize_visual_script_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { + unregister_visual_script_nodes(); - ScriptServer::unregister_language(visual_script_language); + ScriptServer::unregister_language(visual_script_language); + + if (visual_script_language) { + memdelete(visual_script_language); + } + } #ifdef TOOLS_ENABLED - VisualScriptEditor::free_clipboard(); - if (vs_custom_nodes_singleton) { - memdelete(vs_custom_nodes_singleton); + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + VisualScriptEditor::free_clipboard(); + if (vs_custom_nodes_singleton) { + memdelete(vs_custom_nodes_singleton); + } } #endif - if (visual_script_language) { - memdelete(visual_script_language); - } } diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h index b02a93ebc1..90f84de11c 100644 --- a/modules/visual_script/register_types.h +++ b/modules/visual_script/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef VISUAL_SCRIPT_REGISTER_TYPES_H #define VISUAL_SCRIPT_REGISTER_TYPES_H -void register_visual_script_types(); -void unregister_visual_script_types(); +#include "modules/register_module_types.h" + +void initialize_visual_script_module(ModuleInitializationLevel p_level); +void uninitialize_visual_script_module(ModuleInitializationLevel p_level); #endif // VISUAL_SCRIPT_REGISTER_TYPES_H diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 63bd9bbee4..7028fead9a 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -930,8 +930,9 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { get_variable_list(&vars); for (const StringName &E : vars) { - //if (!variables[E]._export) - // continue; + if (!variables[E]._export) { + continue; + } PropertyInfo pi = variables[E].info; pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; p_list->push_back(pi); @@ -1120,7 +1121,7 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function); ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function); ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function); - ClassDB::bind_method(D_METHOD("set_scroll", "ofs"), &VisualScript::set_scroll); + ClassDB::bind_method(D_METHOD("set_scroll", "offset"), &VisualScript::set_scroll); ClassDB::bind_method(D_METHOD("get_scroll"), &VisualScript::get_scroll); ClassDB::bind_method(D_METHOD("add_node", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2())); @@ -1164,9 +1165,6 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_custom_signal", "name"), &VisualScript::remove_custom_signal); ClassDB::bind_method(D_METHOD("rename_custom_signal", "name", "new_name"), &VisualScript::rename_custom_signal); - //ClassDB::bind_method(D_METHOD("set_variable_info","name","info"),&VScript::set_variable_info); - //ClassDB::bind_method(D_METHOD("get_variable_info","name"),&VScript::set_variable_info); - ClassDB::bind_method(D_METHOD("set_instance_base_type", "type"), &VisualScript::set_instance_base_type); ClassDB::bind_method(D_METHOD("_set_data", "data"), &VisualScript::_set_data); @@ -1710,7 +1708,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p return return_value; } -Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; //ok by default Map<StringName, Function>::Element *F = functions.find(p_method); @@ -1803,13 +1801,13 @@ void VisualScriptInstance::notification(int p_notification) { Variant what = p_notification; const Variant *whatp = &what; Callable::CallError ce; - call(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); // Do as call. + callp(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); // Do as call. } String VisualScriptInstance::to_string(bool *r_valid) { if (has_method(CoreStringNames::get_singleton()->_to_string)) { Callable::CallError ce; - Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); + Variant ret = callp(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); if (ce.error == Callable::CallError::CALL_OK) { if (ret.get_type() != Variant::STRING) { if (r_valid) { @@ -2241,20 +2239,15 @@ void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) co void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { } -Ref<Script> VisualScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - Ref<VisualScript> script; - script.instantiate(); - script->set_instance_base_type(p_base_class_name); - return script; -} - bool VisualScriptLanguage::is_using_templates() { - return true; + return false; } -void VisualScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { - Ref<VisualScript> script = p_script; +Ref<Script> VisualScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { + Ref<VisualScript> script; + script.instantiate(); script->set_instance_base_type(p_base_class_name); + return script; } 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 { diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 39cef8f68b..6b27af15f6 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -338,8 +338,8 @@ public: virtual Error reload(bool p_keep_state = false) override; #ifdef TOOLS_ENABLED - virtual const Vector<DocData::ClassDoc> &get_documentation() const override { - static Vector<DocData::ClassDoc> docs; + virtual Vector<DocData::ClassDoc> get_documentation() const override { + Vector<DocData::ClassDoc> docs; return docs; } #endif // TOOLS_ENABLED @@ -410,7 +410,7 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual void notification(int p_notification); String to_string(bool *r_valid); @@ -495,7 +495,7 @@ class VisualScriptLanguage : public ScriptLanguage { String _debug_error; int _debug_call_stack_pos = 0; int _debug_max_call_stack; - CallLevel *_call_stack; + CallLevel *_call_stack = nullptr; public: StringName notification = "_notification"; @@ -554,57 +554,56 @@ public: ////////////////////////////////////// - virtual String get_name() const; + virtual String get_name() const override; /* LANGUAGE FUNCTIONS */ - virtual void init(); - virtual String get_type() const; - virtual String get_extension() const; - virtual Error execute_file(const String &p_path); - virtual void finish(); + virtual void init() override; + virtual String get_type() const override; + virtual String get_extension() const override; + virtual Error execute_file(const String &p_path) override; + virtual void finish() override; /* 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, 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; - virtual int find_function(const String &p_function, const String &p_code) const; - virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; - virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; - virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); + virtual void get_reserved_words(List<String> *p_words) const override; + virtual bool is_control_flow_keyword(String p_keyword) const override; + virtual void get_comment_delimiters(List<String> *p_delimiters) const override; + virtual void get_string_delimiters(List<String> *p_delimiters) const override; + virtual bool is_using_templates() override; + virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; + 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 override; + virtual Script *create_script() const override; + virtual bool has_named_classes() const override; + virtual bool supports_builtin_mode() const override; + virtual int find_function(const String &p_function, const String &p_code) const override; + virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override; + virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override; + virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) override; /* DEBUGGER FUNCTIONS */ - virtual String debug_get_error() const; - virtual int debug_get_stack_level_count() const; - virtual int debug_get_stack_level_line(int p_level) const; - virtual String debug_get_stack_level_function(int p_level) const; - virtual String debug_get_stack_level_source(int p_level) const; - virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); - - virtual void reload_all_scripts(); - virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); + virtual String debug_get_error() const override; + virtual int debug_get_stack_level_count() const override; + virtual int debug_get_stack_level_line(int p_level) const override; + virtual String debug_get_stack_level_function(int p_level) const override; + virtual String debug_get_stack_level_source(int p_level) const override; + virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; + virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; + virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; + virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) override; + + virtual void reload_all_scripts() override; + virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override; /* LOADER FUNCTIONS */ - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual void get_public_functions(List<MethodInfo> *p_functions) const; - virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual void get_public_functions(List<MethodInfo> *p_functions) const override; + virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override; - virtual void profiling_start(); - virtual void profiling_stop(); + virtual void profiling_start() override; + virtual void profiling_stop() override; - virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); - virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); + virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override; + virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override; void add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func); void remove_register_func(const String &p_name); diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 7ae85ea415..44e792869d 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -65,6 +65,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "step_decimals", "snapped", "lerp", + "cubic_interpolate", "inverse_lerp", "range_lerp", "move_toward", @@ -212,6 +213,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case MATH_WRAPF: case LOGIC_CLAMP: return 3; + case MATH_CUBIC_INTERPOLATE: case MATH_RANGE_LERP: return 5; case FUNC_MAX: { @@ -329,6 +331,19 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::FLOAT, "weight"); } } break; + case MATH_CUBIC_INTERPOLATE: { + if (p_idx == 0) { + return PropertyInfo(Variant::FLOAT, "from"); + } else if (p_idx == 1) { + return PropertyInfo(Variant::FLOAT, "to"); + } else if (p_idx == 2) { + return PropertyInfo(Variant::FLOAT, "pre"); + } else if (p_idx == 3) { + return PropertyInfo(Variant::FLOAT, "post"); + } else { + return PropertyInfo(Variant::FLOAT, "weight"); + } + } break; case MATH_RANGE_LERP: { if (p_idx == 0) { return PropertyInfo(Variant::FLOAT, "value"); @@ -525,6 +540,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } break; case MATH_SNAPPED: case MATH_LERP: + case MATH_CUBIC_INTERPOLATE: case MATH_LERP_ANGLE: case MATH_INVERSE_LERP: case MATH_RANGE_LERP: @@ -795,6 +811,14 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(2); *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; + case VisualScriptBuiltinFunc::MATH_CUBIC_INTERPOLATE: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + VALIDATE_ARG_NUM(3); + VALIDATE_ARG_NUM(4); + *r_return = Math::cubic_interpolate((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); + } break; case VisualScriptBuiltinFunc::MATH_LERP_ANGLE: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); @@ -964,8 +988,8 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in return; } - if (p_inputs[0]->is_ref()) { - REF r = *p_inputs[0]; + if (p_inputs[0]->is_ref_counted()) { + Ref<RefCounted> r = *p_inputs[0]; if (!r.is_valid()) { return; } @@ -1156,16 +1180,16 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { public: - VisualScriptBuiltinFunc *node; - VisualScriptInstance *instance; + VisualScriptBuiltinFunc *node = nullptr; + VisualScriptInstance *instance = nullptr; VisualScriptBuiltinFunc::BuiltinFunc func; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str); return 0; } @@ -1220,6 +1244,7 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_STEP_DECIMALS); BIND_ENUM_CONSTANT(MATH_SNAPPED); BIND_ENUM_CONSTANT(MATH_LERP); + BIND_ENUM_CONSTANT(MATH_CUBIC_INTERPOLATE); BIND_ENUM_CONSTANT(MATH_INVERSE_LERP); BIND_ENUM_CONSTANT(MATH_RANGE_LERP); BIND_ENUM_CONSTANT(MATH_MOVE_TOWARD); @@ -1309,6 +1334,7 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/step_decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEP_DECIMALS>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/snapped", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SNAPPED>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/cubic_interpolate", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CUBIC_INTERPOLATE>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp_angle", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP_ANGLE>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index f71a053f7d..18935b9995 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -65,6 +65,7 @@ public: MATH_STEP_DECIMALS, MATH_SNAPPED, MATH_LERP, + MATH_CUBIC_INTERPOLATE, MATH_INVERSE_LERP, MATH_RANGE_LERP, MATH_MOVE_TOWARD, diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index 699042ffa6..e0f6436094 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -176,7 +176,7 @@ PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const } String VisualScriptExpression::get_caption() const { - return "Expression"; + return RTR("Expression"); } String VisualScriptExpression::get_text() const { @@ -328,6 +328,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) { }; case '"': { String str; + char32_t prev = 0; while (true) { char32_t ch = GET_CHAR(); @@ -364,9 +365,11 @@ Error VisualScriptExpression::_get_token(Token &r_token) { case 'r': res = 13; break; + case 'U': case 'u': { - // hex number - for (int j = 0; j < 4; j++) { + // Hexadecimal sequence. + int hex_len = (next == 'U') ? 6 : 4; + for (int j = 0; j < hex_len; j++) { char32_t c = GET_CHAR(); if (c == 0) { @@ -374,13 +377,13 @@ Error VisualScriptExpression::_get_token(Token &r_token) { r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } - if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { + if (!is_hex_digit(c)) { _set_error("Malformed hex constant in string"); r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } char32_t v; - if (c >= '0' && c <= '9') { + if (is_digit(c)) { v = c - '0'; } else if (c >= 'a' && c <= 'f') { v = c - 'a'; @@ -403,12 +406,46 @@ Error VisualScriptExpression::_get_token(Token &r_token) { } break; } + // Parse UTF-16 pair. + if ((res & 0xfffffc00) == 0xd800) { + if (prev == 0) { + prev = res; + continue; + } else { + _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + } else if ((res & 0xfffffc00) == 0xdc00) { + if (prev == 0) { + _set_error("Invalid UTF-16 sequence in string, unpaired trail surrogate"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } else { + res = (prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000); + prev = 0; + } + } + if (prev != 0) { + _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } str += res; - } else { + if (prev != 0) { + _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } str += ch; } } + if (prev != 0) { + _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } r_token.type = TK_CONSTANT; r_token.value = str; @@ -420,7 +457,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) { break; } - if (cchar >= '0' && cchar <= '9') { + if (is_digit(cchar)) { //a number String num; @@ -439,7 +476,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) { while (true) { switch (reading) { case READING_INT: { - if (c >= '0' && c <= '9') { + if (is_digit(c)) { //pass } else if (c == '.') { reading = READING_DEC; @@ -452,7 +489,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) { } break; case READING_DEC: { - if (c >= '0' && c <= '9') { + if (is_digit(c)) { } else if (c == 'e') { reading = READING_EXP; @@ -462,7 +499,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) { } break; case READING_EXP: { - if (c >= '0' && c <= '9') { + if (is_digit(c)) { exp_beg = true; } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) { @@ -495,11 +532,11 @@ Error VisualScriptExpression::_get_token(Token &r_token) { } return OK; - } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') { + } else if (is_ascii_char(cchar) || cchar == '_') { String id; bool first = true; - while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) { + while (is_ascii_char(cchar) || cchar == '_' || (!first && is_digit(cchar))) { id += String::chr(cchar); cchar = GET_CHAR(); first = false; @@ -1262,10 +1299,10 @@ bool VisualScriptExpression::_compile_expression() { class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; - VisualScriptExpression *expression; + VisualScriptInstance *instance = nullptr; + VisualScriptExpression *expression = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //execute by parsing the tree directly virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) { switch (p_node->type) { @@ -1463,7 +1500,7 @@ public: argp.write[i] = &arr[i]; } - base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); + base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); if (ce.error != Callable::CallError::CALL_OK) { r_error_str = "On call to '" + String(call->method) + "':"; @@ -1475,7 +1512,7 @@ public: return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!expression->root || expression->error_set) { r_error_str = expression->error_str; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h index ef16222b42..c93eb0686b 100644 --- a/modules/visual_script/visual_script_expression.h +++ b/modules/visual_script/visual_script_expression.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index 278d806595..0e63753720 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -70,7 +70,7 @@ PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const { } String VisualScriptReturn::get_caption() const { - return "Return"; + return RTR("Return"); } String VisualScriptReturn::get_text() const { @@ -119,15 +119,15 @@ void VisualScriptReturn::_bind_methods() { class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance { public: - VisualScriptReturn *node; - VisualScriptInstance *instance; - bool with_value; + VisualScriptReturn *node = nullptr; + VisualScriptInstance *instance = nullptr; + bool with_value = false; - virtual int get_working_memory_size() const { return 1; } + virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (with_value) { *p_working_mem = *p_inputs[0]; return STEP_EXIT_FUNCTION_BIT; @@ -201,11 +201,11 @@ PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const } String VisualScriptCondition::get_caption() const { - return "Condition"; + return RTR("Condition"); } String VisualScriptCondition::get_text() const { - return "if (cond) is: "; + return RTR("if (cond) is:"); } void VisualScriptCondition::_bind_methods() { @@ -213,14 +213,14 @@ void VisualScriptCondition::_bind_methods() { class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance { public: - VisualScriptCondition *node; - VisualScriptInstance *instance; + VisualScriptCondition *node = nullptr; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 1; } + //virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) { return 2; } else if (p_inputs[0]->operator bool()) { @@ -281,11 +281,11 @@ PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const { } String VisualScriptWhile::get_caption() const { - return "While"; + return RTR("While"); } String VisualScriptWhile::get_text() const { - return "while (cond): "; + return RTR("while (cond):"); } void VisualScriptWhile::_bind_methods() { @@ -293,14 +293,14 @@ void VisualScriptWhile::_bind_methods() { class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance { public: - VisualScriptWhile *node; - VisualScriptInstance *instance; + VisualScriptWhile *node = nullptr; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 1; } + //virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool keep_going = p_inputs[0]->operator bool(); if (keep_going) { @@ -364,11 +364,11 @@ PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const { } String VisualScriptIterator::get_caption() const { - return "Iterator"; + return RTR("Iterator"); } String VisualScriptIterator::get_text() const { - return "for (elem) in (input): "; + return RTR("for (elem) in (input):"); } void VisualScriptIterator::_bind_methods() { @@ -376,14 +376,14 @@ void VisualScriptIterator::_bind_methods() { class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance { public: - VisualScriptIterator *node; - VisualScriptInstance *instance; + VisualScriptIterator *node = nullptr; + VisualScriptInstance *instance = nullptr; - virtual int get_working_memory_size() const { return 2; } + virtual int get_working_memory_size() const override { return 2; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_BEGIN_SEQUENCE) { p_working_mem[0] = *p_inputs[0]; bool valid; @@ -478,11 +478,11 @@ PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const { } String VisualScriptSequence::get_caption() const { - return "Sequence"; + return RTR("Sequence"); } String VisualScriptSequence::get_text() const { - return "in order: "; + return RTR("in order:"); } void VisualScriptSequence::set_steps(int p_steps) { @@ -508,15 +508,15 @@ void VisualScriptSequence::_bind_methods() { class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance { public: - VisualScriptSequence *node; - VisualScriptInstance *instance; - int steps; + VisualScriptSequence *node = nullptr; + VisualScriptInstance *instance = nullptr; + int steps = 0; - virtual int get_working_memory_size() const { return 1; } + virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_BEGIN_SEQUENCE) { p_working_mem[0] = 0; } @@ -587,23 +587,23 @@ PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const { } String VisualScriptSwitch::get_caption() const { - return "Switch"; + return RTR("Switch"); } String VisualScriptSwitch::get_text() const { - return "'input' is:"; + return RTR("'input' is:"); } class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; - int case_count; + VisualScriptInstance *instance = nullptr; + int case_count = 0; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) { return case_count; //exit } @@ -720,14 +720,14 @@ PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const { } String VisualScriptTypeCast::get_caption() const { - return "Type Cast"; + return RTR("Type Cast"); } String VisualScriptTypeCast::get_text() const { if (!script.is_empty()) { - return "Is " + script.get_file() + "?"; + return vformat(RTR("Is %s?"), script.get_file()); } else { - return "Is " + base_type + "?"; + return vformat(RTR("Is %s?"), base_type); } } @@ -774,15 +774,15 @@ VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGues class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; StringName base_type; String script; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Object *obj = *p_inputs[0]; *p_outputs[0] = Variant(); diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index 73822fcc37..7ffdf3df65 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 651464dfdb..483fc8b6c3 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,6 +33,7 @@ #include "core/config/engine.h" #include "core/io/resource_loader.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" #include "visual_script_nodes.h" @@ -261,13 +262,13 @@ String VisualScriptFunctionCall::get_text() const { String text; if (call_mode == CALL_MODE_BASIC_TYPE) { - text = String("On ") + Variant::get_type_name(basic_type); + text = vformat(RTR("On %s"), Variant::get_type_name(basic_type)); } else if (call_mode == CALL_MODE_INSTANCE) { - text = String("On ") + base_type; + text = vformat(RTR("On %s"), base_type); } else if (call_mode == CALL_MODE_NODE_PATH) { text = "[" + String(base_path.simplified()) + "]"; } else if (call_mode == CALL_MODE_SELF) { - text = "On Self"; + text = RTR("On Self"); } else if (call_mode == CALL_MODE_SINGLETON) { text = String(singleton) + ":" + String(function) + "()"; } @@ -719,17 +720,17 @@ class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance { public: VisualScriptFunctionCall::CallMode call_mode; NodePath node_path; - int input_args; - bool validate; - int returns; + int input_args = 0; + bool validate = false; + int returns = 0; VisualScriptFunctionCall::RPCCallMode rpc_mode; StringName function; StringName singleton; - VisualScriptFunctionCall *node; - VisualScriptInstance *instance; + VisualScriptFunctionCall *node = nullptr; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } @@ -764,7 +765,7 @@ public: return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (call_mode) { case VisualScriptFunctionCall::CALL_MODE_SELF: { Object *object = instance->get_owner_ptr(); @@ -772,9 +773,9 @@ public: if (rpc_mode) { call_rpc(object, p_inputs, input_args); } else if (returns) { - *p_outputs[0] = object->call(function, p_inputs, input_args, r_error); + *p_outputs[0] = object->callp(function, p_inputs, input_args, r_error); } else { - object->call(function, p_inputs, input_args, r_error); + object->callp(function, p_inputs, input_args, r_error); } } break; case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: { @@ -795,9 +796,9 @@ public: if (rpc_mode) { call_rpc(node, p_inputs, input_args); } else if (returns) { - *p_outputs[0] = another->call(function, p_inputs, input_args, r_error); + *p_outputs[0] = another->callp(function, p_inputs, input_args, r_error); } else { - another->call(function, p_inputs, input_args, r_error); + another->callp(function, p_inputs, input_args, r_error); } } break; @@ -813,21 +814,21 @@ public: } else if (returns) { if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) { if (returns >= 2) { - v.call(function, p_inputs + 1, input_args, *p_outputs[1], r_error); + v.callp(function, p_inputs + 1, input_args, *p_outputs[1], r_error); } else if (returns == 1) { Variant ret; - v.call(function, p_inputs + 1, input_args, ret, r_error); + v.callp(function, p_inputs + 1, input_args, ret, r_error); } else { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Invalid returns count for call_mode == CALL_MODE_INSTANCE"; return 0; } } else { - v.call(function, p_inputs + 1, input_args, *p_outputs[0], r_error); + v.callp(function, p_inputs + 1, input_args, *p_outputs[0], r_error); } } else { Variant ret; - v.call(function, p_inputs + 1, input_args, ret, r_error); + v.callp(function, p_inputs + 1, input_args, ret, r_error); } if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) { @@ -846,9 +847,9 @@ public: if (rpc_mode) { call_rpc(object, p_inputs, input_args); } else if (returns) { - *p_outputs[0] = object->call(function, p_inputs, input_args, r_error); + *p_outputs[0] = object->callp(function, p_inputs, input_args, r_error); } else { - object->call(function, p_inputs, input_args, r_error); + object->callp(function, p_inputs, input_args, r_error); } } break; } @@ -912,7 +913,7 @@ int VisualScriptPropertySet::get_output_sequence_port_count() const { } bool VisualScriptPropertySet::has_input_sequence_port() const { - return 1; + return true; } Node *VisualScriptPropertySet::_get_base_node() const { @@ -1032,16 +1033,26 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons } String VisualScriptPropertySet::get_caption() const { - static const char *opname[ASSIGN_OP_MAX] = { - "Set", "Add", "Subtract", "Multiply", "Divide", "Mod", "ShiftLeft", "ShiftRight", "BitAnd", "BitOr", "BitXor" + static const LocalVector<String> opname = { + RTR("Set %s"), + RTR("Add %s"), + RTR("Subtract %s"), + RTR("Multiply %s"), + RTR("Divide %s"), + RTR("Mod %s"), + RTR("ShiftLeft %s"), + RTR("ShiftRight %s"), + RTR("BitAnd %s"), + RTR("BitOr %s"), + RTR("BitXor %s"), }; - String prop = String(opname[assign_op]) + " " + property; + String prop = property; if (index != StringName()) { prop += "." + String(index); } - return prop; + return vformat(opname[assign_op], prop); } String VisualScriptPropertySet::get_text() const { @@ -1049,13 +1060,13 @@ String VisualScriptPropertySet::get_text() const { return ""; } if (call_mode == CALL_MODE_BASIC_TYPE) { - return String("On ") + Variant::get_type_name(basic_type); + return vformat(RTR("On %s"), Variant::get_type_name(basic_type)); } else if (call_mode == CALL_MODE_INSTANCE) { - return String("On ") + base_type; + return vformat(RTR("On %s"), base_type); } else if (call_mode == CALL_MODE_NODE_PATH) { return " [" + String(base_path.simplified()) + "]"; } else { - return "On Self"; + return RTR("On Self"); } } @@ -1451,13 +1462,13 @@ public: NodePath node_path; StringName property; - VisualScriptPropertySet *node; - VisualScriptInstance *instance; + VisualScriptPropertySet *node = nullptr; + VisualScriptInstance *instance = nullptr; VisualScriptPropertySet::AssignOp assign_op; StringName index; - bool needs_get; + bool needs_get = false; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } @@ -1518,7 +1529,7 @@ public: } } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (call_mode) { case VisualScriptPropertySet::CALL_MODE_SELF: { Object *object = instance->get_owner_ptr(); @@ -1761,23 +1772,23 @@ PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) cons } String VisualScriptPropertyGet::get_caption() const { - String prop = String("Get ") + property; + String prop = property; if (index != StringName()) { prop += "." + String(index); } - return prop; + return vformat(RTR("Get %s"), prop); } String VisualScriptPropertyGet::get_text() const { if (call_mode == CALL_MODE_BASIC_TYPE) { - return String("On ") + Variant::get_type_name(basic_type); + return vformat(RTR("On %s"), Variant::get_type_name(basic_type)); } else if (call_mode == CALL_MODE_INSTANCE) { - return String("On ") + base_type; + return vformat(RTR("On %s"), base_type); } else if (call_mode == CALL_MODE_NODE_PATH) { return " [" + String(base_path.simplified()) + "]"; } else { - return "On Self"; + return RTR("On Self"); } } @@ -2141,10 +2152,10 @@ public: StringName property; StringName index; - VisualScriptPropertyGet *node; - VisualScriptInstance *instance; + VisualScriptPropertyGet *node = nullptr; + VisualScriptInstance *instance = nullptr; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (call_mode) { case VisualScriptPropertyGet::CALL_MODE_SELF: { Object *object = instance->get_owner_ptr(); @@ -2293,7 +2304,7 @@ PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const } String VisualScriptEmitSignal::get_caption() const { - return "Emit " + String(name); + return vformat(RTR("Emit %s"), name); } void VisualScriptEmitSignal::set_signal(const StringName &p_type) { @@ -2316,10 +2327,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { property.hint = PROPERTY_HINT_ENUM; List<StringName> sigs; + List<MethodInfo> base_sigs; Ref<VisualScript> vs = get_visual_script(); if (vs.is_valid()) { vs->get_custom_signal_list(&sigs); + ClassDB::get_signal_list(vs->get_instance_base_type(), &base_sigs); } String ml; @@ -2329,6 +2342,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { } ml += E; } + for (const MethodInfo &E : base_sigs) { + if (!ml.is_empty()) { + ml += ","; + } + ml += E.name; + } property.hint_string = ml; } @@ -2343,19 +2362,19 @@ void VisualScriptEmitSignal::_bind_methods() { class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { public: - VisualScriptEmitSignal *node; - VisualScriptInstance *instance; - int argcount; + VisualScriptEmitSignal *node = nullptr; + VisualScriptInstance *instance = nullptr; + int argcount = 0; StringName name; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Object *obj = instance->get_owner_ptr(); - obj->emit_signal(name, p_inputs, argcount); + obj->emit_signalp(name, p_inputs, argcount); return 0; } diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index cca08455f9..886ed7bc81 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index bb4c83bd24..dbbe74f3d5 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -204,7 +204,7 @@ PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const { } String VisualScriptFunction::get_caption() const { - return "Function"; + return RTR("Function"); } String VisualScriptFunction::get_text() const { @@ -271,12 +271,12 @@ Multiplayer::RPCMode VisualScriptFunction::get_rpc_mode() const { class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance { public: - VisualScriptFunction *node; - VisualScriptInstance *instance; + VisualScriptFunction *node = nullptr; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { int ac = node->get_argument_count(); for (int i = 0; i < ac; i++) { @@ -767,7 +767,7 @@ PropertyInfo VisualScriptComposeArray::get_output_value_port_info(int p_idx) con } String VisualScriptComposeArray::get_caption() const { - return "Compose Array"; + return RTR("Compose Array"); } String VisualScriptComposeArray::get_text() const { @@ -777,9 +777,9 @@ String VisualScriptComposeArray::get_text() const { class VisualScriptComposeArrayNode : public VisualScriptNodeInstance { public: int input_count = 0; - virtual int get_working_memory_size() const { return 0; } + virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (input_count > 0) { Array arr; for (int i = 0; i < input_count; i++) { @@ -1097,12 +1097,12 @@ void VisualScriptOperator::_bind_methods() { class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { public: - bool unary; + bool unary = false; Variant::Operator op; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; if (unary) { Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid); @@ -1186,11 +1186,11 @@ PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const { } String VisualScriptSelect::get_caption() const { - return "Select"; + return RTR("Select"); } String VisualScriptSelect::get_text() const { - return "a if cond, else b"; + return RTR("a if cond, else b"); } void VisualScriptSelect::set_typed(Variant::Type p_op) { @@ -1220,9 +1220,9 @@ void VisualScriptSelect::_bind_methods() { class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance { public: - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool cond = *p_inputs[0]; if (cond) { *p_outputs[0] = *p_inputs[1]; @@ -1284,7 +1284,7 @@ PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) cons } String VisualScriptVariableGet::get_caption() const { - return "Get " + variable; + return vformat(RTR("Get %s"), variable); } void VisualScriptVariableGet::set_variable(StringName p_variable) { @@ -1328,11 +1328,11 @@ void VisualScriptVariableGet::_bind_methods() { class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { public: - VisualScriptVariableGet *node; - VisualScriptInstance *instance; + VisualScriptVariableGet *node = nullptr; + VisualScriptInstance *instance = nullptr; StringName variable; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!instance->get_variable(variable, p_outputs[0])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("VariableGet not found in script: ") + "'" + String(variable) + "'"; @@ -1394,7 +1394,7 @@ PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) cons } String VisualScriptVariableSet::get_caption() const { - return "Set " + variable; + return vformat(RTR("Set %s"), variable); } void VisualScriptVariableSet::set_variable(StringName p_variable) { @@ -1438,13 +1438,13 @@ void VisualScriptVariableSet::_bind_methods() { class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { public: - VisualScriptVariableSet *node; - VisualScriptInstance *instance; + VisualScriptVariableSet *node = nullptr; + VisualScriptInstance *instance = nullptr; StringName variable; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!instance->set_variable(variable, *p_inputs[0])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("VariableSet not found in script: ") + "'" + String(variable) + "'"; @@ -1501,7 +1501,7 @@ PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const { } String VisualScriptConstant::get_caption() const { - return "Constant"; + return RTR("Constant"); } void VisualScriptConstant::set_constant_type(Variant::Type p_type) { @@ -1561,9 +1561,9 @@ void VisualScriptConstant::_bind_methods() { class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { public: Variant constant; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = constant; return 0; } @@ -1628,7 +1628,7 @@ PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const { } String VisualScriptPreload::get_caption() const { - return "Preload"; + return RTR("Preload"); } void VisualScriptPreload::set_preload(const Ref<Resource> &p_preload) { @@ -1654,9 +1654,9 @@ void VisualScriptPreload::_bind_methods() { class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance { public: Ref<Resource> preload; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = preload; return 0; } @@ -1708,14 +1708,14 @@ PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const { } String VisualScriptIndexGet::get_caption() const { - return "Get Index"; + return RTR("Get Index"); } class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { public: - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; *p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid); @@ -1775,19 +1775,16 @@ PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const { } String VisualScriptIndexSet::get_caption() const { - return "Set Index"; + return RTR("Set Index"); } class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { public: - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; - // *p_output[0] points to the same place as *p_inputs[2] so we need a temp to store the value before the change in the next line - Variant temp = *p_inputs[2]; - *p_outputs[0] = *p_inputs[0]; - p_outputs[0]->set(*p_inputs[1], temp, &valid); + ((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid); if (!valid) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -1839,7 +1836,7 @@ PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) c } String VisualScriptGlobalConstant::get_caption() const { - return "Global Constant"; + return RTR("Global Constant"); } void VisualScriptGlobalConstant::set_global_constant(int p_which) { @@ -1854,10 +1851,9 @@ int VisualScriptGlobalConstant::get_global_constant() { class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance { public: - int index; - //virtual int get_working_memory_size() const { return 0; } + int index = 0; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = CoreConstants::get_global_constant_value(index); return 0; } @@ -1925,7 +1921,7 @@ PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) co } String VisualScriptClassConstant::get_caption() const { - return "Class Constant"; + return RTR("Class Constant"); } void VisualScriptClassConstant::set_class_constant(const StringName &p_which) { @@ -1966,11 +1962,10 @@ StringName VisualScriptClassConstant::get_base_type() { class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance { public: - int value; - bool valid; - //virtual int get_working_memory_size() const { return 0; } + int value = 0; + bool valid = false; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Invalid constant name, pick a valid class constant."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2050,7 +2045,7 @@ PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx } String VisualScriptBasicTypeConstant::get_caption() const { - return "Basic Constant"; + return RTR("Basic Constant"); } String VisualScriptBasicTypeConstant::get_text() const { @@ -2101,10 +2096,9 @@ Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const { class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance { public: Variant value; - bool valid; - //virtual int get_working_memory_size() const { return 0; } + bool valid = false; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Invalid constant name, pick a valid basic type constant."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2215,7 +2209,7 @@ PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) con } String VisualScriptMathConstant::get_caption() const { - return "Math Constant"; + return RTR("Math Constant"); } void VisualScriptMathConstant::set_math_constant(MathConstant p_which) { @@ -2230,10 +2224,9 @@ VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_consta class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance { public: - float value; - //virtual int get_working_memory_size() const { return 0; } + float value = 0.0f; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = value; return 0; } @@ -2307,7 +2300,7 @@ PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) } String VisualScriptEngineSingleton::get_caption() const { - return "Get Engine Singleton"; + return RTR("Get Engine Singleton"); } void VisualScriptEngineSingleton::set_singleton(const String &p_string) { @@ -2323,11 +2316,11 @@ String VisualScriptEngineSingleton::get_singleton() { class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance { public: - Object *singleton; + Object *singleton = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = singleton; return 0; } @@ -2417,7 +2410,7 @@ PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const } String VisualScriptSceneNode::get_caption() const { - return "Get Scene Node"; + return RTR("Get Scene Node"); } void VisualScriptSceneNode::set_node_path(const NodePath &p_path) { @@ -2432,13 +2425,13 @@ NodePath VisualScriptSceneNode::get_node_path() { class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance { public: - VisualScriptSceneNode *node; - VisualScriptInstance *instance; + VisualScriptSceneNode *node = nullptr; + VisualScriptInstance *instance = nullptr; NodePath path; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); if (!node) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2495,7 +2488,7 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGuess *p_inputs, int p_output) const { VisualScriptSceneNode::TypeGuess tg; tg.type = Variant::OBJECT; - tg.gdclass = "Node"; + tg.gdclass = SNAME("Node"); #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); @@ -2608,17 +2601,17 @@ PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const } String VisualScriptSceneTree::get_caption() const { - return "Get Scene Tree"; + return RTR("Get Scene Tree"); } class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance { public: - VisualScriptSceneTree *node; - VisualScriptInstance *instance; + VisualScriptSceneTree *node = nullptr; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); if (!node) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2649,7 +2642,7 @@ VisualScriptNodeInstance *VisualScriptSceneTree::instantiate(VisualScriptInstanc VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGuess *p_inputs, int p_output) const { TypeGuess tg; tg.type = Variant::OBJECT; - tg.gdclass = "SceneTree"; + tg.gdclass = SNAME("SceneTree"); return tg; } @@ -2695,7 +2688,7 @@ PropertyInfo VisualScriptResourcePath::get_output_value_port_info(int p_idx) con } String VisualScriptResourcePath::get_caption() const { - return "Resource Path"; + return RTR("Resource Path"); } void VisualScriptResourcePath::set_resource_path(const String &p_path) { @@ -2712,9 +2705,9 @@ class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance { public: String path; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = path; return 0; } @@ -2766,27 +2759,27 @@ PropertyInfo VisualScriptSelf::get_input_value_port_info(int p_idx) const { } PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const { - String type_name; + StringName type_name; if (get_visual_script().is_valid()) { type_name = get_visual_script()->get_instance_base_type(); } else { - type_name = "instance"; + type_name = SNAME("instance"); } return PropertyInfo(Variant::OBJECT, type_name); } String VisualScriptSelf::get_caption() const { - return "Get Self"; + return RTR("Get Self"); } class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = instance->get_owner_ptr(); return 0; } @@ -2801,7 +2794,7 @@ VisualScriptNodeInstance *VisualScriptSelf::instantiate(VisualScriptInstance *p_ VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess *p_inputs, int p_output) const { VisualScriptSceneNode::TypeGuess tg; tg.type = Variant::OBJECT; - tg.gdclass = "Object"; + tg.gdclass = SNAME("Object"); Ref<Script> script = get_visual_script(); if (!script.is_valid()) { @@ -2947,7 +2940,7 @@ String VisualScriptCustomNode::get_caption() const { if (GDVIRTUAL_CALL(_get_caption, ret)) { return ret; } - return "CustomNode"; + return RTR("CustomNode"); } String VisualScriptCustomNode::get_text() const { @@ -2968,14 +2961,14 @@ String VisualScriptCustomNode::get_category() const { class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; - VisualScriptCustomNode *node; - int in_count; - int out_count; - int work_mem_size; - - virtual int get_working_memory_size() const { return work_mem_size; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + VisualScriptInstance *instance = nullptr; + VisualScriptCustomNode *node = nullptr; + int in_count = 0; + int out_count = 0; + int work_mem_size = 0; + + virtual int get_working_memory_size() const override { return work_mem_size; } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (GDVIRTUAL_IS_OVERRIDDEN_PTR(node, _step)) { Array in_values; Array out_values; @@ -3141,7 +3134,7 @@ PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const { } String VisualScriptSubCall::get_caption() const { - return "SubCall"; + return RTR("SubCall"); } String VisualScriptSubCall::get_text() const { @@ -3164,20 +3157,20 @@ String VisualScriptSubCall::get_category() const { class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; - VisualScriptSubCall *subcall; - int input_args; - bool valid; + VisualScriptInstance *instance = nullptr; + VisualScriptSubCall *subcall = nullptr; + int input_args = 0; + bool valid = false; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Node requires a script with a _subcall(<args>) method to work."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return 0; } - *p_outputs[0] = subcall->call(VisualScriptLanguage::singleton->_subcall, p_inputs, input_args, r_error); + *p_outputs[0] = subcall->callp(VisualScriptLanguage::singleton->_subcall, p_inputs, input_args, r_error); return 0; } }; @@ -3284,11 +3277,11 @@ String VisualScriptComment::get_category() const { class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { return 0; } }; @@ -3352,7 +3345,7 @@ PropertyInfo VisualScriptConstructor::get_output_value_port_info(int p_idx) cons } String VisualScriptConstructor::get_caption() const { - return "Construct " + Variant::get_type_name(type); + return vformat(RTR("Construct %s"), Variant::get_type_name(type)); } String VisualScriptConstructor::get_category() const { @@ -3383,13 +3376,13 @@ Dictionary VisualScriptConstructor::get_constructor() const { class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; Variant::Type type; - int argcount; + int argcount = 0; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Callable::CallError ce; Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce); if (ce.error != Callable::CallError::CALL_OK) { @@ -3469,7 +3462,7 @@ PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const { } String VisualScriptLocalVar::get_caption() const { - return "Get Local Var"; + return RTR("Get Local Var"); } String VisualScriptLocalVar::get_category() const { @@ -3500,11 +3493,11 @@ Variant::Type VisualScriptLocalVar::get_var_type() const { class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; StringName name; - virtual int get_working_memory_size() const { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int get_working_memory_size() const override { return 1; } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = *p_working_mem; return 0; } @@ -3572,7 +3565,7 @@ PropertyInfo VisualScriptLocalVarSet::get_output_value_port_info(int p_idx) cons } String VisualScriptLocalVarSet::get_caption() const { - return "Set Local Var"; + return RTR("Set Local Var"); } String VisualScriptLocalVarSet::get_text() const { @@ -3607,11 +3600,11 @@ Variant::Type VisualScriptLocalVarSet::get_var_type() const { class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; StringName name; - virtual int get_working_memory_size() const { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int get_working_memory_size() const override { return 1; } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_working_mem = *p_inputs[0]; *p_outputs[0] = *p_working_mem; return 0; @@ -3696,7 +3689,7 @@ PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) cons } String VisualScriptInputAction::get_caption() const { - return "Action " + name; + return vformat(RTR("Action %s"), name); } String VisualScriptInputAction::get_category() const { @@ -3731,11 +3724,11 @@ VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const { class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; StringName action; VisualScriptInputAction::Mode mode; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (mode) { case VisualScriptInputAction::MODE_PRESSED: { *p_outputs[0] = Input::get_singleton()->is_action_pressed(action); @@ -3850,7 +3843,7 @@ PropertyInfo VisualScriptDeconstruct::get_output_value_port_info(int p_idx) cons } String VisualScriptDeconstruct::get_caption() const { - return "Deconstruct " + Variant::get_type_name(type); + return vformat(RTR("Deconstruct %s"), Variant::get_type_name(type)); } String VisualScriptDeconstruct::get_category() const { @@ -3909,12 +3902,12 @@ Array VisualScriptDeconstruct::_get_elem_cache() const { class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance { public: - VisualScriptInstance *instance; + VisualScriptInstance *instance = nullptr; Vector<StringName> outputs; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Variant in = *p_inputs[0]; for (int i = 0; i < outputs.size(); i++) { diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 78881f0a53..18573f8682 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index c5d17e5a11..96e91a0baf 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -68,7 +68,7 @@ PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const { } String VisualScriptYield::get_caption() const { - return yield_mode == YIELD_RETURN ? "Yield" : "Wait"; + return yield_mode == YIELD_RETURN ? RTR("Yield") : RTR("Wait"); } String VisualScriptYield::get_text() const { @@ -77,13 +77,13 @@ String VisualScriptYield::get_text() const { return ""; break; case YIELD_FRAME: - return "Next Frame"; + return RTR("Next Frame"); break; case YIELD_PHYSICS_FRAME: - return "Next Physics Frame"; + return RTR("Next Physics Frame"); break; case YIELD_WAIT: - return rtos(wait_time) + " sec(s)"; + return vformat(RTR("%s sec(s)"), rtos(wait_time)); break; } @@ -93,13 +93,13 @@ String VisualScriptYield::get_text() const { class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance { public: VisualScriptYield::YieldMode mode; - double wait_time; + double wait_time = 0.0; - virtual int get_working_memory_size() const { return 1; } //yield needs at least 1 + virtual int get_working_memory_size() const override { return 1; } //yield needs at least 1 //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_RESUME_YIELD) { return 0; //resuming yield } else { @@ -335,13 +335,18 @@ PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) cons } String VisualScriptYieldSignal::get_caption() const { - static const char *cname[3] = { - "WaitSignal", - "WaitNodeSignal", - "WaitInstanceSigna;", - }; - - return cname[call_mode]; + switch (call_mode) { + case CALL_MODE_SELF: { + return RTR("WaitSignal"); + } break; + case CALL_MODE_NODE_PATH: { + return RTR("WaitNodeSignal"); + } break; + case CALL_MODE_INSTANCE: { + return RTR("WaitInstanceSignal"); + } break; + } + return String(); } String VisualScriptYieldSignal::get_text() const { @@ -495,17 +500,17 @@ class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance { public: VisualScriptYieldSignal::CallMode call_mode; NodePath node_path; - int output_args; + int output_args = 0; StringName signal; - VisualScriptYieldSignal *node; - VisualScriptInstance *instance; + VisualScriptYieldSignal *node = nullptr; + VisualScriptInstance *instance = nullptr; - virtual int get_working_memory_size() const { return 1; } + virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_RESUME_YIELD) { return 0; //resuming yield } else { diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index 6005ff30b0..a7bf4e8a78 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 06ed021a5a..b645a48c88 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -110,7 +110,7 @@ int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p if (info.channels > 1) { for (int frame = 0; frame < frames; frame++) { p_buffer[frame].l = pcm[0][frame]; - p_buffer[frame].r = pcm[0][frame]; + p_buffer[frame].r = pcm[1][frame]; } } else { for (int frame = 0; frame < frames; frame++) { @@ -166,7 +166,7 @@ void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) { active = true; seek(p_from_pos); loops = 0; - _begin_resample(); + begin_resample(); } void AudioStreamPlaybackOGGVorbis::stop() { @@ -350,7 +350,6 @@ void AudioStreamOGGVorbis::maybe_update_info() { vorbis_info_init(&info); vorbis_comment_init(&comment); - int packet_count = 0; Ref<OGGPacketSequencePlayback> packet_sequence_playback = packet_sequence->instance_playback(); for (int i = 0; i < 3; i++) { @@ -369,8 +368,6 @@ void AudioStreamOGGVorbis::maybe_update_info() { err = vorbis_synthesis_headerin(&info, &comment, packet); ERR_FAIL_COND_MSG(err != 0, "Error parsing header packet " + itos(i) + ": " + itos(err)); - - packet_count++; } packet_sequence->set_sampling_rate(info.rate); diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index 59a1318a6b..b09ef9ff5d 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml index 4cd278fe83..2f210a6cb4 100644 --- a/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamOGGVorbis" inherits="AudioStream" version="4.0"> +<class name="AudioStreamOGGVorbis" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml b/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml index 05c70d88da..68aa46147f 100644 --- a/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamPlaybackOGGVorbis" inherits="AudioStreamPlaybackResampled" version="4.0"> +<class name="AudioStreamPlaybackOGGVorbis" inherits="AudioStreamPlaybackResampled" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp index de3f41afdd..7f81f88cdb 100644 --- a/modules/vorbis/register_types.cpp +++ b/modules/vorbis/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,7 +33,11 @@ #include "audio_stream_ogg_vorbis.h" #include "resource_importer_ogg_vorbis.h" -void register_vorbis_types() { +void initialize_vorbis_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { Ref<ResourceImporterOGGVorbis> ogg_vorbis_importer; @@ -45,4 +49,8 @@ void register_vorbis_types() { GDREGISTER_CLASS(AudioStreamPlaybackOGGVorbis); } -void unregister_vorbis_types() {} +void uninitialize_vorbis_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/vorbis/register_types.h b/modules/vorbis/register_types.h index 1497e6f5e4..74c18b9c04 100644 --- a/modules/vorbis/register_types.h +++ b/modules/vorbis/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef VORBIS_REGISTER_TYPES_H #define VORBIS_REGISTER_TYPES_H -void register_vorbis_types(); -void unregister_vorbis_types(); +#include "modules/register_module_types.h" + +void initialize_vorbis_module(ModuleInitializationLevel p_level); +void uninitialize_vorbis_module(ModuleInitializationLevel p_level); #endif // VORBIS_REGISTER_TYPES_H diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index be9f880103..03e145216a 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -78,9 +78,8 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); uint64_t len = f->get_length(); @@ -90,8 +89,6 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin f->get_buffer(w, len); - memdelete(f); - Ref<AudioStreamOGGVorbis> ogg_vorbis_stream; ogg_vorbis_stream.instantiate(); @@ -136,11 +133,11 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin // Have a page now. if (!initialized_stream) { - ogg_stream_init(&stream_state, ogg_page_serialno(&page)); - ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err)); + if (ogg_stream_init(&stream_state, ogg_page_serialno(&page))) { + ERR_FAIL_V_MSG(Error::ERR_OUT_OF_MEMORY, "Failed allocating memory for OGG Vorbis stream."); + } initialized_stream = true; } - ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err)); ogg_stream_pagein(&stream_state, &page); ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err)); int desync_iters = 0; @@ -160,10 +157,12 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin break; } if (packet_count == 0 && vorbis_synthesis_idheader(&packet) == 0) { - WARN_PRINT("Found a non-vorbis-header packet in a header position"); + print_verbose("Found a non-vorbis-header packet in a header position"); // Clearly this logical stream is not a vorbis stream, so destroy it and try again with the next page. - ogg_stream_destroy(&stream_state); - initialized_stream = false; + if (initialized_stream) { + ogg_stream_clear(&stream_state); + initialized_stream = false; + } break; } granule_pos = packet.granulepos; @@ -178,6 +177,14 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin ogg_packet_sequence->push_page(granule_pos, packet_data); } } + if (initialized_stream) { + ogg_stream_clear(&stream_state); + } + ogg_sync_clear(&sync_state); + + if (ogg_packet_sequence->get_packet_granule_positions().is_empty()) { + ERR_FAIL_V_MSG(Error::ERR_FILE_CORRUPT, "OGG Vorbis decoding failed. Check that your data is a valid OGG Vorbis audio stream."); + } ogg_vorbis_stream->set_packet_sequence(ogg_packet_sequence); ogg_vorbis_stream->set_loop(loop); diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h index 8565e0deb8..07291803a1 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.h +++ b/modules/vorbis/resource_importer_ogg_vorbis.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 5bebad2b53..0e41f6c973 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -211,7 +211,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { return img; } -Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderWEBP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -221,8 +221,6 @@ Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_forc f->get_buffer(&w[0], src_image_len); - f->close(); - Error err = webp_load_image_from_buffer(p_image.ptr(), w, src_image_len); return err; diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h index 9ea3056a19..1acd1459a0 100644 --- a/modules/webp/image_loader_webp.h +++ b/modules/webp/image_loader_webp.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,7 +35,7 @@ class ImageLoaderWEBP : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderWEBP(); }; diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp index ea9af72418..148e325498 100644 --- a/modules/webp/register_types.cpp +++ b/modules/webp/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -34,11 +34,19 @@ static ImageLoaderWEBP *image_loader_webp = nullptr; -void register_webp_types() { +void initialize_webp_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + image_loader_webp = memnew(ImageLoaderWEBP); ImageLoader::add_image_format_loader(image_loader_webp); } -void unregister_webp_types() { +void uninitialize_webp_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + memdelete(image_loader_webp); } diff --git a/modules/webp/register_types.h b/modules/webp/register_types.h index 59d6894bf6..6e37dcfb61 100644 --- a/modules/webp/register_types.h +++ b/modules/webp/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef WEBP_REGISTER_TYPES_H #define WEBP_REGISTER_TYPES_H -void register_webp_types(); -void unregister_webp_types(); +#include "modules/register_module_types.h" + +void initialize_webp_module(ModuleInitializationLevel p_level); +void uninitialize_webp_module(ModuleInitializationLevel p_level); #endif // WEBP_REGISTER_TYPES_H diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml index cf5735bab5..a9ba8a23de 100644 --- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml +++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCDataChannel" inherits="PacketPeer" version="4.0"> +<class name="WebRTCDataChannel" inherits="PacketPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml index 746fabd6e5..f937fba9d6 100644 --- a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml +++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" version="4.0"> +<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index a8360a4d45..3996a002ed 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> +<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A simple interface to create a peer-to-peer mesh network composed of [WebRTCPeerConnection] that is compatible with the [MultiplayerAPI]. </brief_description> @@ -32,7 +32,7 @@ <return type="Dictionary" /> <argument index="0" name="peer_id" type="int" /> <description> - Return a dictionary representation of the peer with given [code]peer_id[/code] with three keys. [code]connection[/code] containing the [WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three [WebRTCDataChannel], and [code]connected[/code] a boolean representing if the peer connection is currently connected (all three channels are open). + Returns a dictionary representation of the peer with given [code]peer_id[/code] with three keys. [code]connection[/code] containing the [WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three [WebRTCDataChannel], and [code]connected[/code] a boolean representing if the peer connection is currently connected (all three channels are open). </description> </method> <method name="get_peers"> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index 618fe14137..b4d97077e3 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="RefCounted" version="4.0"> +<class name="WebRTCPeerConnection" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Interface to a WebRTC peer connection. </brief_description> @@ -33,8 +33,7 @@ <method name="create_data_channel"> <return type="WebRTCDataChannel" /> <argument index="0" name="label" type="String" /> - <argument index="1" name="options" type="Dictionary" default="{ -}" /> + <argument index="1" name="options" type="Dictionary" default="{}" /> <description> Returns a new [WebRTCDataChannel] (or [code]null[/code] on failure) with given [code]label[/code] and optionally configured via the [code]options[/code] dictionary. This method can only be called when the connection is in state [constant STATE_NEW]. There are two ways to create a working data channel: either call [method create_data_channel] on only one of the peer and listen to [signal data_channel_received] on the other, or call [method create_data_channel] on both peers, with the same values, and the [code]negotiated[/code] option set to [code]true[/code]. @@ -70,8 +69,7 @@ </method> <method name="initialize"> <return type="int" enum="Error" /> - <argument index="0" name="configuration" type="Dictionary" default="{ -}" /> + <argument index="0" name="configuration" type="Dictionary" default="{}" /> <description> Re-initialize this peer connection, closing any previously active connection, and going back to state [constant STATE_NEW]. A dictionary of [code]options[/code] can be passed to configure the peer connection. Valid [code]options[/code] are: @@ -119,7 +117,7 @@ </methods> <signals> <signal name="data_channel_received"> - <argument index="0" name="channel" type="Object" /> + <argument index="0" name="channel" type="WebRTCDataChannel" /> <description> Emitted when a new in-band channel is received, i.e. when the channel was created with [code]negotiated: false[/code] (default). The object will be an instance of [WebRTCDataChannel]. You must keep a reference of it or it will be closed automatically. See [method create_data_channel]. diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml index d296fcd6e7..e88acdc845 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" version="4.0"> +<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js index a0a6c21be3..e57e4299e0 100644 --- a/modules/webrtc/library_godot_webrtc.js +++ b/modules/webrtc/library_godot_webrtc.js @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp index 8110e4a048..09cd538b96 100644 --- a/modules/webrtc/register_types.cpp +++ b/modules/webrtc/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,20 +37,30 @@ #include "webrtc_data_channel_extension.h" #include "webrtc_peer_connection_extension.h" -void register_webrtc_types() { -#define _SET_HINT(NAME, _VAL_, _MAX_) \ - GLOBAL_DEF(NAME, _VAL_); \ +void initialize_webrtc_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + +#define SET_HINT(NAME, _VAL_, _MAX_) \ + GLOBAL_DEF(NAME, _VAL_); \ ProjectSettings::get_singleton()->set_custom_property_info(NAME, PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater")); - _SET_HINT(WRTC_IN_BUF, 64, 4096); + SET_HINT(WRTC_IN_BUF, 64, 4096); ClassDB::register_custom_instance_class<WebRTCPeerConnection>(); GDREGISTER_CLASS(WebRTCPeerConnectionExtension); - GDREGISTER_VIRTUAL_CLASS(WebRTCDataChannel); + GDREGISTER_ABSTRACT_CLASS(WebRTCDataChannel); GDREGISTER_CLASS(WebRTCDataChannelExtension); GDREGISTER_CLASS(WebRTCMultiplayerPeer); + +#undef SET_HINT } -void unregister_webrtc_types() {} +void uninitialize_webrtc_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h index 710ee88a28..17171d0e0b 100644 --- a/modules/webrtc/register_types.h +++ b/modules/webrtc/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef WEBRTC_REGISTER_TYPES_H #define WEBRTC_REGISTER_TYPES_H -void register_webrtc_types(); -void unregister_webrtc_types(); +#include "modules/register_module_types.h" + +void initialize_webrtc_module(ModuleInitializationLevel p_level); +void uninitialize_webrtc_module(ModuleInitializationLevel p_level); #endif // WEBRTC_REGISTER_TYPES_H diff --git a/modules/webrtc/webrtc_data_channel.cpp b/modules/webrtc/webrtc_data_channel.cpp index ca520a733d..b4af4b8415 100644 --- a/modules/webrtc/webrtc_data_channel.cpp +++ b/modules/webrtc/webrtc_data_channel.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_data_channel.h b/modules/webrtc/webrtc_data_channel.h index 809d35c6e3..eac8f85a84 100644 --- a/modules/webrtc/webrtc_data_channel.h +++ b/modules/webrtc/webrtc_data_channel.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_data_channel_extension.cpp b/modules/webrtc/webrtc_data_channel_extension.cpp index ae346f6d8e..b7ea8d22bb 100644 --- a/modules/webrtc/webrtc_data_channel_extension.cpp +++ b/modules/webrtc/webrtc_data_channel_extension.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_data_channel_extension.h b/modules/webrtc/webrtc_data_channel_extension.h index eec96b4c62..83bb627815 100644 --- a/modules/webrtc/webrtc_data_channel_extension.h +++ b/modules/webrtc/webrtc_data_channel_extension.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_data_channel_js.cpp b/modules/webrtc/webrtc_data_channel_js.cpp index 31d6a0568c..0fb074b0c2 100644 --- a/modules/webrtc/webrtc_data_channel_js.cpp +++ b/modules/webrtc/webrtc_data_channel_js.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,6 +31,7 @@ #ifdef JAVASCRIPT_ENABLED #include "webrtc_data_channel_js.h" + #include "emscripten.h" extern "C" { @@ -104,8 +105,9 @@ int WebRTCDataChannelJS::get_available_packet_count() const { Error WebRTCDataChannelJS::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V(get_ready_state() != STATE_OPEN, ERR_UNCONFIGURED); - if (queue_count == 0) + if (queue_count == 0) { return ERR_UNAVAILABLE; + } uint32_t to_read = 0; uint32_t left = 0; diff --git a/modules/webrtc/webrtc_data_channel_js.h b/modules/webrtc/webrtc_data_channel_js.h index 5cd6a32ed9..d059ec31ed 100644 --- a/modules/webrtc/webrtc_data_channel_js.h +++ b/modules/webrtc/webrtc_data_channel_js.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 20fe63bf7d..0bc42b104c 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -353,10 +353,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si ch += CH_RESERVED_MAX - 1; } - Map<int, Ref<ConnectedPeer>>::Element *E = nullptr; - if (target_peer > 0) { - E = peer_map.find(target_peer); + Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(target_peer); ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + "."); ERR_FAIL_COND_V_MSG(E->value()->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); @@ -372,7 +370,7 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si continue; } - ERR_CONTINUE_MSG(F.value->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); + ERR_CONTINUE_MSG(F.value->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, F.value->channels.size())); ERR_CONTINUE(F.value->channels[ch].is_null()); F.value->channels[ch]->put_packet(p_buffer, p_buffer_size); } diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 4a7e9ad7c8..6675c67867 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp index ad28aa76c7..7fdf26d3cd 100644 --- a/modules/webrtc/webrtc_peer_connection.cpp +++ b/modules/webrtc/webrtc_peer_connection.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -69,7 +69,7 @@ void WebRTCPeerConnection::_bind_methods() { ADD_SIGNAL(MethodInfo("session_description_created", PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::STRING, "sdp"))); ADD_SIGNAL(MethodInfo("ice_candidate_created", PropertyInfo(Variant::STRING, "media"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::STRING, "name"))); - ADD_SIGNAL(MethodInfo("data_channel_received", PropertyInfo(Variant::OBJECT, "channel"))); + ADD_SIGNAL(MethodInfo("data_channel_received", PropertyInfo(Variant::OBJECT, "channel", PROPERTY_HINT_RESOURCE_TYPE, "WebRTCDataChannel"))); BIND_ENUM_CONSTANT(STATE_NEW); BIND_ENUM_CONSTANT(STATE_CONNECTING); diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h index e2ef3e55ad..8c324d0942 100644 --- a/modules/webrtc/webrtc_peer_connection.h +++ b/modules/webrtc/webrtc_peer_connection.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_peer_connection_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp index 33288e66d6..3bc7de217e 100644 --- a/modules/webrtc/webrtc_peer_connection_extension.cpp +++ b/modules/webrtc/webrtc_peer_connection_extension.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_peer_connection_extension.h b/modules/webrtc/webrtc_peer_connection_extension.h index b3c2039fc1..82e32b5602 100644 --- a/modules/webrtc/webrtc_peer_connection_extension.h +++ b/modules/webrtc/webrtc_peer_connection_extension.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp index ed3459d5f8..90e19fe4f1 100644 --- a/modules/webrtc/webrtc_peer_connection_js.cpp +++ b/modules/webrtc/webrtc_peer_connection_js.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h index d2beccaf03..8fa5ea7779 100644 --- a/modules/webrtc/webrtc_peer_connection_js.h +++ b/modules/webrtc/webrtc_peer_connection_js.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -63,16 +63,16 @@ private: static void _on_error(void *p_obj); public: - virtual ConnectionState get_connection_state() const; + virtual ConnectionState get_connection_state() const override; - virtual Error initialize(Dictionary configuration = Dictionary()); - virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary()); - virtual Error create_offer(); - virtual Error set_remote_description(String type, String sdp); - virtual Error set_local_description(String type, String sdp); - virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName); - virtual Error poll(); - virtual void close(); + virtual Error initialize(Dictionary configuration = Dictionary()) override; + virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary()) override; + virtual Error create_offer() override; + virtual Error set_remote_description(String type, String sdp) override; + virtual Error set_local_description(String type, String sdp) override; + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override; + virtual Error poll() override; + virtual void close() override; WebRTCPeerConnectionJS(); ~WebRTCPeerConnectionJS(); diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub index 63c941c4a8..dc0661995f 100644 --- a/modules/websocket/SCsub +++ b/modules/websocket/SCsub @@ -41,6 +41,8 @@ elif env["builtin_wslay"]: module_obj = [] env_ws.add_source_files(module_obj, "*.cpp") +if env["tools"]: + env_ws.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml index 4b515c12a1..ad2acf8a21 100644 --- a/modules/websocket/doc_classes/WebSocketClient.xml +++ b/modules/websocket/doc_classes/WebSocketClient.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" version="4.0"> +<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A WebSocket client implementation. </brief_description> @@ -39,13 +39,13 @@ <method name="get_connected_host" qualifiers="const"> <return type="String" /> <description> - Return the IP address of the currently connected host. + Returns the IP address of the currently connected host. </description> </method> <method name="get_connected_port" qualifiers="const"> <return type="int" /> <description> - Return the IP port of the currently connected host. + Returns the IP port of the currently connected host. </description> </method> </methods> diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index 8d8ab220e2..4a617f4c82 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="MultiplayerPeer" version="4.0"> +<class name="WebSocketMultiplayerPeer" inherits="MultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Base class for WebSocket server and client. </brief_description> diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml index 2f455c32fd..6466654517 100644 --- a/modules/websocket/doc_classes/WebSocketPeer.xml +++ b/modules/websocket/doc_classes/WebSocketPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketPeer" inherits="PacketPeer" version="4.0"> +<class name="WebSocketPeer" inherits="PacketPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A class representing a specific WebSocket connection. </brief_description> diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index f901b089ea..46b0274de3 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" version="4.0"> +<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> A WebSocket server implementation. </brief_description> @@ -60,6 +60,13 @@ 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(id)[/code] to communicate with the peer with given [code]id[/code] (e.g. [code]get_peer(id).get_available_packet_count[/code]). </description> </method> + <method name="set_extra_headers"> + <return type="void" /> + <argument index="0" name="headers" type="PackedStringArray" default="PackedStringArray()" /> + <description> + Sets additional headers to be sent to clients during the HTTP handshake. + </description> + </method> <method name="stop"> <return type="void" /> <description> diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor/editor_debugger_server_websocket.cpp index 78a5fa50d8..0443147d98 100644 --- a/modules/websocket/editor_debugger_server_websocket.cpp +++ b/modules/websocket/editor/editor_debugger_server_websocket.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -30,11 +30,13 @@ #include "editor_debugger_server_websocket.h" +#ifdef TOOLS_ENABLED + +#include "../remote_debugger_peer_websocket.h" #include "core/config/project_settings.h" #include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "modules/websocket/remote_debugger_peer_websocket.h" void EditorDebuggerServerWebSocket::_peer_connected(int p_id, String _protocol) { pending_peers.push_back(p_id); @@ -129,3 +131,5 @@ EditorDebuggerServer *EditorDebuggerServerWebSocket::create(const String &p_prot ERR_FAIL_COND_V(p_protocol != "ws://", nullptr); return memnew(EditorDebuggerServerWebSocket); } + +#endif // TOOLS_ENABLED diff --git a/modules/websocket/editor_debugger_server_websocket.h b/modules/websocket/editor/editor_debugger_server_websocket.h index 1e5ea66146..7c0705302d 100644 --- a/modules/websocket/editor_debugger_server_websocket.h +++ b/modules/websocket/editor/editor_debugger_server_websocket.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,8 +31,10 @@ #ifndef EDITOR_DEBUGGER_SERVER_WEBSOCKET_H #define EDITOR_DEBUGGER_SERVER_WEBSOCKET_H +#ifdef TOOLS_ENABLED + +#include "../websocket_server.h" #include "editor/debugger/editor_debugger_server.h" -#include "modules/websocket/websocket_server.h" class EditorDebuggerServerWebSocket : public EditorDebuggerServer { GDCLASS(EditorDebuggerServerWebSocket, EditorDebuggerServer); @@ -60,4 +62,6 @@ public: ~EditorDebuggerServerWebSocket(); }; +#endif // TOOLS_ENABLED + #endif // EDITOR_DEBUGGER_SERVER_WEBSOCKET_H diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 5cd94e978f..e051a3b564 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,6 +31,7 @@ #ifdef JAVASCRIPT_ENABLED #include "emws_client.h" + #include "core/config/project_settings.h" #include "core/io/ip.h" #include "emscripten.h" @@ -45,8 +46,9 @@ void EMWSClient::_esws_on_message(void *obj, const uint8_t *p_data, int p_data_s EMWSClient *client = static_cast<EMWSClient *>(obj); Error err = static_cast<EMWSPeer *>(*client->get_peer(1))->read_msg(p_data, p_data_size, p_is_string == 1); - if (err == OK) + if (err == OK) { client->_on_peer_packet(); + } } void EMWSClient::_esws_on_error(void *obj) { @@ -71,8 +73,9 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, String proto_string; for (int i = 0; i < p_protocols.size(); i++) { - if (i != 0) + if (i != 0) { proto_string += ","; + } proto_string += p_protocols[i]; } @@ -109,8 +112,9 @@ Ref<WebSocketPeer> EMWSClient::get_peer(int p_peer_id) const { MultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const { if (_peer->is_connected_to_host()) { - if (_is_connecting) + if (_is_connecting) { return CONNECTION_CONNECTING; + } return CONNECTION_CONNECTED; } diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h index 3b0b8395b9..ca327a56fa 100644 --- a/modules/websocket/emws_client.h +++ b/modules/websocket/emws_client.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -53,15 +53,15 @@ private: static void _esws_on_close(void *obj, int code, const char *reason, int was_clean); public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - 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 = ""); - IPAddress get_connected_host() const; - uint16_t get_connected_port() const; - virtual ConnectionStatus get_connection_status() const; - int get_max_packet_size() const; - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + 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>()) override; + Ref<WebSocketPeer> get_peer(int p_peer_id) const override; + void disconnect_from_host(int p_code = 1000, String p_reason = "") override; + IPAddress get_connected_host() const override; + uint16_t get_connected_port() const override; + virtual ConnectionStatus get_connection_status() const override; + int get_max_packet_size() const override; + virtual void poll() override; EMWSClient(); ~EMWSClient(); }; diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index 035d036b90..86169f88e9 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,6 +31,7 @@ #ifdef JAVASCRIPT_ENABLED #include "emws_peer.h" + #include "core/io/ip.h" void EMWSPeer::set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size) { @@ -66,8 +67,9 @@ Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { } Error EMWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - if (_in_buffer.packets_left() == 0) + if (_in_buffer.packets_left() == 0) { return ERR_UNAVAILABLE; + } int read = 0; Error err = _in_buffer.read_packet(_packet_buffer.ptrw(), _packet_buffer.size(), &_is_string, read); @@ -109,7 +111,7 @@ void EMWSPeer::close(int p_code, String p_reason) { IPAddress EMWSPeer::get_connected_host() const { ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export."); -}; +} uint16_t EMWSPeer::get_connected_port() const { ERR_FAIL_V_MSG(0, "Not supported in HTML5 export."); diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h index 6e93ea31a2..6bb4552c37 100644 --- a/modules/websocket/emws_peer.h +++ b/modules/websocket/emws_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -68,21 +68,21 @@ private: public: Error read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string); void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size); - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - virtual int get_max_packet_size() const { return _packet_buffer.size(); }; - virtual int get_current_outbound_buffered_amount() const; + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_max_packet_size() const override { return _packet_buffer.size(); }; + virtual int get_current_outbound_buffered_amount() const override; - virtual void close(int p_code = 1000, String p_reason = ""); - virtual bool is_connected_to_host() const; - virtual IPAddress get_connected_host() const; - virtual uint16_t get_connected_port() const; + virtual void close(int p_code = 1000, String p_reason = "") override; + virtual bool is_connected_to_host() const override; + virtual IPAddress get_connected_host() const override; + virtual uint16_t get_connected_port() const override; - virtual WriteMode get_write_mode() const; - virtual void set_write_mode(WriteMode p_mode); - virtual bool was_string_packet() const; - virtual void set_no_delay(bool p_enabled); + virtual WriteMode get_write_mode() const override; + virtual void set_write_mode(WriteMode p_mode) override; + virtual bool was_string_packet() const override; + virtual void set_no_delay(bool p_enabled) override; EMWSPeer(); ~EMWSPeer(); diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp index 4a4f09a943..2033098cad 100644 --- a/modules/websocket/emws_server.cpp +++ b/modules/websocket/emws_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -33,6 +33,9 @@ #include "emws_server.h" #include "core/os/os.h" +void EMWSServer::set_extra_headers(const Vector<String> &p_headers) { +} + Error EMWSServer::listen(int p_port, Vector<String> p_protocols, bool gd_mp_api) { return FAILED; } diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h index d36e3a3557..ae31d9dbb0 100644 --- a/modules/websocket/emws_server.h +++ b/modules/websocket/emws_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -41,17 +41,18 @@ class EMWSServer : public WebSocketServer { GDCIIMPL(EMWSServer, WebSocketServer); public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false); - void stop(); - bool is_listening() const; - bool has_peer(int p_id) const; - Ref<WebSocketPeer> get_peer(int p_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; - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + void set_extra_headers(const Vector<String> &p_headers) override; + Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override; + void stop() override; + bool is_listening() const override; + bool has_peer(int p_id) const override; + Ref<WebSocketPeer> get_peer(int p_id) const override; + IPAddress get_peer_address(int p_peer_id) const override; + int get_peer_port(int p_peer_id) const override; + void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override; + int get_max_packet_size() const override; + virtual void poll() override; virtual Vector<String> get_protocols() const; EMWSServer(); diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js index dd2fd1e94f..57f1f10b02 100644 --- a/modules/websocket/library_godot_websocket.js +++ b/modules/websocket/library_godot_websocket.js @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -135,7 +135,7 @@ const GodotWebSocket = { if (!ref) { return; } - GodotWebSocket.close(p_id, 1001, ''); + GodotWebSocket.close(p_id, 3001, 'destroyed'); IDHandler.remove(p_id); ref.onopen = null; ref.onmessage = null; diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h index e99a379767..7b4a164576 100644 --- a/modules/websocket/packet_buffer.h +++ b/modules/websocket/packet_buffer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp index 7c742b1b89..f562de111f 100644 --- a/modules/websocket/register_types.cpp +++ b/modules/websocket/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -29,8 +29,10 @@ /*************************************************************************/ #include "register_types.h" + #include "core/config/project_settings.h" #include "core/error/error_macros.h" + #ifdef JAVASCRIPT_ENABLED #include "emscripten.h" #include "emws_client.h" @@ -40,10 +42,11 @@ #include "wsl_client.h" #include "wsl_server.h" #endif + #ifdef TOOLS_ENABLED #include "editor/debugger/editor_debugger_server.h" +#include "editor/editor_debugger_server_websocket.h" #include "editor/editor_node.h" -#include "editor_debugger_server_websocket.h" #endif #ifdef TOOLS_ENABLED @@ -52,25 +55,33 @@ static void _editor_init_callback() { } #endif -void register_websocket_types() { +void initialize_websocket_module(ModuleInitializationLevel p_level) { + if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { #ifdef JAVASCRIPT_ENABLED - EMWSPeer::make_default(); - EMWSClient::make_default(); - EMWSServer::make_default(); + EMWSPeer::make_default(); + EMWSClient::make_default(); + EMWSServer::make_default(); #else - WSLPeer::make_default(); - WSLClient::make_default(); - WSLServer::make_default(); + WSLPeer::make_default(); + WSLClient::make_default(); + WSLServer::make_default(); #endif - GDREGISTER_VIRTUAL_CLASS(WebSocketMultiplayerPeer); - ClassDB::register_custom_instance_class<WebSocketServer>(); - ClassDB::register_custom_instance_class<WebSocketClient>(); - ClassDB::register_custom_instance_class<WebSocketPeer>(); + GDREGISTER_ABSTRACT_CLASS(WebSocketMultiplayerPeer); + ClassDB::register_custom_instance_class<WebSocketServer>(); + ClassDB::register_custom_instance_class<WebSocketClient>(); + ClassDB::register_custom_instance_class<WebSocketPeer>(); + } #ifdef TOOLS_ENABLED - EditorNode::add_init_callback(&_editor_init_callback); + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + EditorNode::add_init_callback(&_editor_init_callback); + } #endif } -void unregister_websocket_types() {} +void uninitialize_websocket_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/websocket/register_types.h b/modules/websocket/register_types.h index 3884db67b7..dab42d6ed9 100644 --- a/modules/websocket/register_types.h +++ b/modules/websocket/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef WEBSOCKET_REGISTER_TYPES_H #define WEBSOCKET_REGISTER_TYPES_H -void register_websocket_types(); -void unregister_websocket_types(); +#include "modules/register_module_types.h" + +void initialize_websocket_module(ModuleInitializationLevel p_level); +void uninitialize_websocket_module(ModuleInitializationLevel p_level); #endif // WEBSOCKET_REGISTER_TYPES_H diff --git a/modules/websocket/remote_debugger_peer_websocket.cpp b/modules/websocket/remote_debugger_peer_websocket.cpp index c9591cc564..6319c3c664 100644 --- a/modules/websocket/remote_debugger_peer_websocket.cpp +++ b/modules/websocket/remote_debugger_peer_websocket.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h index 590d925dcc..3227065ded 100644 --- a/modules/websocket/remote_debugger_peer_websocket.h +++ b/modules/websocket/remote_debugger_peer_websocket.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,12 +31,13 @@ #ifndef REMOTE_DEBUGGER_PEER_WEBSOCKET_H #define REMOTE_DEBUGGER_PEER_WEBSOCKET_H +#include "core/debugger/remote_debugger_peer.h" + #ifdef JAVASCRIPT_ENABLED -#include "modules/websocket/emws_client.h" +#include "emws_client.h" #else -#include "modules/websocket/wsl_client.h" +#include "wsl_client.h" #endif -#include "core/debugger/remote_debugger_peer.h" class RemoteDebuggerPeerWebSocket : public RemoteDebuggerPeer { Ref<WebSocketClient> ws_client; @@ -50,14 +51,14 @@ public: static RemoteDebuggerPeer *create(const String &p_uri); Error connect_to_host(const String &p_uri); - bool is_peer_connected(); - int get_max_message_size() const; - bool has_message(); - Error put_message(const Array &p_arr); - Array get_message(); - void close(); - void poll(); - bool can_block() const; + bool is_peer_connected() override; + int get_max_message_size() const override; + bool has_message() override; + Error put_message(const Array &p_arr) override; + Array get_message() override; + void close() override; + void poll() override; + bool can_block() const override; RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer = Ref<WebSocketPeer>()); }; diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp index bf35c91c7f..2734b4b88f 100644 --- a/modules/websocket/websocket_client.cpp +++ b/modules/websocket/websocket_client.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h index c7f17f1ffb..d6c072ae16 100644 --- a/modules/websocket/websocket_client.h +++ b/modules/websocket/websocket_client.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h index 2ca60a3b61..a01ae65c56 100644 --- a/modules/websocket/websocket_macros.h +++ b/modules/websocket/websocket_macros.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index e54bfbca12..7a3bbf1c47 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 380edf67ed..43d9d59f38 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp index ee13040821..a0af9303b8 100644 --- a/modules/websocket/websocket_peer.cpp +++ b/modules/websocket/websocket_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h index 517b8600d6..13fef2424f 100644 --- a/modules/websocket/websocket_peer.h +++ b/modules/websocket/websocket_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp index e7f90fdeba..b7851b02c4 100644 --- a/modules/websocket/websocket_server.cpp +++ b/modules/websocket/websocket_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -42,6 +42,7 @@ WebSocketServer::~WebSocketServer() { void WebSocketServer::_bind_methods() { ClassDB::bind_method(D_METHOD("is_listening"), &WebSocketServer::is_listening); + ClassDB::bind_method(D_METHOD("set_extra_headers", "headers"), &WebSocketServer::set_extra_headers, DEFVAL(Vector<String>())); ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(Vector<String>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("stop"), &WebSocketServer::stop); ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer); @@ -67,7 +68,7 @@ void WebSocketServer::_bind_methods() { 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_PROPERTY(PropertyInfo(Variant::FLOAT, "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"))); diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h index c4d651471f..7bd80851f5 100644 --- a/modules/websocket/websocket_server.h +++ b/modules/websocket/websocket_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -51,6 +51,7 @@ protected: uint32_t handshake_timeout = 3000; public: + virtual void set_extra_headers(const Vector<String> &p_headers) = 0; virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0; virtual void stop() = 0; virtual bool is_listening() const = 0; diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index 26c0176ea4..894ba7766f 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -91,6 +91,7 @@ void WSLClient::_do_handshake() { data->id = 1; _peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size); _peer->set_no_delay(true); + _status = CONNECTION_CONNECTED; _on_connect(protocol); break; } @@ -103,13 +104,14 @@ bool WSLClient::_verify_headers(String &r_protocol) { String s = (char *)_resp_buf; Vector<String> psa = s.split("\r\n"); int len = psa.size(); - ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4."); + ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers. Got: " + itos(len) + ", expected >= 4."); Vector<String> req = psa[0].split(" ", false); - ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code."); + ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code. Got '" + psa[0] + "', expected 'HTTP/1.1 101'."); // Wrong protocol - ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1" || req[1] != "101", false, "Invalid protocol or status code."); + ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1", false, "Invalid protocol. Got: '" + req[0] + "', expected 'HTTP/1.1'."); + ERR_FAIL_COND_V_MSG(req[1] != "101", false, "Invalid status code. Got: '" + req[1] + "', expected '101'."); Map<String, String> headers; for (int i = 1; i < len; i++) { @@ -124,22 +126,24 @@ bool WSLClient::_verify_headers(String &r_protocol) { } } -#define _WSL_CHECK(NAME, VALUE) \ +#define WSL_CHECK(NAME, VALUE) \ ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \ "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'."); -#define _WSL_CHECK_NC(NAME, VALUE) \ +#define WSL_CHECK_NC(NAME, VALUE) \ ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME] != VALUE, false, \ "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'."); - _WSL_CHECK("connection", "upgrade"); - _WSL_CHECK("upgrade", "websocket"); - _WSL_CHECK_NC("sec-websocket-accept", WSLPeer::compute_key_response(_key)); -#undef _WSL_CHECK_NC -#undef _WSL_CHECK + WSL_CHECK("connection", "upgrade"); + WSL_CHECK("upgrade", "websocket"); + WSL_CHECK_NC("sec-websocket-accept", WSLPeer::compute_key_response(_key)); +#undef WSL_CHECK_NC +#undef WSL_CHECK if (_protocols.size() == 0) { // We didn't request a custom protocol - ERR_FAIL_COND_V(headers.has("sec-websocket-protocol"), false); + ERR_FAIL_COND_V_MSG(headers.has("sec-websocket-protocol"), false, "Received unrequested sub-protocol -> " + headers["sec-websocket-protocol"]); } else { - ERR_FAIL_COND_V(!headers.has("sec-websocket-protocol"), false); + // We requested at least one custom protocol but didn't receive one + ERR_FAIL_COND_V_MSG(!headers.has("sec-websocket-protocol"), false, "Requested sub-protocol(s) but received none."); + // Check received sub-protocol was one of those requested. r_protocol = headers["sec-websocket-protocol"]; bool valid = false; for (int i = 0; i < _protocols.size(); i++) { @@ -150,6 +154,7 @@ bool WSLClient::_verify_headers(String &r_protocol) { break; } if (!valid) { + ERR_FAIL_V_MSG(false, "Received unrequested sub-protocol -> " + r_protocol); return false; } } @@ -163,22 +168,24 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, _peer = Ref<WSLPeer>(memnew(WSLPeer)); if (p_host.is_valid_ip_address()) { - ip_candidates.clear(); - ip_candidates.push_back(IPAddress(p_host)); + _ip_candidates.push_back(IPAddress(p_host)); } else { - ip_candidates = IP::get_singleton()->resolve_hostname_addresses(p_host); - } - - ERR_FAIL_COND_V(ip_candidates.is_empty(), ERR_INVALID_PARAMETER); - - String port = ""; - if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) { - port = ":" + itos(p_port); + // Queue hostname for resolution. + _resolver_id = IP::get_singleton()->resolve_hostname_queue_item(p_host); + ERR_FAIL_COND_V(_resolver_id == IP::RESOLVER_INVALID_ID, ERR_INVALID_PARAMETER); + // Check if it was found in cache. + IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(_resolver_id); + if (ip_status == IP::RESOLVER_STATUS_DONE) { + _ip_candidates = IP::get_singleton()->get_resolve_item_addresses(_resolver_id); + IP::get_singleton()->erase_resolve_item(_resolver_id); + _resolver_id = IP::RESOLVER_INVALID_ID; + } } - Error err = ERR_BUG; // Should be at least one entry. - while (ip_candidates.size() > 0) { - err = _tcp->connect_to_host(ip_candidates.pop_front(), p_port); + // We assume OK while hostname resolution is pending. + Error err = _resolver_id != IP::RESOLVER_INVALID_ID ? OK : FAILED; + while (_ip_candidates.size()) { + err = _tcp->connect_to_host(_ip_candidates.pop_front(), p_port); if (err == OK) { break; } @@ -200,8 +207,11 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, } _key = WSLPeer::generate_key(); - // TODO custom extra headers (allow overriding this too?) String request = "GET " + p_path + " HTTP/1.1\r\n"; + String port = ""; + if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) { + port = ":" + itos(p_port); + } request += "Host: " + p_host + port + "\r\n"; request += "Upgrade: websocket\r\n"; request += "Connection: Upgrade\r\n"; @@ -222,6 +232,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, } request += "\r\n"; _request = request.utf8(); + _status = CONNECTION_CONNECTING; return OK; } @@ -231,6 +242,30 @@ int WSLClient::get_max_packet_size() const { } void WSLClient::poll() { + if (_resolver_id != IP::RESOLVER_INVALID_ID) { + IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(_resolver_id); + if (ip_status == IP::RESOLVER_STATUS_WAITING) { + return; + } + // Anything else is either a candidate or a failure. + Error err = FAILED; + if (ip_status == IP::RESOLVER_STATUS_DONE) { + _ip_candidates = IP::get_singleton()->get_resolve_item_addresses(_resolver_id); + while (_ip_candidates.size()) { + err = _tcp->connect_to_host(_ip_candidates.pop_front(), _port); + if (err == OK) { + break; + } + } + } + IP::get_singleton()->erase_resolve_item(_resolver_id); + _resolver_id = IP::RESOLVER_INVALID_ID; + if (err != OK) { + disconnect_from_host(); + _on_error(); + return; + } + } if (_peer->is_connected_to_host()) { _peer->poll(); if (!_peer->is_connected_to_host()) { @@ -244,6 +279,7 @@ void WSLClient::poll() { return; // Not connected. } + _tcp->poll(); switch (_tcp->get_status()) { case StreamPeerTCP::STATUS_NONE: // Clean close @@ -251,7 +287,7 @@ void WSLClient::poll() { _on_error(); break; case StreamPeerTCP::STATUS_CONNECTED: { - ip_candidates.clear(); + _ip_candidates.clear(); Ref<StreamPeerSSL> ssl; if (_use_ssl) { if (_connection == _tcp) { @@ -282,9 +318,9 @@ void WSLClient::poll() { _do_handshake(); } break; case StreamPeerTCP::STATUS_ERROR: - while (ip_candidates.size() > 0) { + while (_ip_candidates.size() > 0) { _tcp->disconnect_from_host(); - if (_tcp->connect_to_host(ip_candidates.pop_front(), _port) == OK) { + if (_tcp->connect_to_host(_ip_candidates.pop_front(), _port) == OK) { return; } } @@ -303,21 +339,19 @@ Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const { } MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const { + // This is surprising, but keeps the current behaviour to allow clean close requests. + // TODO Refactor WebSocket and split Client/Server/Multiplayer like done in other peers. if (_peer->is_connected_to_host()) { return CONNECTION_CONNECTED; } - - if (_tcp->is_connected_to_host()) { - return CONNECTION_CONNECTING; - } - - return CONNECTION_DISCONNECTED; + return _status; } void WSLClient::disconnect_from_host(int p_code, String p_reason) { _peer->close(p_code, p_reason); _connection = Ref<StreamPeer>(nullptr); _tcp = Ref<StreamPeerTCP>(memnew(StreamPeerTCP)); + _status = CONNECTION_DISCONNECTED; _key = ""; _host = ""; @@ -330,7 +364,12 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) { memset(_resp_buf, 0, sizeof(_resp_buf)); _resp_pos = 0; - ip_candidates.clear(); + if (_resolver_id != IP::RESOLVER_INVALID_ID) { + IP::get_singleton()->erase_resolve_item(_resolver_id); + _resolver_id = IP::RESOLVER_INVALID_ID; + } + + _ip_candidates.clear(); } IPAddress WSLClient::get_connected_host() const { diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h index 3972977910..22d7ffa839 100644 --- a/modules/websocket/wsl_client.h +++ b/modules/websocket/wsl_client.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -52,6 +52,7 @@ private: Ref<WSLPeer> _peer; Ref<StreamPeerTCP> _tcp; Ref<StreamPeer> _connection; + ConnectionStatus _status = CONNECTION_DISCONNECTED; CharString _request; int _requested = 0; @@ -59,28 +60,27 @@ private: uint8_t _resp_buf[WSL_MAX_HEADER_SIZE]; int _resp_pos = 0; - String _response; - String _key; String _host; - int _port; - Array ip_candidates; + uint16_t _port = 0; + Array _ip_candidates; Vector<String> _protocols; bool _use_ssl = false; + IP::ResolverID _resolver_id = IP::RESOLVER_INVALID_ID; void _do_handshake(); bool _verify_headers(String &r_protocol); public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - 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>()); - 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 = ""); - IPAddress get_connected_host() const; - uint16_t get_connected_port() const; - virtual ConnectionStatus get_connection_status() const; - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + 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>()) override; + int get_max_packet_size() const override; + Ref<WebSocketPeer> get_peer(int p_peer_id) const override; + void disconnect_from_host(int p_code = 1000, String p_reason = "") override; + IPAddress get_connected_host() const override; + uint16_t get_connected_port() const override; + virtual ConnectionStatus get_connection_status() const override; + virtual void poll() override; WSLClient(); ~WSLClient(); diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index fc520ec57c..15df4d039c 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -146,17 +146,17 @@ void wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event if (!peer_data->valid || peer_data->closing) { return; } - WSLPeer *peer = (WSLPeer *)peer_data->peer; + WSLPeer *peer = static_cast<WSLPeer *>(peer_data->peer); if (peer->parse_message(arg) != OK) { return; } if (peer_data->is_server) { - WSLServer *helper = (WSLServer *)peer_data->obj; + WSLServer *helper = static_cast<WSLServer *>(peer_data->obj); helper->_on_peer_packet(peer_data->id); } else { - WSLClient *helper = (WSLClient *)peer_data->obj; + WSLClient *helper = static_cast<WSLClient *>(peer_data->obj); helper->_on_peer_packet(); } } @@ -184,10 +184,10 @@ Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) { } if (!wslay_event_get_close_sent(_data->ctx)) { if (_data->is_server) { - WSLServer *helper = (WSLServer *)_data->obj; + WSLServer *helper = static_cast<WSLServer *>(_data->obj); helper->_on_close_request(_data->id, close_code, close_reason); } else { - WSLClient *helper = (WSLClient *)_data->obj; + WSLClient *helper = static_cast<WSLClient *>(_data->obj); helper->_on_close_request(close_code, close_reason); } } diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h index 260d4b183d..abeecdd537 100644 --- a/modules/websocket/wsl_peer.h +++ b/modules/websocket/wsl_peer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -85,22 +85,22 @@ public: String close_reason; void poll(); // Used by client and server. - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - virtual int get_max_packet_size() const { return _packet_buffer.size(); }; - virtual int get_current_outbound_buffered_amount() const; + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_max_packet_size() const override { return _packet_buffer.size(); }; + virtual int get_current_outbound_buffered_amount() const override; virtual void close_now(); - virtual void close(int p_code = 1000, String p_reason = ""); - virtual bool is_connected_to_host() const; - virtual IPAddress get_connected_host() const; - virtual uint16_t get_connected_port() const; - - virtual WriteMode get_write_mode() const; - virtual void set_write_mode(WriteMode p_mode); - virtual bool was_string_packet() const; - virtual void set_no_delay(bool p_enabled); + virtual void close(int p_code = 1000, String p_reason = "") override; + virtual bool is_connected_to_host() const override; + virtual IPAddress get_connected_host() const override; + virtual uint16_t get_connected_port() const override; + + virtual WriteMode get_write_mode() const override; + virtual void set_write_mode(WriteMode p_mode) override; + virtual bool was_string_packet() const override; + virtual void set_no_delay(bool p_enabled) override; void make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size); Error parse_message(const wslay_event_on_msg_recv_arg *arg); diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index a3d0d3554f..b58b2e4724 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -58,17 +58,17 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, St headers[name] = value; } } -#define _WSL_CHECK(NAME, VALUE) \ +#define WSL_CHECK(NAME, VALUE) \ ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \ "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'."); -#define _WSL_CHECK_EX(NAME) \ +#define WSL_CHECK_EX(NAME) \ ERR_FAIL_COND_V_MSG(!headers.has(NAME), false, "Missing header '" + String(NAME) + "'."); - _WSL_CHECK("upgrade", "websocket"); - _WSL_CHECK("sec-websocket-version", "13"); - _WSL_CHECK_EX("sec-websocket-key"); - _WSL_CHECK_EX("connection"); -#undef _WSL_CHECK_EX -#undef _WSL_CHECK + WSL_CHECK("upgrade", "websocket"); + WSL_CHECK("sec-websocket-version", "13"); + WSL_CHECK_EX("sec-websocket-key"); + WSL_CHECK_EX("connection"); +#undef WSL_CHECK_EX +#undef WSL_CHECK key = headers["sec-websocket-key"]; if (headers.has("sec-websocket-protocol")) { Vector<String> protos = headers["sec-websocket-protocol"].split(","); @@ -96,7 +96,7 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, St return true; } -Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name) { +Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers) { 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; @@ -141,6 +141,9 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin if (!protocol.is_empty()) { s += "Sec-WebSocket-Protocol: " + protocol + "\r\n"; } + for (int i = 0; i < p_extra_headers.size(); i++) { + s += p_extra_headers[i] + "\r\n"; + } s += "\r\n"; response = s.utf8(); has_request = true; @@ -167,6 +170,10 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin return OK; } +void WSLServer::set_extra_headers(const Vector<String> &p_headers) { + _extra_headers = p_headers; +} + Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp_api) { ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE); @@ -183,7 +190,7 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp void WSLServer::poll() { List<int> remove_ids; for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) { - Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr(); + Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr())); peer->poll(); if (!peer->is_connected_to_host()) { _on_disconnect(E.key, peer->close_code != -1); @@ -199,7 +206,7 @@ void WSLServer::poll() { for (const Ref<PendingPeer> &E : _pending) { String resource_name; Ref<PendingPeer> ppeer = E; - Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name); + Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name, _extra_headers); if (err == ERR_BUSY) { continue; } else if (err != OK) { @@ -266,7 +273,7 @@ int WSLServer::get_max_packet_size() const { void WSLServer::stop() { _server->stop(); for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) { - Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr(); + Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr())); peer->close_now(); } _pending.clear(); diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h index 508b5a12a1..a920e9c665 100644 --- a/modules/websocket/wsl_server.h +++ b/modules/websocket/wsl_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -62,7 +62,7 @@ private: CharString response; int response_sent = 0; - Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name); + Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers); }; int _in_buf_size = DEF_BUF_SHIFT; @@ -73,19 +73,21 @@ private: List<Ref<PendingPeer>> _pending; Ref<TCPServer> _server; Vector<String> _protocols; + Vector<String> _extra_headers; public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false); - void stop(); - bool is_listening() const; - int get_max_packet_size() const; - bool has_peer(int p_id) const; - Ref<WebSocketPeer> get_peer(int p_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(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + void set_extra_headers(const Vector<String> &p_headers) override; + Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override; + void stop() override; + bool is_listening() const override; + int get_max_packet_size() const override; + bool has_peer(int p_id) const override; + Ref<WebSocketPeer> get_peer(int p_id) const override; + IPAddress get_peer_address(int p_peer_id) const override; + int get_peer_port(int p_peer_id) const override; + void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override; + virtual void poll() override; WSLServer(); ~WSLServer(); diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index 6e224a8242..48447eb074 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebXRInterface" inherits="XRInterface" version="4.0"> +<class name="WebXRInterface" inherits="XRInterface" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> AR/VR interface using WebXR. </brief_description> diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h index 7aac0a6508..34225df001 100644 --- a/modules/webxr/godot_webxr.h +++ b/modules/webxr/godot_webxr.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp index 16b483c39e..cd403a4996 100644 --- a/modules/webxr/register_types.cpp +++ b/modules/webxr/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -37,8 +37,12 @@ Ref<WebXRInterfaceJS> webxr; #endif -void register_webxr_types() { - GDREGISTER_VIRTUAL_CLASS(WebXRInterface); +void initialize_webxr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + GDREGISTER_ABSTRACT_CLASS(WebXRInterface); #ifdef JAVASCRIPT_ENABLED webxr.instantiate(); @@ -46,7 +50,11 @@ void register_webxr_types() { #endif } -void unregister_webxr_types() { +void uninitialize_webxr_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + #ifdef JAVASCRIPT_ENABLED if (webxr.is_valid()) { // uninitialise our interface if it is initialised diff --git a/modules/webxr/register_types.h b/modules/webxr/register_types.h index f0c5a4bd79..2ea9bc1169 100644 --- a/modules/webxr/register_types.h +++ b/modules/webxr/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef WEBXR_REGISTER_TYPES_H #define WEBXR_REGISTER_TYPES_H -void register_webxr_types(); -void unregister_webxr_types(); +#include "modules/register_module_types.h" + +void initialize_webxr_module(ModuleInitializationLevel p_level); +void uninitialize_webxr_module(ModuleInitializationLevel p_level); #endif // WEBXR_REGISTER_TYPES_H diff --git a/modules/webxr/webxr_interface.cpp b/modules/webxr/webxr_interface.cpp index 3e8e75bf0e..b0ad53523a 100644 --- a/modules/webxr/webxr_interface.cpp +++ b/modules/webxr/webxr_interface.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h index 366235fcd5..801643bfa6 100644 --- a/modules/webxr/webxr_interface.h +++ b/modules/webxr/webxr_interface.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -35,8 +35,6 @@ #include "servers/xr/xr_positional_tracker.h" /** - @author David Snopek <david.snopek@snopekgames.com> - The WebXR interface is a VR/AR interface that can be used on the web. */ diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 2676b3cf80..74e744402b 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,11 +31,13 @@ #ifdef JAVASCRIPT_ENABLED #include "webxr_interface_js.h" + #include "core/input/input.h" #include "core/os/os.h" #include "emscripten.h" #include "godot_webxr.h" #include "servers/rendering/renderer_compositor.h" + #include <stdlib.h> void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) { @@ -57,7 +59,7 @@ void _emwebxr_on_session_started(char *p_reference_space_type) { ERR_FAIL_COND(interface.is_null()); String reference_space_type = String(p_reference_space_type); - ((WebXRInterfaceJS *)interface.ptr())->_set_reference_space_type(reference_space_type); + static_cast<WebXRInterfaceJS *>(interface.ptr())->_set_reference_space_type(reference_space_type); interface->emit_signal(SNAME("session_started")); } @@ -92,7 +94,7 @@ void _emwebxr_on_controller_changed() { Ref<XRInterface> interface = xr_server->find_interface("WebXR"); ERR_FAIL_COND(interface.is_null()); - ((WebXRInterfaceJS *)interface.ptr())->_on_controller_changed(); + static_cast<WebXRInterfaceJS *>(interface.ptr())->_on_controller_changed(); } extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_input_event(char *p_signal_name, int p_input_source) { @@ -289,15 +291,15 @@ void WebXRInterfaceJS::uninitialize() { 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]; - transform.basis.elements[2].x = p_js_matrix[2]; - transform.basis.elements[0].y = p_js_matrix[4]; - transform.basis.elements[1].y = p_js_matrix[5]; - transform.basis.elements[2].y = p_js_matrix[6]; - transform.basis.elements[0].z = p_js_matrix[8]; - transform.basis.elements[1].z = p_js_matrix[9]; - transform.basis.elements[2].z = p_js_matrix[10]; + transform.basis.rows[0].x = p_js_matrix[0]; + transform.basis.rows[1].x = p_js_matrix[1]; + transform.basis.rows[2].x = p_js_matrix[2]; + transform.basis.rows[0].y = p_js_matrix[4]; + transform.basis.rows[1].y = p_js_matrix[5]; + transform.basis.rows[2].y = p_js_matrix[6]; + transform.basis.rows[0].z = p_js_matrix[8]; + transform.basis.rows[1].z = p_js_matrix[9]; + transform.basis.rows[2].z = p_js_matrix[10]; transform.origin.x = p_js_matrix[12]; transform.origin.y = p_js_matrix[13]; transform.origin.z = p_js_matrix[14]; @@ -385,7 +387,7 @@ CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p return eye; } -Vector<BlitToScreen> WebXRInterfaceJS::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { +Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { Vector<BlitToScreen> blit_to_screen; if (!initialized) { @@ -481,7 +483,6 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { sprintf(name, "axis_%i", i); float value = *((float *)axes + (i + 1)); - ; tracker->set_input(name, value); } free(axes); diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index 6e6548c946..31858194f6 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -36,8 +36,6 @@ #include "webxr_interface.h" /** - @author David Snopek <david.snopek@snopekgames.com> - The WebXR interface is a VR/AR interface that can be used on the web. */ @@ -90,7 +88,7 @@ public: 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, double p_aspect, double p_z_near, double p_z_far) override; - virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void process() override; diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp index 58a6216b1e..e9985984a6 100644 --- a/modules/xatlas_unwrap/register_types.cpp +++ b/modules/xatlas_unwrap/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -120,6 +120,8 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver xatlas::ChartOptions chart_options; chart_options.fixWinding = true; + ERR_FAIL_COND_V_MSG(p_texel_size <= 0.0f, false, "Texel size must be greater than 0."); + xatlas::PackOptions pack_options; pack_options.padding = 1; pack_options.maxChartSize = 4094; // Lightmap atlassing needs 2 for padding between meshes, so 4096-2 @@ -220,9 +222,16 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver return true; } -void register_xatlas_unwrap_types() { +void initialize_xatlas_unwrap_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + array_mesh_lightmap_unwrap_callback = xatlas_mesh_lightmap_unwrap_callback; } -void unregister_xatlas_unwrap_types() { +void uninitialize_xatlas_unwrap_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } } diff --git a/modules/xatlas_unwrap/register_types.h b/modules/xatlas_unwrap/register_types.h index 2ad729f172..f82b5912f4 100644 --- a/modules/xatlas_unwrap/register_types.h +++ b/modules/xatlas_unwrap/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ @@ -31,7 +31,9 @@ #ifndef XATLAS_UNWRAP_REGISTER_TYPES_H #define XATLAS_UNWRAP_REGISTER_TYPES_H -void register_xatlas_unwrap_types(); -void unregister_xatlas_unwrap_types(); +#include "modules/register_module_types.h" + +void initialize_xatlas_unwrap_module(ModuleInitializationLevel p_level); +void uninitialize_xatlas_unwrap_module(ModuleInitializationLevel p_level); #endif // XATLAS_UNWRAP_REGISTER_TYPES_H |