diff options
Diffstat (limited to 'modules')
28 files changed, 1309 insertions, 1773 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 9b0dc9577b..429f53e59f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2563,8 +2563,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name); } - if (is_static && !base_type.is_meta_type && !(callee_type != GDScriptParser::Node::SUBSCRIPT && parser->current_function != nullptr && parser->current_function->is_static)) { - parser->push_warning(p_call, GDScriptWarning::STATIC_CALLED_ON_INSTANCE, p_call->function_name, base_type.to_string()); + if (is_static && !base_type.is_meta_type && !(is_self && parser->current_function != nullptr && parser->current_function->is_static)) { + String caller_type = String(base_type.native_type); + + if (caller_type.is_empty()) { + caller_type = base_type.to_string(); + } + + parser->push_warning(p_call, GDScriptWarning::STATIC_CALLED_ON_INSTANCE, p_call->function_name, caller_type); } #endif // DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 7f2f49f336..7074520a34 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3740,6 +3740,12 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node // 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 == SNAME("@export_range")) { + if (export_type.builtin_type == Variant::INT) { + variable->export_info.type = Variant::INT; + } + } + 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); diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index d0740cf7ca..9a554a0d49 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -66,7 +66,7 @@ </description> </method> <method name="get_materials"> - <return type="BaseMaterial3D[]" /> + <return type="Material[]" /> <description> </description> </method> @@ -169,7 +169,7 @@ </method> <method name="set_materials"> <return type="void" /> - <param index="0" name="materials" type="BaseMaterial3D[]" /> + <param index="0" name="materials" type="Material[]" /> <description> </description> </method> diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index f27e2385c6..eb8f7e5ebc 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -2484,12 +2484,12 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { if (surface_i < instance_materials.size()) { v = instance_materials.get(surface_i); } - Ref<BaseMaterial3D> mat = v; + Ref<Material> mat = v; if (!mat.is_valid()) { mat = import_mesh->get_surface_material(surface_i); } if (mat.is_valid()) { - HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); + HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); if (material_cache_i && material_cache_i->value != -1) { primitive["material"] = material_cache_i->value; } else { @@ -2937,16 +2937,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } } - Ref<BaseMaterial3D> mat; + Ref<Material> mat; 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]; + Ref<Material> 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); + + Ref<BaseMaterial3D> base_material = mat3d; + if (has_vertex_color && base_material.is_valid()) { + base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; @@ -2954,7 +2956,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Ref<StandardMaterial3D> mat3d; mat3d.instantiate(); if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; } @@ -3382,8 +3384,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Array materials; for (int32_t i = 0; i < state->materials.size(); i++) { Dictionary d; - - Ref<BaseMaterial3D> material = state->materials[i]; + Ref<Material> material = state->materials[i]; if (material.is_null()) { materials.push_back(d); continue; @@ -3391,11 +3392,12 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (!material->get_name().is_empty()) { d["name"] = _gen_unique_name(state, material->get_name()); } - { + Ref<BaseMaterial3D> base_material = material; + if (base_material.is_valid()) { Dictionary mr; { Array arr; - const Color c = material->get_albedo().srgb_to_linear(); + const Color c = base_material->get_albedo().srgb_to_linear(); arr.push_back(c.r); arr.push_back(c.g); arr.push_back(c.b); @@ -3404,167 +3406,169 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } { Dictionary bct; - Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - GLTFTextureIndex gltf_texture_index = -1; + if (base_material.is_valid()) { + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + GLTFTextureIndex gltf_texture_index = -1; - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - albedo_texture->set_name(material->get_name() + "_albedo"); - gltf_texture_index = _set_texture(state, albedo_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (gltf_texture_index != -1) { - bct["index"] = gltf_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - bct["extensions"] = extensions; - state->use_khr_texture_transform = true; + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + albedo_texture->set_name(material->get_name() + "_albedo"); + gltf_texture_index = _set_texture(state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (gltf_texture_index != -1) { + bct["index"] = gltf_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + bct["extensions"] = extensions; + state->use_khr_texture_transform = true; + } + mr["baseColorTexture"] = bct; } - mr["baseColorTexture"] = bct; } } - - mr["metallicFactor"] = material->get_metallic(); - mr["roughnessFactor"] = material->get_roughness(); - bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; - if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); + if (base_material.is_valid()) { + mr["metallicFactor"] = base_material->get_metallic(); + mr["roughnessFactor"] = base_material->get_roughness(); + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); + } + if (ao_image->is_compressed()) { + ao_image->decompress(); + } } - if (ao_image->is_compressed()) { - ao_image->decompress(); + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); + } + if (roughness_image->is_compressed()) { + roughness_image->decompress(); + } } - } - Ref<Image> roughness_image; - if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); + } + if (metallness_image->is_compressed()) { + metallness_image->decompress(); + } } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); } - } - Ref<Image> metallness_image; - if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); } - } - Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); - } - orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); + if (has_ao) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; + } } - } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; + if (has_roughness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; + } } - } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; + if (has_metalness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; + } } + orm_image->set_pixel(w, h, c); } - orm_image->set_pixel(w, h, c); } - } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(state, orm_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - state->use_khr_texture_transform = true; + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + state->use_khr_texture_transform = true; + } + mr["metallicRoughnessTexture"] = mrt; } - mr["metallicRoughnessTexture"] = mrt; } } d["pbrMetallicRoughness"] = mr; } - - if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { Dictionary nt; Ref<ImageTexture> tex; tex.instantiate(); { - Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); + Ref<Texture2D> normal_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); if (normal_texture.is_valid()) { // Code for uncompressing RG normal maps Ref<Image> img = normal_texture->get_image(); @@ -3594,30 +3598,30 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); - gltf_texture_index = _set_texture(state, tex, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + gltf_texture_index = _set_texture(state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } - nt["scale"] = material->get_normal_scale(); + nt["scale"] = base_material->get_normal_scale(); if (gltf_texture_index != -1) { nt["index"] = gltf_texture_index; d["normalTexture"] = nt; } } - if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { - const Color c = material->get_emission().linear_to_srgb(); + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + const Color c = base_material->get_emission().linear_to_srgb(); Array arr; arr.push_back(c.r); arr.push_back(c.g); arr.push_back(c.b); d["emissiveFactor"] = arr; } - if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { Dictionary et; - Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); + Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { emission_texture->set_name(material->get_name() + "_emission"); - gltf_texture_index = _set_texture(state, emission_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + gltf_texture_index = _set_texture(state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } if (gltf_texture_index != -1) { @@ -3625,14 +3629,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { d["emissiveTexture"] = et; } } - const bool ds = material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; + const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; if (ds) { d["doubleSided"] = ds; } - if (material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { + if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { d["alphaMode"] = "MASK"; - d["alphaCutoff"] = material->get_alpha_scissor_threshold(); - } else if (material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { + d["alphaCutoff"] = base_material->get_alpha_scissor_threshold(); + } else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { d["alphaMode"] = "BLEND"; } materials.push_back(d); @@ -3838,29 +3842,37 @@ void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMater if (d.has("extensions")) { const Dictionary &extensions = d["extensions"]; if (extensions.has("KHR_texture_transform")) { - const Dictionary &texture_transform = extensions["KHR_texture_transform"]; - const Array &offset_arr = texture_transform["offset"]; - if (offset_arr.size() == 2) { - const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); - material->set_uv1_offset(offset_vector3); - } + if (material.is_valid()) { + const Dictionary &texture_transform = extensions["KHR_texture_transform"]; + const Array &offset_arr = texture_transform["offset"]; + if (offset_arr.size() == 2) { + const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); + material->set_uv1_offset(offset_vector3); + } - const Array &scale_arr = texture_transform["scale"]; - if (scale_arr.size() == 2) { - const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); - material->set_uv1_scale(scale_vector3); + const Array &scale_arr = texture_transform["scale"]; + if (scale_arr.size() == 2) { + const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); + material->set_uv1_scale(scale_vector3); + } } } } } void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) { + if (r_spec_gloss.is_null()) { + return; + } if (r_spec_gloss->spec_gloss_img.is_null()) { return; } if (r_spec_gloss->diffuse_img.is_null()) { return; } + if (p_material.is_null()) { + return; + } bool has_roughness = false; bool has_metal = false; p_material->set_roughness(1.0f); @@ -6657,21 +6669,17 @@ Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { } Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { - if (p_material.is_valid()) { - Vector3 offset = p_material->get_uv1_offset(); - Vector3 scale = p_material->get_uv1_scale(); - return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); - } - return Dictionary(); + ERR_FAIL_NULL_V(p_material, Dictionary()); + Vector3 offset = p_material->get_uv1_offset(); + Vector3 scale = p_material->get_uv1_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { - if (p_material.is_valid()) { - Vector3 offset = p_material->get_uv2_offset(); - Vector3 scale = p_material->get_uv2_scale(); - return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); - } - return Dictionary(); + ERR_FAIL_NULL_V(p_material, Dictionary()); + Vector3 offset = p_material->get_uv2_offset(); + Vector3 scale = p_material->get_uv2_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index ac5665e396..6654c9e5d2 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -209,11 +209,11 @@ void GLTFState::set_meshes(TypedArray<GLTFMesh> p_meshes) { GLTFTemplateConvert::set_from_array(meshes, p_meshes); } -TypedArray<BaseMaterial3D> GLTFState::get_materials() { +TypedArray<Material> GLTFState::get_materials() { return GLTFTemplateConvert::to_array(materials); } -void GLTFState::set_materials(TypedArray<BaseMaterial3D> p_materials) { +void GLTFState::set_materials(TypedArray<Material> p_materials) { GLTFTemplateConvert::set_from_array(materials, p_materials); } diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index e24017b0fd..1c20520b22 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -72,8 +72,8 @@ class GLTFState : public Resource { Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to. Vector<AnimationPlayer *> animation_players; - HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache; - Vector<Ref<BaseMaterial3D>> materials; + HashMap<Ref<Material>, GLTFMaterialIndex> material_cache; + Vector<Ref<Material>> materials; String scene_name; Vector<int> root_nodes; @@ -138,8 +138,8 @@ public: TypedArray<GLTFMesh> get_meshes(); void set_meshes(TypedArray<GLTFMesh> p_meshes); - TypedArray<BaseMaterial3D> get_materials(); - void set_materials(TypedArray<BaseMaterial3D> p_materials); + TypedArray<Material> get_materials(); + void set_materials(TypedArray<Material> p_materials); String get_scene_name(); void set_scene_name(String p_scene_name); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 9c6cbebf0e..c8aedc8b92 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -459,6 +459,7 @@ void GridMapEditor::_delete_selection() { return; } + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("GridMap Delete Selection")); for (int i = selection.begin.x; i <= selection.end.x; i++) { for (int j = selection.begin.y; j <= selection.end.y; j++) { @@ -479,6 +480,7 @@ void GridMapEditor::_fill_selection() { return; } + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("GridMap Fill Selection")); for (int i = selection.begin.x; i <= selection.end.x; i++) { for (int j = selection.begin.y; j <= selection.end.y; j++) { @@ -572,6 +574,7 @@ void GridMapEditor::_do_paste() { rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation); Vector3 ofs = paste_indicator.current - paste_indicator.click; + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("GridMap Paste Selection")); for (const ClipboardItem &item : clipboard_items) { @@ -659,6 +662,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D } else { if ((mb->get_button_index() == MouseButton::RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) { if (set_items.size()) { + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("GridMap Paint")); for (const SetItem &si : set_items) { undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation); @@ -680,6 +684,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D } if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) { + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("GridMap Selection")); undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end); undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end); @@ -1142,8 +1147,6 @@ void GridMapEditor::_bind_methods() { } 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); ec->set_custom_minimum_size(Size2(mw, 0) * EDSCALE); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index 91f14690ca..1cf2e4cb89 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -41,7 +41,6 @@ #include "scene/gui/spin_box.h" class ConfirmationDialog; -class EditorUndoRedoManager; class MenuButton; class Node3DEditorPlugin; @@ -66,7 +65,6 @@ class GridMapEditor : public VBoxContainer { DISPLAY_LIST }; - Ref<EditorUndoRedoManager> undo_redo; InputAction input_action = INPUT_NONE; Panel *panel = nullptr; MenuButton *options = nullptr; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 345d2e4694..a4bffc1e3c 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -710,6 +710,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { return; } + if (!Engine::get_singleton()->is_editor_hint()) { + // We disable collectible assemblies in the game player, because the limitations cause + // issues with mocking libraries. As such, we can only reload assemblies in the editor. + return; + } + // TODO: // Currently, this reloads all scripts, including those whose class is not part of the // assembly load context being unloaded. As such, we unnecessarily reload GodotTools. diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index b90321b586..82b5f478e1 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -2274,7 +2274,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf p_output.append(");\n"); // Generate Callable trampoline for the delegate - p_output << MEMBER_BEGIN "private static unsafe void " << p_isignal.proxy_name << "Trampoline" + p_output << MEMBER_BEGIN "private static void " << p_isignal.proxy_name << "Trampoline" << "(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)\n" << INDENT1 "{\n" << INDENT2 "Callable.ThrowIfArgCountMismatch(args, " << itos(p_isignal.arguments.size()) << ");\n" @@ -2289,9 +2289,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf p_output << ","; } - // TODO: We don't need to use VariantConversionCallbacks. We have the type information so we can use [cs_variant_to_managed] and [cs_managed_to_variant]. - p_output << "\n" INDENT3 "VariantConversionCallbacks.GetToManagedCallback<" - << arg_type->cs_type << ">()(args[" << itos(idx) << "])"; + p_output << sformat(arg_type->cs_variant_to_managed, + "args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name); idx++; } diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs index 8308bada24..4ce02d221e 100644 --- a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs +++ b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs @@ -28,17 +28,24 @@ namespace GodotPlugins get => _pluginLoadContext?.AssemblyLoadedPath; } + public bool IsCollectible + { + [MethodImpl(MethodImplOptions.NoInlining)] + get => _pluginLoadContext?.IsCollectible ?? false; + } + [MethodImpl(MethodImplOptions.NoInlining)] public static (Assembly, PluginLoadContextWrapper) CreateAndLoadFromAssemblyName( AssemblyName assemblyName, string pluginPath, ICollection<string> sharedAssemblies, - AssemblyLoadContext mainLoadContext + AssemblyLoadContext mainLoadContext, + bool isCollectible ) { var wrapper = new PluginLoadContextWrapper(); wrapper._pluginLoadContext = new PluginLoadContext( - pluginPath, sharedAssemblies, mainLoadContext); + pluginPath, sharedAssemblies, mainLoadContext, isCollectible); var assembly = wrapper._pluginLoadContext.LoadFromAssemblyName(assemblyName); return (assembly, wrapper); } @@ -61,6 +68,7 @@ namespace GodotPlugins private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly; private static Assembly? _editorApiAssembly; private static PluginLoadContextWrapper? _projectLoadContext; + private static bool _editorHint = false; private static readonly AssemblyLoadContext MainLoadContext = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ?? @@ -77,15 +85,17 @@ namespace GodotPlugins { try { + _editorHint = editorHint.ToBool(); + _dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport; SharedAssemblies.Add(CoreApiAssembly.GetName()); NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver); - AlcReloadCfg.Configure(alcReloadEnabled: editorHint.ToBool()); + AlcReloadCfg.Configure(alcReloadEnabled: _editorHint); NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize); - if (editorHint.ToBool()) + if (_editorHint) { _editorApiAssembly = Assembly.Load("GodotSharpEditor"); SharedAssemblies.Add(_editorApiAssembly.GetName()); @@ -128,7 +138,7 @@ namespace GodotPlugins string assemblyPath = new(nAssemblyPath); - (var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath); + (var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath, isCollectible: _editorHint); string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath; *outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath); @@ -155,7 +165,7 @@ namespace GodotPlugins if (_editorApiAssembly == null) throw new InvalidOperationException("The Godot editor API assembly is not loaded."); - var (assembly, _) = LoadPlugin(assemblyPath); + var (assembly, _) = LoadPlugin(assemblyPath, isCollectible: _editorHint); NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!); @@ -180,7 +190,7 @@ namespace GodotPlugins } } - private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath) + private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath, bool isCollectible) { string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); @@ -194,7 +204,7 @@ namespace GodotPlugins } return PluginLoadContextWrapper.CreateAndLoadFromAssemblyName( - new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext); + new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext, isCollectible); } [UnmanagedCallersOnly] @@ -218,6 +228,12 @@ namespace GodotPlugins if (pluginLoadContext == null) return true; + if (!pluginLoadContext.IsCollectible) + { + Console.Error.WriteLine("Cannot unload a non-collectible assembly load context."); + return false; + } + Console.WriteLine("Unloading assembly load context..."); var alcWeakReference = pluginLoadContext.CreateWeakReference(); diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs index dcd572c65e..344b76a202 100644 --- a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs +++ b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs @@ -15,8 +15,8 @@ namespace GodotPlugins public string? AssemblyLoadedPath { get; private set; } public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies, - AssemblyLoadContext mainLoadContext) - : base(isCollectible: true) + AssemblyLoadContext mainLoadContext, bool isCollectible) + : base(isCollectible) { _resolver = new AssemblyDependencyResolver(pluginPath); _sharedAssemblies = sharedAssemblies; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index f1b46e293b..e3b7ac297d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -495,35 +495,10 @@ namespace Godot.Collections private static Array<T> FromVariantFunc(in godot_variant variant) => VariantUtils.ConvertToArrayObject<T>(variant); - // ReSharper disable StaticMemberInGenericType - // Warning is about unique static fields being created for each generic type combination: - // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html - // In our case this is exactly what we want. - - private static readonly unsafe delegate* managed<in T, godot_variant> ConvertToVariantCallback; - private static readonly unsafe delegate* managed<in godot_variant, T> ConvertToManagedCallback; - - // ReSharper restore StaticMemberInGenericType - static unsafe Array() { - VariantConversionCallbacks.GenericConversionCallbacks[typeof(Array<T>)] = - ( - (IntPtr)(delegate* managed<in Array<T>, godot_variant>)&ToVariantFunc, - (IntPtr)(delegate* managed<in godot_variant, Array<T>>)&FromVariantFunc - ); - - ConvertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>(); - ConvertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>(); - } - - private static unsafe void ValidateVariantConversionCallbacks() - { - if (ConvertToVariantCallback == null || ConvertToManagedCallback == null) - { - throw new InvalidOperationException( - $"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'."); - } + VariantUtils.GenericConversion<Array<T>>.ToVariantCb = &ToVariantFunc; + VariantUtils.GenericConversion<Array<T>>.FromVariantCb = &FromVariantFunc; } private readonly Array _underlyingArray; @@ -539,8 +514,6 @@ namespace Godot.Collections /// </summary> public Array() { - ValidateVariantConversionCallbacks(); - _underlyingArray = new Array(); } @@ -551,8 +524,6 @@ namespace Godot.Collections /// <returns>A new Godot Array.</returns> public Array(IEnumerable<T> collection) { - ValidateVariantConversionCallbacks(); - if (collection == null) throw new ArgumentNullException(nameof(collection)); @@ -569,8 +540,6 @@ namespace Godot.Collections /// <returns>A new Godot Array.</returns> public Array(T[] array) : this() { - ValidateVariantConversionCallbacks(); - if (array == null) throw new ArgumentNullException(nameof(array)); @@ -586,8 +555,6 @@ namespace Godot.Collections /// <param name="array">The untyped array to construct from.</param> public Array(Array array) { - ValidateVariantConversionCallbacks(); - _underlyingArray = array; } @@ -665,7 +632,7 @@ namespace Godot.Collections get { _underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem); - return ConvertToManagedCallback(borrowElem); + return VariantUtils.ConvertTo<T>(borrowElem); } set { @@ -675,7 +642,7 @@ namespace Godot.Collections godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self); godot_variant* itemPtr = &ptrw[index]; (*itemPtr).Dispose(); - *itemPtr = ConvertToVariantCallback(value); + *itemPtr = VariantUtils.CreateFrom(value); } } @@ -685,9 +652,9 @@ namespace Godot.Collections /// </summary> /// <param name="item">The item to search for.</param> /// <returns>The index of the item, or -1 if not found.</returns> - public unsafe int IndexOf(T item) + public int IndexOf(T item) { - using var variantValue = ConvertToVariantCallback(item); + using var variantValue = VariantUtils.CreateFrom(item); var self = (godot_array)_underlyingArray.NativeValue; return NativeFuncs.godotsharp_array_index_of(ref self, variantValue); } @@ -700,12 +667,12 @@ namespace Godot.Collections /// </summary> /// <param name="index">The index to insert at.</param> /// <param name="item">The item to insert.</param> - public unsafe void Insert(int index, T item) + public void Insert(int index, T item) { if (index < 0 || index > Count) throw new ArgumentOutOfRangeException(nameof(index)); - using var variantValue = ConvertToVariantCallback(item); + using var variantValue = VariantUtils.CreateFrom(item); var self = (godot_array)_underlyingArray.NativeValue; NativeFuncs.godotsharp_array_insert(ref self, index, variantValue); } @@ -736,9 +703,9 @@ namespace Godot.Collections /// </summary> /// <param name="item">The item to add.</param> /// <returns>The new size after adding the item.</returns> - public unsafe void Add(T item) + public void Add(T item) { - using var variantValue = ConvertToVariantCallback(item); + using var variantValue = VariantUtils.CreateFrom(item); var self = (godot_array)_underlyingArray.NativeValue; _ = NativeFuncs.godotsharp_array_add(ref self, variantValue); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs index 6c6a104019..ff385da1c9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs @@ -54,7 +54,7 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 1); ((Action<T0>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]) + VariantUtils.ConvertTo<T0>(args[0]) ); ret = default; @@ -73,8 +73,8 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 2); ((Action<T0, T1>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]) ); ret = default; @@ -93,9 +93,9 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 3); ((Action<T0, T1, T2>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]) ); ret = default; @@ -114,10 +114,10 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 4); ((Action<T0, T1, T2, T3>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]) ); ret = default; @@ -136,11 +136,11 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 5); ((Action<T0, T1, T2, T3, T4>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]) ); ret = default; @@ -159,12 +159,12 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 6); ((Action<T0, T1, T2, T3, T4, T5>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]) ); ret = default; @@ -183,13 +183,13 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 7); ((Action<T0, T1, T2, T3, T4, T5, T6>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]), - VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]), + VariantUtils.ConvertTo<T6>(args[6]) ); ret = default; @@ -208,14 +208,14 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 8); ((Action<T0, T1, T2, T3, T4, T5, T6, T7>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]), - VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]), - VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]), + VariantUtils.ConvertTo<T6>(args[6]), + VariantUtils.ConvertTo<T7>(args[7]) ); ret = default; @@ -234,15 +234,15 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 9); ((Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]), - VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]), - VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]), - VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]), + VariantUtils.ConvertTo<T6>(args[6]), + VariantUtils.ConvertTo<T7>(args[7]), + VariantUtils.ConvertTo<T8>(args[8]) ); ret = default; @@ -265,7 +265,7 @@ public readonly partial struct Callable TResult res = ((Func<TResult>)delegateObj)(); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -281,10 +281,10 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 1); TResult res = ((Func<T0, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]) + VariantUtils.ConvertTo<T0>(args[0]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -300,11 +300,11 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 2); TResult res = ((Func<T0, T1, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -320,12 +320,12 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 3); TResult res = ((Func<T0, T1, T2, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -341,13 +341,13 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 4); TResult res = ((Func<T0, T1, T2, T3, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -363,14 +363,14 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 5); TResult res = ((Func<T0, T1, T2, T3, T4, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -386,15 +386,15 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 6); TResult res = ((Func<T0, T1, T2, T3, T4, T5, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -410,16 +410,16 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 7); TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]), - VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]), + VariantUtils.ConvertTo<T6>(args[6]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -435,17 +435,17 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 8); TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]), - VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]), - VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]), + VariantUtils.ConvertTo<T6>(args[6]), + VariantUtils.ConvertTo<T7>(args[7]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); @@ -461,18 +461,18 @@ public readonly partial struct Callable ThrowIfArgCountMismatch(args, 9); TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>)delegateObj)( - VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]), - VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]), - VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]), - VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]), - VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]), - VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]), - VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]), - VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]), - VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8]) + VariantUtils.ConvertTo<T0>(args[0]), + VariantUtils.ConvertTo<T1>(args[1]), + VariantUtils.ConvertTo<T2>(args[2]), + VariantUtils.ConvertTo<T3>(args[3]), + VariantUtils.ConvertTo<T4>(args[4]), + VariantUtils.ConvertTo<T5>(args[5]), + VariantUtils.ConvertTo<T6>(args[6]), + VariantUtils.ConvertTo<T7>(args[7]), + VariantUtils.ConvertTo<T8>(args[8]) ); - ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res); + ret = VariantUtils.CreateFrom(res); } return CreateWithUnsafeTrampoline(func, &Trampoline); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index f8793332a0..f14790a218 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -362,45 +362,10 @@ namespace Godot.Collections private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) => VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant); - // ReSharper disable StaticMemberInGenericType - // Warning is about unique static fields being created for each generic type combination: - // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html - // In our case this is exactly what we want. - - private static readonly unsafe delegate* managed<in TKey, godot_variant> ConvertKeyToVariantCallback; - private static readonly unsafe delegate* managed<in godot_variant, TKey> ConvertKeyToManagedCallback; - private static readonly unsafe delegate* managed<in TValue, godot_variant> ConvertValueToVariantCallback; - private static readonly unsafe delegate* managed<in godot_variant, TValue> ConvertValueToManagedCallback; - - // ReSharper restore StaticMemberInGenericType - static unsafe Dictionary() { - VariantConversionCallbacks.GenericConversionCallbacks[typeof(Dictionary<TKey, TValue>)] = - ( - (IntPtr)(delegate* managed<in Dictionary<TKey, TValue>, godot_variant>)&ToVariantFunc, - (IntPtr)(delegate* managed<in godot_variant, Dictionary<TKey, TValue>>)&FromVariantFunc - ); - - ConvertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>(); - ConvertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>(); - ConvertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>(); - ConvertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>(); - } - - private static unsafe void ValidateVariantConversionCallbacks() - { - if (ConvertKeyToVariantCallback == null || ConvertKeyToManagedCallback == null) - { - throw new InvalidOperationException( - $"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'."); - } - - if (ConvertValueToVariantCallback == null || ConvertValueToManagedCallback == null) - { - throw new InvalidOperationException( - $"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'."); - } + VariantUtils.GenericConversion<Dictionary<TKey, TValue>>.ToVariantCb = &ToVariantFunc; + VariantUtils.GenericConversion<Dictionary<TKey, TValue>>.FromVariantCb = &FromVariantFunc; } private readonly Dictionary _underlyingDict; @@ -416,8 +381,6 @@ namespace Godot.Collections /// </summary> public Dictionary() { - ValidateVariantConversionCallbacks(); - _underlyingDict = new Dictionary(); } @@ -428,8 +391,6 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary<TKey, TValue> dictionary) { - ValidateVariantConversionCallbacks(); - if (dictionary == null) throw new ArgumentNullException(nameof(dictionary)); @@ -446,8 +407,6 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary(Dictionary dictionary) { - ValidateVariantConversionCallbacks(); - _underlyingDict = dictionary; } @@ -481,18 +440,18 @@ namespace Godot.Collections /// Returns the value at the given <paramref name="key"/>. /// </summary> /// <value>The value at the given <paramref name="key"/>.</value> - public unsafe TValue this[TKey key] + public TValue this[TKey key] { get { - using var variantKey = ConvertKeyToVariantCallback(key); + using var variantKey = VariantUtils.CreateFrom(key); var self = (godot_dictionary)_underlyingDict.NativeValue; if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, out godot_variant value).ToBool()) { using (value) - return ConvertValueToManagedCallback(value); + return VariantUtils.ConvertTo<TValue>(value); } else { @@ -501,8 +460,8 @@ namespace Godot.Collections } set { - using var variantKey = ConvertKeyToVariantCallback(key); - using var variantValue = ConvertValueToVariantCallback(value); + using var variantKey = VariantUtils.CreateFrom(key); + using var variantValue = VariantUtils.CreateFrom(value); var self = (godot_dictionary)_underlyingDict.NativeValue; NativeFuncs.godotsharp_dictionary_set_value(ref self, variantKey, variantValue); @@ -541,7 +500,7 @@ namespace Godot.Collections IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values; - private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index) + private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) { var self = (godot_dictionary)_underlyingDict.NativeValue; NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index, @@ -551,8 +510,8 @@ namespace Godot.Collections using (value) { return new KeyValuePair<TKey, TValue>( - ConvertKeyToManagedCallback(key), - ConvertValueToManagedCallback(value)); + VariantUtils.ConvertTo<TKey>(key), + VariantUtils.ConvertTo<TValue>(value)); } } @@ -562,15 +521,15 @@ namespace Godot.Collections /// </summary> /// <param name="key">The key at which to add the object.</param> /// <param name="value">The object to add.</param> - public unsafe void Add(TKey key, TValue value) + public void Add(TKey key, TValue value) { - using var variantKey = ConvertKeyToVariantCallback(key); + using var variantKey = VariantUtils.CreateFrom(key); var self = (godot_dictionary)_underlyingDict.NativeValue; if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool()) throw new ArgumentException("An element with the same key already exists.", nameof(key)); - using var variantValue = ConvertValueToVariantCallback(value); + using var variantValue = VariantUtils.CreateFrom(value); NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue); } @@ -579,9 +538,9 @@ namespace Godot.Collections /// </summary> /// <param name="key">The key to look for.</param> /// <returns>Whether or not this dictionary contains the given key.</returns> - public unsafe bool ContainsKey(TKey key) + public bool ContainsKey(TKey key) { - using var variantKey = ConvertKeyToVariantCallback(key); + using var variantKey = VariantUtils.CreateFrom(key); var self = (godot_dictionary)_underlyingDict.NativeValue; return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool(); } @@ -590,9 +549,9 @@ namespace Godot.Collections /// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key. /// </summary> /// <param name="key">The key of the element to remove.</param> - public unsafe bool Remove(TKey key) + public bool Remove(TKey key) { - using var variantKey = ConvertKeyToVariantCallback(key); + using var variantKey = VariantUtils.CreateFrom(key); var self = (godot_dictionary)_underlyingDict.NativeValue; return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool(); } @@ -603,15 +562,15 @@ namespace Godot.Collections /// <param name="key">The key of the element to get.</param> /// <param name="value">The value at the given <paramref name="key"/>.</param> /// <returns>If an object was found for the given <paramref name="key"/>.</returns> - public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { - using var variantKey = ConvertKeyToVariantCallback(key); + using var variantKey = VariantUtils.CreateFrom(key); var self = (godot_dictionary)_underlyingDict.NativeValue; bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, out godot_variant retValue).ToBool(); using (retValue) - value = found ? ConvertValueToManagedCallback(retValue) : default; + value = found ? VariantUtils.ConvertTo<TValue>(retValue) : default; return found; } @@ -635,9 +594,9 @@ namespace Godot.Collections /// </summary> public void Clear() => _underlyingDict.Clear(); - unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { - using var variantKey = ConvertKeyToVariantCallback(item.Key); + using var variantKey = VariantUtils.CreateFrom(item.Key); var self = (godot_dictionary)_underlyingDict.NativeValue; bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, out godot_variant retValue).ToBool(); @@ -647,7 +606,7 @@ namespace Godot.Collections if (!found) return false; - using var variantValue = ConvertValueToVariantCallback(item.Value); + using var variantValue = VariantUtils.CreateFrom(item.Value); return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool(); } } @@ -680,9 +639,9 @@ namespace Godot.Collections } } - unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { - using var variantKey = ConvertKeyToVariantCallback(item.Key); + using var variantKey = VariantUtils.CreateFrom(item.Key); var self = (godot_dictionary)_underlyingDict.NativeValue; bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, out godot_variant retValue).ToBool(); @@ -692,7 +651,7 @@ namespace Godot.Collections if (!found) return false; - using var variantValue = ConvertValueToVariantCallback(item.Value); + using var variantValue = VariantUtils.CreateFrom(item.Value); if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool()) { return NativeFuncs.godotsharp_dictionary_remove_key( diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index f2667c6807..3f9e986f62 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -282,7 +282,7 @@ namespace Godot /// <summary> /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by - /// the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points. + /// the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points. /// </summary> /// <param name="start">The start value for the interpolation.</param> /// <param name="control1">Control point that defines the bezier curve.</param> @@ -303,6 +303,27 @@ namespace Godot } /// <summary> + /// Returns the derivative at the given <paramref name="t"/> on a one dimensional Bezier curve defined by + /// the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points. + /// </summary> + /// <param name="start">The start value for the interpolation.</param> + /// <param name="control1">Control point that defines the bezier curve.</param> + /// <param name="control2">Control point that defines the bezier curve.</param> + /// <param name="end">The destination value for the interpolation.</param> + /// <param name="t">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 BezierDerivative(real_t start, real_t control1, real_t control2, real_t end, real_t t) + { + // Formula from Wikipedia article on Bezier curves + real_t omt = 1 - t; + real_t omt2 = omt * omt; + real_t t2 = t * t; + + real_t d = (control1 - start) * 3 * omt2 + (control2 - control1) * 6 * omt * t + (end - control2) * 3 * t2; + return d; + } + + /// <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/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs deleted file mode 100644 index 4b3db0c01a..0000000000 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs +++ /dev/null @@ -1,1057 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - -namespace Godot.NativeInterop; - -// TODO: Change VariantConversionCallbacks<T>. Store the callback in a static field for quick repeated access, instead of checking every time. -internal static unsafe class VariantConversionCallbacks -{ - internal static System.Collections.Generic.Dictionary<Type, (IntPtr ToVariant, IntPtr FromVariant)> - GenericConversionCallbacks = new(); - - [SuppressMessage("ReSharper", "RedundantNameQualifier")] - internal static delegate*<in T, godot_variant> GetToVariantCallback<T>() - { - static godot_variant FromBool(in bool @bool) => - VariantUtils.CreateFromBool(@bool); - - static godot_variant FromChar(in char @char) => - VariantUtils.CreateFromInt(@char); - - static godot_variant FromInt8(in sbyte @int8) => - VariantUtils.CreateFromInt(@int8); - - static godot_variant FromInt16(in short @int16) => - VariantUtils.CreateFromInt(@int16); - - static godot_variant FromInt32(in int @int32) => - VariantUtils.CreateFromInt(@int32); - - static godot_variant FromInt64(in long @int64) => - VariantUtils.CreateFromInt(@int64); - - static godot_variant FromUInt8(in byte @uint8) => - VariantUtils.CreateFromInt(@uint8); - - static godot_variant FromUInt16(in ushort @uint16) => - VariantUtils.CreateFromInt(@uint16); - - static godot_variant FromUInt32(in uint @uint32) => - VariantUtils.CreateFromInt(@uint32); - - static godot_variant FromUInt64(in ulong @uint64) => - VariantUtils.CreateFromInt(@uint64); - - static godot_variant FromFloat(in float @float) => - VariantUtils.CreateFromFloat(@float); - - static godot_variant FromDouble(in double @double) => - VariantUtils.CreateFromFloat(@double); - - static godot_variant FromVector2(in Vector2 @vector2) => - VariantUtils.CreateFromVector2(@vector2); - - static godot_variant FromVector2I(in Vector2i vector2I) => - VariantUtils.CreateFromVector2i(vector2I); - - static godot_variant FromRect2(in Rect2 @rect2) => - VariantUtils.CreateFromRect2(@rect2); - - static godot_variant FromRect2I(in Rect2i rect2I) => - VariantUtils.CreateFromRect2i(rect2I); - - static godot_variant FromTransform2D(in Transform2D @transform2D) => - VariantUtils.CreateFromTransform2D(@transform2D); - - static godot_variant FromVector3(in Vector3 @vector3) => - VariantUtils.CreateFromVector3(@vector3); - - static godot_variant FromVector3I(in Vector3i vector3I) => - VariantUtils.CreateFromVector3i(vector3I); - - static godot_variant FromBasis(in Basis @basis) => - VariantUtils.CreateFromBasis(@basis); - - static godot_variant FromQuaternion(in Quaternion @quaternion) => - VariantUtils.CreateFromQuaternion(@quaternion); - - static godot_variant FromTransform3D(in Transform3D @transform3d) => - VariantUtils.CreateFromTransform3D(@transform3d); - - static godot_variant FromVector4(in Vector4 @vector4) => - VariantUtils.CreateFromVector4(@vector4); - - static godot_variant FromVector4I(in Vector4i vector4I) => - VariantUtils.CreateFromVector4i(vector4I); - - static godot_variant FromAabb(in AABB @aabb) => - VariantUtils.CreateFromAABB(@aabb); - - static godot_variant FromColor(in Color @color) => - VariantUtils.CreateFromColor(@color); - - static godot_variant FromPlane(in Plane @plane) => - VariantUtils.CreateFromPlane(@plane); - - static godot_variant FromCallable(in Callable @callable) => - VariantUtils.CreateFromCallable(@callable); - - static godot_variant FromSignalInfo(in SignalInfo @signalInfo) => - VariantUtils.CreateFromSignalInfo(@signalInfo); - - static godot_variant FromString(in string @string) => - VariantUtils.CreateFromString(@string); - - static godot_variant FromByteArray(in byte[] byteArray) => - VariantUtils.CreateFromPackedByteArray(byteArray); - - static godot_variant FromInt32Array(in int[] int32Array) => - VariantUtils.CreateFromPackedInt32Array(int32Array); - - static godot_variant FromInt64Array(in long[] int64Array) => - VariantUtils.CreateFromPackedInt64Array(int64Array); - - static godot_variant FromFloatArray(in float[] floatArray) => - VariantUtils.CreateFromPackedFloat32Array(floatArray); - - static godot_variant FromDoubleArray(in double[] doubleArray) => - VariantUtils.CreateFromPackedFloat64Array(doubleArray); - - static godot_variant FromStringArray(in string[] stringArray) => - VariantUtils.CreateFromPackedStringArray(stringArray); - - static godot_variant FromVector2Array(in Vector2[] vector2Array) => - VariantUtils.CreateFromPackedVector2Array(vector2Array); - - static godot_variant FromVector3Array(in Vector3[] vector3Array) => - VariantUtils.CreateFromPackedVector3Array(vector3Array); - - static godot_variant FromColorArray(in Color[] colorArray) => - VariantUtils.CreateFromPackedColorArray(colorArray); - - static godot_variant FromStringNameArray(in StringName[] stringNameArray) => - VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray); - - static godot_variant FromNodePathArray(in NodePath[] nodePathArray) => - VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray); - - static godot_variant FromRidArray(in RID[] ridArray) => - VariantUtils.CreateFromSystemArrayOfRID(ridArray); - - static godot_variant FromGodotObject(in Godot.Object godotObject) => - VariantUtils.CreateFromGodotObject(godotObject); - - static godot_variant FromStringName(in StringName stringName) => - VariantUtils.CreateFromStringName(stringName); - - static godot_variant FromNodePath(in NodePath nodePath) => - VariantUtils.CreateFromNodePath(nodePath); - - static godot_variant FromRid(in RID rid) => - VariantUtils.CreateFromRID(rid); - - static godot_variant FromGodotDictionary(in Collections.Dictionary godotDictionary) => - VariantUtils.CreateFromDictionary(godotDictionary); - - static godot_variant FromGodotArray(in Collections.Array godotArray) => - VariantUtils.CreateFromArray(godotArray); - - static godot_variant FromVariant(in Variant variant) => - NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar); - - var typeOfT = typeof(T); - - if (typeOfT == typeof(bool)) - { - return (delegate*<in T, godot_variant>)(delegate*<in bool, godot_variant>) - &FromBool; - } - - if (typeOfT == typeof(char)) - { - return (delegate*<in T, godot_variant>)(delegate*<in char, godot_variant>) - &FromChar; - } - - if (typeOfT == typeof(sbyte)) - { - return (delegate*<in T, godot_variant>)(delegate*<in sbyte, godot_variant>) - &FromInt8; - } - - if (typeOfT == typeof(short)) - { - return (delegate*<in T, godot_variant>)(delegate*<in short, godot_variant>) - &FromInt16; - } - - if (typeOfT == typeof(int)) - { - return (delegate*<in T, godot_variant>)(delegate*<in int, godot_variant>) - &FromInt32; - } - - if (typeOfT == typeof(long)) - { - return (delegate*<in T, godot_variant>)(delegate*<in long, godot_variant>) - &FromInt64; - } - - if (typeOfT == typeof(byte)) - { - return (delegate*<in T, godot_variant>)(delegate*<in byte, godot_variant>) - &FromUInt8; - } - - if (typeOfT == typeof(ushort)) - { - return (delegate*<in T, godot_variant>)(delegate*<in ushort, godot_variant>) - &FromUInt16; - } - - if (typeOfT == typeof(uint)) - { - return (delegate*<in T, godot_variant>)(delegate*<in uint, godot_variant>) - &FromUInt32; - } - - if (typeOfT == typeof(ulong)) - { - return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>) - &FromUInt64; - } - - if (typeOfT == typeof(float)) - { - return (delegate*<in T, godot_variant>)(delegate*<in float, godot_variant>) - &FromFloat; - } - - if (typeOfT == typeof(double)) - { - return (delegate*<in T, godot_variant>)(delegate*<in double, godot_variant>) - &FromDouble; - } - - if (typeOfT == typeof(Vector2)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector2, godot_variant>) - &FromVector2; - } - - if (typeOfT == typeof(Vector2i)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector2i, godot_variant>) - &FromVector2I; - } - - if (typeOfT == typeof(Rect2)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Rect2, godot_variant>) - &FromRect2; - } - - if (typeOfT == typeof(Rect2i)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Rect2i, godot_variant>) - &FromRect2I; - } - - if (typeOfT == typeof(Transform2D)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Transform2D, godot_variant>) - &FromTransform2D; - } - - if (typeOfT == typeof(Vector3)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector3, godot_variant>) - &FromVector3; - } - - if (typeOfT == typeof(Vector3i)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector3i, godot_variant>) - &FromVector3I; - } - - if (typeOfT == typeof(Basis)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Basis, godot_variant>) - &FromBasis; - } - - if (typeOfT == typeof(Quaternion)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Quaternion, godot_variant>) - &FromQuaternion; - } - - if (typeOfT == typeof(Transform3D)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Transform3D, godot_variant>) - &FromTransform3D; - } - - if (typeOfT == typeof(Vector4)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector4, godot_variant>) - &FromVector4; - } - - if (typeOfT == typeof(Vector4i)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector4i, godot_variant>) - &FromVector4I; - } - - if (typeOfT == typeof(AABB)) - { - return (delegate*<in T, godot_variant>)(delegate*<in AABB, godot_variant>) - &FromAabb; - } - - if (typeOfT == typeof(Color)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Color, godot_variant>) - &FromColor; - } - - if (typeOfT == typeof(Plane)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Plane, godot_variant>) - &FromPlane; - } - - if (typeOfT == typeof(Callable)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Callable, godot_variant>) - &FromCallable; - } - - if (typeOfT == typeof(SignalInfo)) - { - return (delegate*<in T, godot_variant>)(delegate*<in SignalInfo, godot_variant>) - &FromSignalInfo; - } - - if (typeOfT.IsEnum) - { - var enumUnderlyingType = typeOfT.GetEnumUnderlyingType(); - - switch (Type.GetTypeCode(enumUnderlyingType)) - { - case TypeCode.SByte: - { - return (delegate*<in T, godot_variant>)(delegate*<in sbyte, godot_variant>) - &FromInt8; - } - case TypeCode.Int16: - { - return (delegate*<in T, godot_variant>)(delegate*<in short, godot_variant>) - &FromInt16; - } - case TypeCode.Int32: - { - return (delegate*<in T, godot_variant>)(delegate*<in int, godot_variant>) - &FromInt32; - } - case TypeCode.Int64: - { - return (delegate*<in T, godot_variant>)(delegate*<in long, godot_variant>) - &FromInt64; - } - case TypeCode.Byte: - { - return (delegate*<in T, godot_variant>)(delegate*<in byte, godot_variant>) - &FromUInt8; - } - case TypeCode.UInt16: - { - return (delegate*<in T, godot_variant>)(delegate*<in ushort, godot_variant>) - &FromUInt16; - } - case TypeCode.UInt32: - { - return (delegate*<in T, godot_variant>)(delegate*<in uint, godot_variant>) - &FromUInt32; - } - case TypeCode.UInt64: - { - return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>) - &FromUInt64; - } - default: - return null; - } - } - - if (typeOfT == typeof(string)) - { - return (delegate*<in T, godot_variant>)(delegate*<in string, godot_variant>) - &FromString; - } - - if (typeOfT == typeof(byte[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in byte[], godot_variant>) - &FromByteArray; - } - - if (typeOfT == typeof(int[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in int[], godot_variant>) - &FromInt32Array; - } - - if (typeOfT == typeof(long[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in long[], godot_variant>) - &FromInt64Array; - } - - if (typeOfT == typeof(float[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in float[], godot_variant>) - &FromFloatArray; - } - - if (typeOfT == typeof(double[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in double[], godot_variant>) - &FromDoubleArray; - } - - if (typeOfT == typeof(string[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in string[], godot_variant>) - &FromStringArray; - } - - if (typeOfT == typeof(Vector2[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector2[], godot_variant>) - &FromVector2Array; - } - - if (typeOfT == typeof(Vector3[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in Vector3[], godot_variant>) - &FromVector3Array; - } - - if (typeOfT == typeof(Color[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in Color[], godot_variant>) - &FromColorArray; - } - - if (typeOfT == typeof(StringName[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in StringName[], godot_variant>) - &FromStringNameArray; - } - - if (typeOfT == typeof(NodePath[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in NodePath[], godot_variant>) - &FromNodePathArray; - } - - if (typeOfT == typeof(RID[])) - { - return (delegate*<in T, godot_variant>)(delegate*<in RID[], godot_variant>) - &FromRidArray; - } - - if (typeof(Godot.Object).IsAssignableFrom(typeOfT)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Godot.Object, godot_variant>) - &FromGodotObject; - } - - if (typeOfT == typeof(StringName)) - { - return (delegate*<in T, godot_variant>)(delegate*<in StringName, godot_variant>) - &FromStringName; - } - - if (typeOfT == typeof(NodePath)) - { - return (delegate*<in T, godot_variant>)(delegate*<in NodePath, godot_variant>) - &FromNodePath; - } - - if (typeOfT == typeof(RID)) - { - return (delegate*<in T, godot_variant>)(delegate*<in RID, godot_variant>) - &FromRid; - } - - if (typeOfT == typeof(Godot.Collections.Dictionary)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Godot.Collections.Dictionary, godot_variant>) - &FromGodotDictionary; - } - - if (typeOfT == typeof(Godot.Collections.Array)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Godot.Collections.Array, godot_variant>) - &FromGodotArray; - } - - if (typeOfT == typeof(Variant)) - { - return (delegate*<in T, godot_variant>)(delegate*<in Variant, godot_variant>) - &FromVariant; - } - - // TODO: - // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode. - // We could make the Godot collections implement an interface and use IsAssignableFrom instead. - // Or we could just skip the check and always look for a conversion callback for the type. - if (typeOfT.IsGenericType) - { - var genericTypeDef = typeOfT.GetGenericTypeDefinition(); - - if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) || - genericTypeDef == typeof(Godot.Collections.Array<>)) - { - RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle); - - if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion)) - { - return (delegate*<in T, godot_variant>)genericConversion.ToVariant; - } - } - } - - return null; - } - - [SuppressMessage("ReSharper", "RedundantNameQualifier")] - internal static delegate*<in godot_variant, T> GetToManagedCallback<T>() - { - static bool ToBool(in godot_variant variant) => - VariantUtils.ConvertToBool(variant); - - static char ToChar(in godot_variant variant) => - VariantUtils.ConvertToChar(variant); - - static sbyte ToInt8(in godot_variant variant) => - VariantUtils.ConvertToInt8(variant); - - static short ToInt16(in godot_variant variant) => - VariantUtils.ConvertToInt16(variant); - - static int ToInt32(in godot_variant variant) => - VariantUtils.ConvertToInt32(variant); - - static long ToInt64(in godot_variant variant) => - VariantUtils.ConvertToInt64(variant); - - static byte ToUInt8(in godot_variant variant) => - VariantUtils.ConvertToUInt8(variant); - - static ushort ToUInt16(in godot_variant variant) => - VariantUtils.ConvertToUInt16(variant); - - static uint ToUInt32(in godot_variant variant) => - VariantUtils.ConvertToUInt32(variant); - - static ulong ToUInt64(in godot_variant variant) => - VariantUtils.ConvertToUInt64(variant); - - static float ToFloat(in godot_variant variant) => - VariantUtils.ConvertToFloat32(variant); - - static double ToDouble(in godot_variant variant) => - VariantUtils.ConvertToFloat64(variant); - - static Vector2 ToVector2(in godot_variant variant) => - VariantUtils.ConvertToVector2(variant); - - static Vector2i ToVector2I(in godot_variant variant) => - VariantUtils.ConvertToVector2i(variant); - - static Rect2 ToRect2(in godot_variant variant) => - VariantUtils.ConvertToRect2(variant); - - static Rect2i ToRect2I(in godot_variant variant) => - VariantUtils.ConvertToRect2i(variant); - - static Transform2D ToTransform2D(in godot_variant variant) => - VariantUtils.ConvertToTransform2D(variant); - - static Vector3 ToVector3(in godot_variant variant) => - VariantUtils.ConvertToVector3(variant); - - static Vector3i ToVector3I(in godot_variant variant) => - VariantUtils.ConvertToVector3i(variant); - - static Basis ToBasis(in godot_variant variant) => - VariantUtils.ConvertToBasis(variant); - - static Quaternion ToQuaternion(in godot_variant variant) => - VariantUtils.ConvertToQuaternion(variant); - - static Transform3D ToTransform3D(in godot_variant variant) => - VariantUtils.ConvertToTransform3D(variant); - - static Vector4 ToVector4(in godot_variant variant) => - VariantUtils.ConvertToVector4(variant); - - static Vector4i ToVector4I(in godot_variant variant) => - VariantUtils.ConvertToVector4i(variant); - - static AABB ToAabb(in godot_variant variant) => - VariantUtils.ConvertToAABB(variant); - - static Color ToColor(in godot_variant variant) => - VariantUtils.ConvertToColor(variant); - - static Plane ToPlane(in godot_variant variant) => - VariantUtils.ConvertToPlane(variant); - - static Callable ToCallable(in godot_variant variant) => - VariantUtils.ConvertToCallableManaged(variant); - - static SignalInfo ToSignalInfo(in godot_variant variant) => - VariantUtils.ConvertToSignalInfo(variant); - - static string ToString(in godot_variant variant) => - VariantUtils.ConvertToStringObject(variant); - - static byte[] ToByteArray(in godot_variant variant) => - VariantUtils.ConvertAsPackedByteArrayToSystemArray(variant); - - static int[] ToInt32Array(in godot_variant variant) => - VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(variant); - - static long[] ToInt64Array(in godot_variant variant) => - VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(variant); - - static float[] ToFloatArray(in godot_variant variant) => - VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(variant); - - static double[] ToDoubleArray(in godot_variant variant) => - VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(variant); - - static string[] ToStringArray(in godot_variant variant) => - VariantUtils.ConvertAsPackedStringArrayToSystemArray(variant); - - static Vector2[] ToVector2Array(in godot_variant variant) => - VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(variant); - - static Vector3[] ToVector3Array(in godot_variant variant) => - VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(variant); - - static Color[] ToColorArray(in godot_variant variant) => - VariantUtils.ConvertAsPackedColorArrayToSystemArray(variant); - - static StringName[] ToStringNameArray(in godot_variant variant) => - VariantUtils.ConvertToSystemArrayOfStringName(variant); - - static NodePath[] ToNodePathArray(in godot_variant variant) => - VariantUtils.ConvertToSystemArrayOfNodePath(variant); - - static RID[] ToRidArray(in godot_variant variant) => - VariantUtils.ConvertToSystemArrayOfRID(variant); - - static Godot.Object ToGodotObject(in godot_variant variant) => - VariantUtils.ConvertToGodotObject(variant); - - static StringName ToStringName(in godot_variant variant) => - VariantUtils.ConvertToStringNameObject(variant); - - static NodePath ToNodePath(in godot_variant variant) => - VariantUtils.ConvertToNodePathObject(variant); - - static RID ToRid(in godot_variant variant) => - VariantUtils.ConvertToRID(variant); - - static Collections.Dictionary ToGodotDictionary(in godot_variant variant) => - VariantUtils.ConvertToDictionaryObject(variant); - - static Collections.Array ToGodotArray(in godot_variant variant) => - VariantUtils.ConvertToArrayObject(variant); - - static Variant ToVariant(in godot_variant variant) => - Variant.CreateCopyingBorrowed(variant); - - var typeOfT = typeof(T); - - // ReSharper disable RedundantCast - // Rider is being stupid here. These casts are definitely needed. We get build errors without them. - - if (typeOfT == typeof(bool)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, bool>) - &ToBool; - } - - if (typeOfT == typeof(char)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, char>) - &ToChar; - } - - if (typeOfT == typeof(sbyte)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, sbyte>) - &ToInt8; - } - - if (typeOfT == typeof(short)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, short>) - &ToInt16; - } - - if (typeOfT == typeof(int)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int>) - &ToInt32; - } - - if (typeOfT == typeof(long)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long>) - &ToInt64; - } - - if (typeOfT == typeof(byte)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte>) - &ToUInt8; - } - - if (typeOfT == typeof(ushort)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ushort>) - &ToUInt16; - } - - if (typeOfT == typeof(uint)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, uint>) - &ToUInt32; - } - - if (typeOfT == typeof(ulong)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>) - &ToUInt64; - } - - if (typeOfT == typeof(float)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, float>) - &ToFloat; - } - - if (typeOfT == typeof(double)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, double>) - &ToDouble; - } - - if (typeOfT == typeof(Vector2)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2>) - &ToVector2; - } - - if (typeOfT == typeof(Vector2i)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2i>) - &ToVector2I; - } - - if (typeOfT == typeof(Rect2)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Rect2>) - &ToRect2; - } - - if (typeOfT == typeof(Rect2i)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Rect2i>) - &ToRect2I; - } - - if (typeOfT == typeof(Transform2D)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform2D>) - &ToTransform2D; - } - - if (typeOfT == typeof(Vector3)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3>) - &ToVector3; - } - - if (typeOfT == typeof(Vector3i)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3i>) - &ToVector3I; - } - - if (typeOfT == typeof(Basis)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Basis>) - &ToBasis; - } - - if (typeOfT == typeof(Quaternion)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Quaternion>) - &ToQuaternion; - } - - if (typeOfT == typeof(Transform3D)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform3D>) - &ToTransform3D; - } - - if (typeOfT == typeof(Vector4)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector4>) - &ToVector4; - } - - if (typeOfT == typeof(Vector4i)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector4i>) - &ToVector4I; - } - - if (typeOfT == typeof(AABB)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, AABB>) - &ToAabb; - } - - if (typeOfT == typeof(Color)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Color>) - &ToColor; - } - - if (typeOfT == typeof(Plane)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Plane>) - &ToPlane; - } - - if (typeOfT == typeof(Callable)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Callable>) - &ToCallable; - } - - if (typeOfT == typeof(SignalInfo)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, SignalInfo>) - &ToSignalInfo; - } - - if (typeOfT.IsEnum) - { - var enumUnderlyingType = typeOfT.GetEnumUnderlyingType(); - - switch (Type.GetTypeCode(enumUnderlyingType)) - { - case TypeCode.SByte: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, sbyte>) - &ToInt8; - } - case TypeCode.Int16: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, short>) - &ToInt16; - } - case TypeCode.Int32: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int>) - &ToInt32; - } - case TypeCode.Int64: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long>) - &ToInt64; - } - case TypeCode.Byte: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte>) - &ToUInt8; - } - case TypeCode.UInt16: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ushort>) - &ToUInt16; - } - case TypeCode.UInt32: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, uint>) - &ToUInt32; - } - case TypeCode.UInt64: - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>) - &ToUInt64; - } - default: - return null; - } - } - - if (typeOfT == typeof(string)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, string>) - &ToString; - } - - if (typeOfT == typeof(byte[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte[]>) - &ToByteArray; - } - - if (typeOfT == typeof(int[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int[]>) - &ToInt32Array; - } - - if (typeOfT == typeof(long[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long[]>) - &ToInt64Array; - } - - if (typeOfT == typeof(float[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, float[]>) - &ToFloatArray; - } - - if (typeOfT == typeof(double[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, double[]>) - &ToDoubleArray; - } - - if (typeOfT == typeof(string[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, string[]>) - &ToStringArray; - } - - if (typeOfT == typeof(Vector2[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2[]>) - &ToVector2Array; - } - - if (typeOfT == typeof(Vector3[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3[]>) - &ToVector3Array; - } - - if (typeOfT == typeof(Color[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Color[]>) - &ToColorArray; - } - - if (typeOfT == typeof(StringName[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, StringName[]>) - &ToStringNameArray; - } - - if (typeOfT == typeof(NodePath[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, NodePath[]>) - &ToNodePathArray; - } - - if (typeOfT == typeof(RID[])) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, RID[]>) - &ToRidArray; - } - - if (typeof(Godot.Object).IsAssignableFrom(typeOfT)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Object>) - &ToGodotObject; - } - - if (typeOfT == typeof(StringName)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, StringName>) - &ToStringName; - } - - if (typeOfT == typeof(NodePath)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, NodePath>) - &ToNodePath; - } - - if (typeOfT == typeof(RID)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, RID>) - &ToRid; - } - - if (typeOfT == typeof(Godot.Collections.Dictionary)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Collections.Dictionary>) - &ToGodotDictionary; - } - - if (typeOfT == typeof(Godot.Collections.Array)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Collections.Array>) - &ToGodotArray; - } - - if (typeOfT == typeof(Variant)) - { - return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Variant>) - &ToVariant; - } - - // TODO: - // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode. - // We could make the Godot collections implement an interface and use IsAssignableFrom instead. - // Or we could just skip the check and always look for a conversion callback for the type. - if (typeOfT.IsGenericType) - { - var genericTypeDef = typeOfT.GetGenericTypeDefinition(); - - if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) || - genericTypeDef == typeof(Godot.Collections.Array<>)) - { - RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle); - - if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion)) - { - return (delegate*<in godot_variant, T>)genericConversion.FromVariant; - } - } - } - - // ReSharper restore RedundantCast - - return null; - } -} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index 57f9ec7d95..ba8e7a6c65 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -8,7 +8,7 @@ using Godot.Collections; namespace Godot.NativeInterop { - public static class VariantUtils + public static partial class VariantUtils { public static godot_variant CreateFromRID(RID from) => new() { Type = Variant.Type.Rid, RID = from }; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs new file mode 100644 index 0000000000..db84175e17 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs @@ -0,0 +1,406 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Godot.NativeInterop; + +public partial class VariantUtils +{ + private static Exception UnsupportedType<T>() => throw new InvalidOperationException( + $"The type is not supported for conversion to/from Variant: '{typeof(T).FullName}'"); + + internal static class GenericConversion<T> + { + public static unsafe godot_variant ToVariant(in T from) => + ToVariantCb != null ? ToVariantCb(from) : throw UnsupportedType<T>(); + + public static unsafe T FromVariant(in godot_variant variant) => + FromVariantCb != null ? FromVariantCb(variant) : throw UnsupportedType<T>(); + + // ReSharper disable once StaticMemberInGenericType + internal static unsafe delegate*<in T, godot_variant> ToVariantCb; + + // ReSharper disable once StaticMemberInGenericType + internal static unsafe delegate*<in godot_variant, T> FromVariantCb; + + [SuppressMessage("ReSharper", "RedundantNameQualifier")] + static GenericConversion() + { + RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + [SuppressMessage("ReSharper", "RedundantNameQualifier")] + public static godot_variant CreateFrom<[MustBeVariant] T>(in T from) + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static TTo UnsafeAs<TTo>(in T f) => Unsafe.As<T, TTo>(ref Unsafe.AsRef(f)); + + // `typeof(T) == typeof(X)` is optimized away. We cannot cache `typeof(T)` in a local variable, as it's not optimized when done like that. + + if (typeof(T) == typeof(bool)) + return CreateFromBool(UnsafeAs<bool>(from)); + + if (typeof(T) == typeof(char)) + return CreateFromInt(UnsafeAs<char>(from)); + + if (typeof(T) == typeof(sbyte)) + return CreateFromInt(UnsafeAs<sbyte>(from)); + + if (typeof(T) == typeof(short)) + return CreateFromInt(UnsafeAs<short>(from)); + + if (typeof(T) == typeof(int)) + return CreateFromInt(UnsafeAs<int>(from)); + + if (typeof(T) == typeof(long)) + return CreateFromInt(UnsafeAs<long>(from)); + + if (typeof(T) == typeof(byte)) + return CreateFromInt(UnsafeAs<byte>(from)); + + if (typeof(T) == typeof(ushort)) + return CreateFromInt(UnsafeAs<ushort>(from)); + + if (typeof(T) == typeof(uint)) + return CreateFromInt(UnsafeAs<uint>(from)); + + if (typeof(T) == typeof(ulong)) + return CreateFromInt(UnsafeAs<ulong>(from)); + + if (typeof(T) == typeof(float)) + return CreateFromFloat(UnsafeAs<float>(from)); + + if (typeof(T) == typeof(double)) + return CreateFromFloat(UnsafeAs<double>(from)); + + if (typeof(T) == typeof(Vector2)) + return CreateFromVector2(UnsafeAs<Vector2>(from)); + + if (typeof(T) == typeof(Vector2i)) + return CreateFromVector2i(UnsafeAs<Vector2i>(from)); + + if (typeof(T) == typeof(Rect2)) + return CreateFromRect2(UnsafeAs<Rect2>(from)); + + if (typeof(T) == typeof(Rect2i)) + return CreateFromRect2i(UnsafeAs<Rect2i>(from)); + + if (typeof(T) == typeof(Transform2D)) + return CreateFromTransform2D(UnsafeAs<Transform2D>(from)); + + if (typeof(T) == typeof(Vector3)) + return CreateFromVector3(UnsafeAs<Vector3>(from)); + + if (typeof(T) == typeof(Vector3i)) + return CreateFromVector3i(UnsafeAs<Vector3i>(from)); + + if (typeof(T) == typeof(Basis)) + return CreateFromBasis(UnsafeAs<Basis>(from)); + + if (typeof(T) == typeof(Quaternion)) + return CreateFromQuaternion(UnsafeAs<Quaternion>(from)); + + if (typeof(T) == typeof(Transform3D)) + return CreateFromTransform3D(UnsafeAs<Transform3D>(from)); + + if (typeof(T) == typeof(Vector4)) + return CreateFromVector4(UnsafeAs<Vector4>(from)); + + if (typeof(T) == typeof(Vector4i)) + return CreateFromVector4i(UnsafeAs<Vector4i>(from)); + + if (typeof(T) == typeof(AABB)) + return CreateFromAABB(UnsafeAs<AABB>(from)); + + if (typeof(T) == typeof(Color)) + return CreateFromColor(UnsafeAs<Color>(from)); + + if (typeof(T) == typeof(Plane)) + return CreateFromPlane(UnsafeAs<Plane>(from)); + + if (typeof(T) == typeof(Callable)) + return CreateFromCallable(UnsafeAs<Callable>(from)); + + if (typeof(T) == typeof(SignalInfo)) + return CreateFromSignalInfo(UnsafeAs<SignalInfo>(from)); + + if (typeof(T) == typeof(string)) + return CreateFromString(UnsafeAs<string>(from)); + + if (typeof(T) == typeof(byte[])) + return CreateFromPackedByteArray(UnsafeAs<byte[]>(from)); + + if (typeof(T) == typeof(int[])) + return CreateFromPackedInt32Array(UnsafeAs<int[]>(from)); + + if (typeof(T) == typeof(long[])) + return CreateFromPackedInt64Array(UnsafeAs<long[]>(from)); + + if (typeof(T) == typeof(float[])) + return CreateFromPackedFloat32Array(UnsafeAs<float[]>(from)); + + if (typeof(T) == typeof(double[])) + return CreateFromPackedFloat64Array(UnsafeAs<double[]>(from)); + + if (typeof(T) == typeof(string[])) + return CreateFromPackedStringArray(UnsafeAs<string[]>(from)); + + if (typeof(T) == typeof(Vector2[])) + return CreateFromPackedVector2Array(UnsafeAs<Vector2[]>(from)); + + if (typeof(T) == typeof(Vector3[])) + return CreateFromPackedVector3Array(UnsafeAs<Vector3[]>(from)); + + if (typeof(T) == typeof(Color[])) + return CreateFromPackedColorArray(UnsafeAs<Color[]>(from)); + + if (typeof(T) == typeof(StringName[])) + return CreateFromSystemArrayOfStringName(UnsafeAs<StringName[]>(from)); + + if (typeof(T) == typeof(NodePath[])) + return CreateFromSystemArrayOfNodePath(UnsafeAs<NodePath[]>(from)); + + if (typeof(T) == typeof(RID[])) + return CreateFromSystemArrayOfRID(UnsafeAs<RID[]>(from)); + + if (typeof(T) == typeof(StringName)) + return CreateFromStringName(UnsafeAs<StringName>(from)); + + if (typeof(T) == typeof(NodePath)) + return CreateFromNodePath(UnsafeAs<NodePath>(from)); + + if (typeof(T) == typeof(RID)) + return CreateFromRID(UnsafeAs<RID>(from)); + + if (typeof(T) == typeof(Godot.Collections.Dictionary)) + return CreateFromDictionary(UnsafeAs<Godot.Collections.Dictionary>(from)); + + if (typeof(T) == typeof(Godot.Collections.Array)) + return CreateFromArray(UnsafeAs<Godot.Collections.Array>(from)); + + if (typeof(T) == typeof(Variant)) + return NativeFuncs.godotsharp_variant_new_copy((godot_variant)UnsafeAs<Variant>(from).NativeVar); + + // More complex checks here at the end, to avoid screwing the simple ones in case they're not optimized away. + + // `typeof(X).IsAssignableFrom(typeof(T))` is optimized away + + if (typeof(Godot.Object).IsAssignableFrom(typeof(T))) + return CreateFromGodotObject(UnsafeAs<Godot.Object>(from)); + + // `typeof(T).IsValueType` is optimized away + // `typeof(T).IsEnum` is NOT optimized away: https://github.com/dotnet/runtime/issues/67113 + // Fortunately, `typeof(System.Enum).IsAssignableFrom(typeof(T))` does the job! + + if (typeof(T).IsValueType && typeof(System.Enum).IsAssignableFrom(typeof(T))) + { + // `Type.GetTypeCode(typeof(T).GetEnumUnderlyingType())` is not optimized away. + // Fortunately, `Unsafe.SizeOf<T>()` works and is optimized away. + // We don't need to know whether it's signed or unsigned. + + if (Unsafe.SizeOf<T>() == 1) + return CreateFromInt(UnsafeAs<sbyte>(from)); + + if (Unsafe.SizeOf<T>() == 2) + return CreateFromInt(UnsafeAs<short>(from)); + + if (Unsafe.SizeOf<T>() == 4) + return CreateFromInt(UnsafeAs<int>(from)); + + if (Unsafe.SizeOf<T>() == 8) + return CreateFromInt(UnsafeAs<long>(from)); + + throw UnsupportedType<T>(); + } + + return GenericConversion<T>.ToVariant(from); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + [SuppressMessage("ReSharper", "RedundantNameQualifier")] + public static T ConvertTo<[MustBeVariant] T>(in godot_variant variant) + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static T UnsafeAsT<TFrom>(TFrom f) => Unsafe.As<TFrom, T>(ref Unsafe.AsRef(f)); + + if (typeof(T) == typeof(bool)) + return UnsafeAsT(ConvertToBool(variant)); + + if (typeof(T) == typeof(char)) + return UnsafeAsT(ConvertToChar(variant)); + + if (typeof(T) == typeof(sbyte)) + return UnsafeAsT(ConvertToInt8(variant)); + + if (typeof(T) == typeof(short)) + return UnsafeAsT(ConvertToInt16(variant)); + + if (typeof(T) == typeof(int)) + return UnsafeAsT(ConvertToInt32(variant)); + + if (typeof(T) == typeof(long)) + return UnsafeAsT(ConvertToInt64(variant)); + + if (typeof(T) == typeof(byte)) + return UnsafeAsT(ConvertToUInt8(variant)); + + if (typeof(T) == typeof(ushort)) + return UnsafeAsT(ConvertToUInt16(variant)); + + if (typeof(T) == typeof(uint)) + return UnsafeAsT(ConvertToUInt32(variant)); + + if (typeof(T) == typeof(ulong)) + return UnsafeAsT(ConvertToUInt64(variant)); + + if (typeof(T) == typeof(float)) + return UnsafeAsT(ConvertToFloat32(variant)); + + if (typeof(T) == typeof(double)) + return UnsafeAsT(ConvertToFloat64(variant)); + + if (typeof(T) == typeof(Vector2)) + return UnsafeAsT(ConvertToVector2(variant)); + + if (typeof(T) == typeof(Vector2i)) + return UnsafeAsT(ConvertToVector2i(variant)); + + if (typeof(T) == typeof(Rect2)) + return UnsafeAsT(ConvertToRect2(variant)); + + if (typeof(T) == typeof(Rect2i)) + return UnsafeAsT(ConvertToRect2i(variant)); + + if (typeof(T) == typeof(Transform2D)) + return UnsafeAsT(ConvertToTransform2D(variant)); + + if (typeof(T) == typeof(Vector3)) + return UnsafeAsT(ConvertToVector3(variant)); + + if (typeof(T) == typeof(Vector3i)) + return UnsafeAsT(ConvertToVector3i(variant)); + + if (typeof(T) == typeof(Basis)) + return UnsafeAsT(ConvertToBasis(variant)); + + if (typeof(T) == typeof(Quaternion)) + return UnsafeAsT(ConvertToQuaternion(variant)); + + if (typeof(T) == typeof(Transform3D)) + return UnsafeAsT(ConvertToTransform3D(variant)); + + if (typeof(T) == typeof(Vector4)) + return UnsafeAsT(ConvertToVector4(variant)); + + if (typeof(T) == typeof(Vector4i)) + return UnsafeAsT(ConvertToVector4i(variant)); + + if (typeof(T) == typeof(AABB)) + return UnsafeAsT(ConvertToAABB(variant)); + + if (typeof(T) == typeof(Color)) + return UnsafeAsT(ConvertToColor(variant)); + + if (typeof(T) == typeof(Plane)) + return UnsafeAsT(ConvertToPlane(variant)); + + if (typeof(T) == typeof(Callable)) + return UnsafeAsT(ConvertToCallableManaged(variant)); + + if (typeof(T) == typeof(SignalInfo)) + return UnsafeAsT(ConvertToSignalInfo(variant)); + + if (typeof(T) == typeof(string)) + return UnsafeAsT(ConvertToStringObject(variant)); + + if (typeof(T) == typeof(byte[])) + return UnsafeAsT(ConvertAsPackedByteArrayToSystemArray(variant)); + + if (typeof(T) == typeof(int[])) + return UnsafeAsT(ConvertAsPackedInt32ArrayToSystemArray(variant)); + + if (typeof(T) == typeof(long[])) + return UnsafeAsT(ConvertAsPackedInt64ArrayToSystemArray(variant)); + + if (typeof(T) == typeof(float[])) + return UnsafeAsT(ConvertAsPackedFloat32ArrayToSystemArray(variant)); + + if (typeof(T) == typeof(double[])) + return UnsafeAsT(ConvertAsPackedFloat64ArrayToSystemArray(variant)); + + if (typeof(T) == typeof(string[])) + return UnsafeAsT(ConvertAsPackedStringArrayToSystemArray(variant)); + + if (typeof(T) == typeof(Vector2[])) + return UnsafeAsT(ConvertAsPackedVector2ArrayToSystemArray(variant)); + + if (typeof(T) == typeof(Vector3[])) + return UnsafeAsT(ConvertAsPackedVector3ArrayToSystemArray(variant)); + + if (typeof(T) == typeof(Color[])) + return UnsafeAsT(ConvertAsPackedColorArrayToSystemArray(variant)); + + if (typeof(T) == typeof(StringName[])) + return UnsafeAsT(ConvertToSystemArrayOfStringName(variant)); + + if (typeof(T) == typeof(NodePath[])) + return UnsafeAsT(ConvertToSystemArrayOfNodePath(variant)); + + if (typeof(T) == typeof(RID[])) + return UnsafeAsT(ConvertToSystemArrayOfRID(variant)); + + if (typeof(T) == typeof(StringName)) + return UnsafeAsT(ConvertToStringNameObject(variant)); + + if (typeof(T) == typeof(NodePath)) + return UnsafeAsT(ConvertToNodePathObject(variant)); + + if (typeof(T) == typeof(RID)) + return UnsafeAsT(ConvertToRID(variant)); + + if (typeof(T) == typeof(Godot.Collections.Dictionary)) + return UnsafeAsT(ConvertToDictionaryObject(variant)); + + if (typeof(T) == typeof(Godot.Collections.Array)) + return UnsafeAsT(ConvertToArrayObject(variant)); + + if (typeof(T) == typeof(Variant)) + return UnsafeAsT(Variant.CreateCopyingBorrowed(variant)); + + // More complex checks here at the end, to avoid screwing the simple ones in case they're not optimized away. + + // `typeof(X).IsAssignableFrom(typeof(T))` is optimized away + + if (typeof(Godot.Object).IsAssignableFrom(typeof(T))) + return (T)(object)ConvertToGodotObject(variant); + + // `typeof(T).IsValueType` is optimized away + // `typeof(T).IsEnum` is NOT optimized away: https://github.com/dotnet/runtime/issues/67113 + // Fortunately, `typeof(System.Enum).IsAssignableFrom(typeof(T))` does the job! + + if (typeof(T).IsValueType && typeof(System.Enum).IsAssignableFrom(typeof(T))) + { + // `Type.GetTypeCode(typeof(T).GetEnumUnderlyingType())` is not optimized away. + // Fortunately, `Unsafe.SizeOf<T>()` works and is optimized away. + // We don't need to know whether it's signed or unsigned. + + if (Unsafe.SizeOf<T>() == 1) + return UnsafeAsT(ConvertToInt8(variant)); + + if (Unsafe.SizeOf<T>() == 2) + return UnsafeAsT(ConvertToInt16(variant)); + + if (Unsafe.SizeOf<T>() == 4) + return UnsafeAsT(ConvertToInt32(variant)); + + if (Unsafe.SizeOf<T>() == 8) + return UnsafeAsT(ConvertToInt64(variant)); + + throw UnsupportedType<T>(); + } + + return GenericConversion<T>.FromVariant(variant); + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index 371729ebec..8b1b73fcc3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -3,6 +3,14 @@ using System.Runtime.InteropServices; namespace Godot { + /// <summary> + /// A 4x4 matrix used for 3D projective transformations. It can represent transformations such as + /// translation, rotation, scaling, shearing, and perspective division. It consists of four + /// <see cref="Vector4"/> columns. + /// For purely linear transformations (translation, rotation, and scale), it is recommended to use + /// <see cref="Transform3D"/>, as it is more performant and has a lower memory footprint. + /// Used internally as <see cref="Camera3D"/>'s projection matrix. + /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Projection : IEquatable<Projection> @@ -59,48 +67,107 @@ namespace Godot public Vector4 w; /// <summary> - /// Constructs a projection from 4 vectors (matrix columns). + /// Access whole columns in the form of <see cref="Vector4"/>. /// </summary> - /// <param name="x">The X column, or column index 0.</param> - /// <param name="y">The Y column, or column index 1.</param> - /// <param name="z">The Z column, or column index 2.</param> - /// <param name="w">The W column, or column index 3.</param> - public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w) + /// <param name="column">Which column vector.</param> + /// <exception cref="ArgumentOutOfRangeException"> + /// <paramref name="column"/> is not 0, 1, 2 or 3. + /// </exception> + public Vector4 this[int column] { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + readonly get + { + switch (column) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } + set + { + switch (column) + { + case 0: + x = value; + return; + case 1: + y = value; + return; + case 2: + z = value; + return; + case 3: + w = value; + return; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } } /// <summary> - /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>. + /// Access single values. /// </summary> - /// <param name="transform">The <see cref="Transform3D"/>.</param> - public Projection(Transform3D transform) + /// <param name="column">Which column vector.</param> + /// <param name="row">Which row of the column.</param> + /// <exception cref="ArgumentOutOfRangeException"> + /// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3. + /// </exception> + public real_t this[int column, int row] { - x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0); - y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0); - z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0); - w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1); + readonly get + { + switch (column) + { + case 0: + return x[row]; + case 1: + return y[row]; + case 2: + return z[row]; + case 3: + return w[row]; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } + set + { + switch (column) + { + case 0: + x[row] = value; + return; + case 1: + y[row] = value; + return; + case 2: + z[row] = value; + return; + case 3: + w[row] = value; + return; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } } /// <summary> - /// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>. + /// Creates a new <see cref="Projection"/> that projects positions from a depth range of + /// <c>-1</c> to <c>1</c> to one that ranges from <c>0</c> to <c>1</c>, and flips the projected + /// positions vertically, according to <paramref name="flipY"/>. /// </summary> - /// <param name="proj">The <see cref="Projection"/>.</param> - public static explicit operator Transform3D(Projection proj) - { - return new Transform3D( - new Basis( - new Vector3(proj.x.x, proj.x.y, proj.x.z), - new Vector3(proj.y.x, proj.y.y, proj.y.z), - new Vector3(proj.z.x, proj.z.y, proj.z.z) - ), - new Vector3(proj.w.x, proj.w.y, proj.w.z) - ); - } - + /// <param name="flipY">If the projection should be flipped vertically.</param> + /// <returns>The created projection.</returns> public static Projection CreateDepthCorrection(bool flipY) { return new Projection( @@ -111,6 +178,12 @@ namespace Godot ); } + /// <summary> + /// Creates a new <see cref="Projection"/> that scales a given projection to fit around + /// a given <see cref="AABB"/> in projection space. + /// </summary> + /// <param name="aabb">The AABB to fit the projection around.</param> + /// <returns>The created projection.</returns> public static Projection CreateFitAabb(AABB aabb) { Vector3 min = aabb.Position; @@ -124,6 +197,25 @@ namespace Godot ); } + /// <summary> + /// Creates a new <see cref="Projection"/> for projecting positions onto a head-mounted display with + /// the given X:Y aspect ratio, distance between eyes, display width, distance to lens, oversampling factor, + /// and depth clipping planes. + /// <paramref name="eye"/> creates the projection for the left eye when set to 1, + /// or the right eye when set to 2. + /// </summary> + /// <param name="eye"> + /// The eye to create the projection for. + /// The left eye when set to 1, the right eye when set to 2. + /// </param> + /// <param name="aspect">The aspect ratio.</param> + /// <param name="intraocularDist">The distance between the eyes.</param> + /// <param name="displayWidth">The display width.</param> + /// <param name="displayToLens">The distance to the lens.</param> + /// <param name="oversample">The oversampling factor.</param> + /// <param name="zNear">The near clipping distance.</param> + /// <param name="zFar">The far clipping distance.</param> + /// <returns>The created projection.</returns> public static Projection CreateForHmd(int eye, real_t aspect, real_t intraocularDist, real_t displayWidth, real_t displayToLens, real_t oversample, real_t zNear, real_t zFar) { real_t f1 = (intraocularDist * (real_t)0.5) / displayToLens; @@ -148,6 +240,17 @@ namespace Godot } } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions in a frustum with + /// the given clipping planes. + /// </summary> + /// <param name="left">The left clipping distance.</param> + /// <param name="right">The right clipping distance.</param> + /// <param name="bottom">The bottom clipping distance.</param> + /// <param name="top">The top clipping distance.</param> + /// <param name="near">The near clipping distance.</param> + /// <param name="far">The far clipping distance.</param> + /// <returns>The created projection.</returns> public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far) { if (right <= left) @@ -179,6 +282,18 @@ namespace Godot ); } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions in a frustum with + /// the given size, X:Y aspect ratio, offset, and clipping planes. + /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal. + /// </summary> + /// <param name="size">The frustum size.</param> + /// <param name="aspect">The aspect ratio.</param> + /// <param name="offset">The offset to apply.</param> + /// <param name="near">The near clipping distance.</param> + /// <param name="far">The far clipping distance.</param> + /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param> + /// <returns>The created projection.</returns> public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t near, real_t far, bool flipFov) { if (!flipFov) @@ -188,6 +303,11 @@ namespace Godot return CreateFrustum(-size / 2 + offset.x, +size / 2 + offset.x, -size / aspect / 2 + offset.y, +size / aspect / 2 + offset.y, near, far); } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions into the given <see cref="Rect2"/>. + /// </summary> + /// <param name="rect">The Rect2 to project positions into.</param> + /// <returns>The created projection.</returns> public static Projection CreateLightAtlasRect(Rect2 rect) { return new Projection( @@ -198,6 +318,17 @@ namespace Godot ); } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions using an orthogonal projection with + /// the given clipping planes. + /// </summary> + /// <param name="left">The left clipping distance.</param> + /// <param name="right">The right clipping distance.</param> + /// <param name="bottom">The bottom clipping distance.</param> + /// <param name="top">The top clipping distance.</param> + /// <param name="zNear">The near clipping distance.</param> + /// <param name="zFar">The far clipping distance.</param> + /// <returns>The created projection.</returns> public static Projection CreateOrthogonal(real_t left, real_t right, real_t bottom, real_t top, real_t zNear, real_t zFar) { Projection proj = Projection.Identity; @@ -211,6 +342,17 @@ namespace Godot return proj; } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions using an orthogonal projection with + /// the given size, X:Y aspect ratio, and clipping planes. + /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal. + /// </summary> + /// <param name="size">The frustum size.</param> + /// <param name="aspect">The aspect ratio.</param> + /// <param name="zNear">The near clipping distance.</param> + /// <param name="zFar">The far clipping distance.</param> + /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param> + /// <returns>The created projection.</returns> public static Projection CreateOrthogonalAspect(real_t size, real_t aspect, real_t zNear, real_t zFar, bool flipFov) { if (!flipFov) @@ -220,6 +362,17 @@ namespace Godot return CreateOrthogonal(-size / 2, +size / 2, -size / aspect / 2, +size / aspect / 2, zNear, zFar); } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions using a perspective projection with + /// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping planes. + /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal. + /// </summary> + /// <param name="fovyDegrees">The vertical field of view (in degrees).</param> + /// <param name="aspect">The aspect ratio.</param> + /// <param name="zNear">The near clipping distance.</param> + /// <param name="zFar">The far clipping distance.</param> + /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param> + /// <returns>The created projection.</returns> public static Projection CreatePerspective(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov) { if (flipFov) @@ -249,6 +402,27 @@ namespace Godot return proj; } + /// <summary> + /// Creates a new <see cref="Projection"/> that projects positions using a perspective projection with + /// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping distances. + /// The projection is adjusted for a head-mounted display with the given distance between eyes and distance + /// to a point that can be focused on. + /// <paramref name="eye"/> creates the projection for the left eye when set to 1, + /// or the right eye when set to 2. + /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal. + /// </summary> + /// <param name="fovyDegrees">The vertical field of view (in degrees).</param> + /// <param name="aspect">The aspect ratio.</param> + /// <param name="zNear">The near clipping distance.</param> + /// <param name="zFar">The far clipping distance.</param> + /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param> + /// <param name="eye"> + /// The eye to create the projection for. + /// The left eye when set to 1, the right eye when set to 2. + /// </param> + /// <param name="intraocularDist">The distance between the eyes.</param> + /// <param name="convergenceDist">The distance to a point of convergence that can be focused on.</param> + /// <returns>The created projection.</returns> public static Projection CreatePerspectiveHmd(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov, int eye, real_t intraocularDist, real_t convergenceDist) { if (flipFov) @@ -286,6 +460,13 @@ namespace Godot return proj * cm; } + /// <summary> + /// Returns a scalar value that is the signed factor by which areas are scaled by this matrix. + /// If the sign is negative, the matrix flips the orientation of the area. + /// The determinant can be used to calculate the invertibility of a matrix or solve linear systems + /// of equations involving the matrix, among other applications. + /// </summary> + /// <returns>The determinant calculated from this projection.</returns> public readonly real_t Determinant() { return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x - @@ -302,12 +483,20 @@ namespace Godot x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w; } + /// <summary> + /// Returns the X:Y aspect ratio of this <see cref="Projection"/>'s viewport. + /// </summary> + /// <returns>The aspect ratio from this projection's viewport.</returns> public readonly real_t GetAspect() { Vector2 vpHe = GetViewportHalfExtents(); return vpHe.x / vpHe.y; } + /// <summary> + /// Returns the horizontal field of view of the projection (in degrees). + /// </summary> + /// <returns>The horizontal field of view of this projection.</returns> public readonly real_t GetFov() { Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized(); @@ -322,11 +511,22 @@ namespace Godot } } + /// <summary> + /// Returns the vertical field of view of the projection (in degrees) associated with + /// the given horizontal field of view (in degrees) and aspect ratio. + /// </summary> + /// <param name="fovx">The horizontal field of view (in degrees).</param> + /// <param name="aspect">The aspect ratio.</param> + /// <returns>The vertical field of view of this projection.</returns> public static real_t GetFovy(real_t fovx, real_t aspect) { return Mathf.RadToDeg(Mathf.Atan(aspect * Mathf.Tan(Mathf.DegToRad(fovx) * (real_t)0.5)) * (real_t)2.0); } + /// <summary> + /// Returns the factor by which the visible level of detail is scaled by this <see cref="Projection"/>. + /// </summary> + /// <returns>The level of detail factor for this projection.</returns> public readonly real_t GetLodMultiplier() { if (IsOrthogonal()) @@ -341,6 +541,12 @@ namespace Godot } } + /// <summary> + /// Returns the number of pixels with the given pixel width displayed per meter, after + /// this <see cref="Projection"/> is applied. + /// </summary> + /// <param name="forPixelWidth">The width for each pixel (in meters).</param> + /// <returns>The number of pixels per meter.</returns> public readonly int GetPixelsPerMeter(int forPixelWidth) { Vector3 result = this * new Vector3(1, 0, -1); @@ -348,6 +554,15 @@ namespace Godot return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth); } + /// <summary> + /// Returns the clipping plane of this <see cref="Projection"/> whose index is given + /// by <paramref name="plane"/>. + /// <paramref name="plane"/> should be equal to one of <see cref="Planes.Near"/>, + /// <see cref="Planes.Far"/>, <see cref="Planes.Left"/>, <see cref="Planes.Top"/>, + /// <see cref="Planes.Right"/>, or <see cref="Planes.Bottom"/>. + /// </summary> + /// <param name="plane">The kind of clipping plane to get from the projection.</param> + /// <returns>The clipping plane of this projection.</returns> public readonly Plane GetProjectionPlane(Planes plane) { Plane newPlane = plane switch @@ -364,28 +579,49 @@ namespace Godot return newPlane.Normalized(); } + /// <summary> + /// Returns the dimensions of the far clipping plane of the projection, divided by two. + /// </summary> + /// <returns>The half extents for this projection's far plane.</returns> public readonly Vector2 GetFarPlaneHalfExtents() { var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); return new Vector2(res.Value.x, res.Value.y); } + /// <summary> + /// Returns the dimensions of the viewport plane that this <see cref="Projection"/> + /// projects positions onto, divided by two. + /// </summary> + /// <returns>The half extents for this projection's viewport plane.</returns> public readonly Vector2 GetViewportHalfExtents() { var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); return new Vector2(res.Value.x, res.Value.y); } + /// <summary> + /// Returns the distance for this <see cref="Projection"/> beyond which positions are clipped. + /// </summary> + /// <returns>The distance beyond which positions are clipped.</returns> public readonly real_t GetZFar() { return GetProjectionPlane(Planes.Far).D; } + /// <summary> + /// Returns the distance for this <see cref="Projection"/> before which positions are clipped. + /// </summary> + /// <returns>The distance before which positions are clipped.</returns> public readonly real_t GetZNear() { return -GetProjectionPlane(Planes.Near).D; } + /// <summary> + /// Returns a copy of this <see cref="Projection"/> with the signs of the values of the Y column flipped. + /// </summary> + /// <returns>The flipped projection.</returns> public readonly Projection FlippedY() { Projection proj = this; @@ -393,6 +629,13 @@ namespace Godot return proj; } + /// <summary> + /// Returns a <see cref="Projection"/> with the near clipping distance adjusted to be + /// <paramref name="newZNear"/>. + /// Note: The original <see cref="Projection"/> must be a perspective projection. + /// </summary> + /// <param name="newZNear">The near clipping distance to adjust the projection to.</param> + /// <returns>The adjusted projection.</returns> public readonly Projection PerspectiveZNearAdjusted(real_t newZNear) { Projection proj = this; @@ -404,6 +647,12 @@ namespace Godot return proj; } + /// <summary> + /// Returns a <see cref="Projection"/> with the X and Y values from the given <see cref="Vector2"/> + /// added to the first and second values of the final column respectively. + /// </summary> + /// <param name="offset">The offset to apply to the projection.</param> + /// <returns>The offseted projection.</returns> public readonly Projection JitterOffseted(Vector2 offset) { Projection proj = this; @@ -412,6 +661,11 @@ namespace Godot return proj; } + /// <summary> + /// Returns a <see cref="Projection"/> that performs the inverse of this <see cref="Projection"/>'s + /// projective transformation. + /// </summary> + /// <returns>The inverted projection.</returns> public readonly Projection Inverse() { Projection proj = this; @@ -535,11 +789,70 @@ namespace Godot return proj; } + /// <summary> + /// Returns <see langword="true"/> if this <see cref="Projection"/> performs an orthogonal projection. + /// </summary> + /// <returns>If the projection performs an orthogonal projection.</returns> public readonly bool IsOrthogonal() { return w.w == (real_t)1.0; } + // Constants + private static readonly Projection _zero = new Projection( + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0) + ); + private static readonly Projection _identity = new Projection( + new Vector4(1, 0, 0, 0), + new Vector4(0, 1, 0, 0), + new Vector4(0, 0, 1, 0), + new Vector4(0, 0, 0, 1) + ); + + /// <summary> + /// Zero projection, a projection with all components set to <c>0</c>. + /// </summary> + /// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value> + public static Projection Zero { get { return _zero; } } + + /// <summary> + /// The identity projection, with no distortion applied. + /// This is used as a replacement for <c>Projection()</c> in GDScript. + /// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero. + /// </summary> + /// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value> + public static Projection Identity { get { return _identity; } } + + /// <summary> + /// Constructs a projection from 4 vectors (matrix columns). + /// </summary> + /// <param name="x">The X column, or column index 0.</param> + /// <param name="y">The Y column, or column index 1.</param> + /// <param name="z">The Z column, or column index 2.</param> + /// <param name="w">The W column, or column index 3.</param> + public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// <summary> + /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>. + /// </summary> + /// <param name="transform">The <see cref="Transform3D"/>.</param> + public Projection(Transform3D transform) + { + x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0); + y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0); + z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0); + w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1); + } + /// <summary> /// Composes these two projections by multiplying them /// together. This has the effect of applying the right @@ -646,127 +959,41 @@ namespace Godot } /// <summary> - /// Access whole columns in the form of <see cref="Vector4"/>. + /// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>. /// </summary> - /// <param name="column">Which column vector.</param> - /// <exception cref="ArgumentOutOfRangeException"> - /// <paramref name="column"/> is not 0, 1, 2 or 3. - /// </exception> - public Vector4 this[int column] + /// <param name="proj">The <see cref="Projection"/>.</param> + public static explicit operator Transform3D(Projection proj) { - readonly get - { - switch (column) - { - case 0: - return x; - case 1: - return y; - case 2: - return z; - case 3: - return w; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } - set - { - switch (column) - { - case 0: - x = value; - return; - case 1: - y = value; - return; - case 2: - z = value; - return; - case 3: - w = value; - return; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } + return new Transform3D( + new Basis( + new Vector3(proj.x.x, proj.x.y, proj.x.z), + new Vector3(proj.y.x, proj.y.y, proj.y.z), + new Vector3(proj.z.x, proj.z.y, proj.z.z) + ), + new Vector3(proj.w.x, proj.w.y, proj.w.z) + ); } /// <summary> - /// Access single values. + /// Returns <see langword="true"/> if the projection is exactly equal + /// to the given object (<see paramref="obj"/>). /// </summary> - /// <param name="column">Which column vector.</param> - /// <param name="row">Which row of the column.</param> - /// <exception cref="ArgumentOutOfRangeException"> - /// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3. - /// </exception> - public real_t this[int column, int row] + /// <param name="obj">The object to compare with.</param> + /// <returns>Whether or not the vector and the object are equal.</returns> + public override readonly bool Equals(object obj) { - readonly get - { - switch (column) - { - case 0: - return x[row]; - case 1: - return y[row]; - case 2: - return z[row]; - case 3: - return w[row]; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } - set - { - switch (column) - { - case 0: - x[row] = value; - return; - case 1: - y[row] = value; - return; - case 2: - z[row] = value; - return; - case 3: - w[row] = value; - return; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } + return obj is Projection other && Equals(other); } - // Constants - private static readonly Projection _zero = new Projection( - new Vector4(0, 0, 0, 0), - new Vector4(0, 0, 0, 0), - new Vector4(0, 0, 0, 0), - new Vector4(0, 0, 0, 0) - ); - private static readonly Projection _identity = new Projection( - new Vector4(1, 0, 0, 0), - new Vector4(0, 1, 0, 0), - new Vector4(0, 0, 1, 0), - new Vector4(0, 0, 0, 1) - ); - - /// <summary> - /// Zero projection, a projection with all components set to <c>0</c>. - /// </summary> - /// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value> - public static Projection Zero { get { return _zero; } } - /// <summary> - /// The identity projection, with no distortion applied. - /// This is used as a replacement for <c>Projection()</c> in GDScript. - /// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero. + /// Returns <see langword="true"/> if the projections are exactly equal. /// </summary> - /// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value> - public static Projection Identity { get { return _identity; } } + /// <param name="other">The other projection.</param> + /// <returns>Whether or not the projections are exactly equal.</returns> + public readonly bool Equals(Projection other) + { + return x == other.x && y == other.y && z == other.z && w == other.w; + } /// <summary> /// Serves as the hash function for <see cref="Projection"/>. @@ -797,26 +1024,5 @@ namespace Godot $"{z.x.ToString(format)}, {z.y.ToString(format)}, {z.z.ToString(format)}, {z.w.ToString(format)}\n" + $"{w.x.ToString(format)}, {w.y.ToString(format)}, {w.z.ToString(format)}, {w.w.ToString(format)}\n"; } - - /// <summary> - /// Returns <see langword="true"/> if the projection is exactly equal - /// to the given object (<see paramref="obj"/>). - /// </summary> - /// <param name="obj">The object to compare with.</param> - /// <returns>Whether or not the vector and the object are equal.</returns> - public override readonly bool Equals(object obj) - { - return obj is Projection other && Equals(other); - } - - /// <summary> - /// Returns <see langword="true"/> if the projections are exactly equal. - /// </summary> - /// <param name="other">The other projection.</param> - /// <returns>Whether or not the projections are exactly equal.</returns> - public readonly bool Equals(Projection other) - { - return x == other.x && y == other.y && z == other.z && w == other.w; - } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs index d354509dbf..237a4da364 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs @@ -121,6 +121,14 @@ public partial struct Variant : IDisposable } [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant From<[MustBeVariant] T>(in T from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFrom(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T As<[MustBeVariant] T>() => + VariantUtils.ConvertTo<T>(NativeVar.DangerousSelfRef); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AsBool() => VariantUtils.ConvertToBool((godot_variant)NativeVar); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 535391f447..c471eceded 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -240,7 +240,7 @@ namespace Godot /// <summary> /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector - /// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points. + /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points. /// </summary> /// <param name="control1">Control point that defines the bezier curve.</param> /// <param name="control2">Control point that defines the bezier curve.</param> @@ -249,14 +249,28 @@ namespace Godot /// <returns>The interpolated vector.</returns> public readonly Vector2 BezierInterpolate(Vector2 control1, Vector2 control2, Vector2 end, real_t t) { - // Formula from Wikipedia article on Bezier curves - real_t omt = 1 - t; - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; + return new Vector2 + ( + Mathf.BezierInterpolate(x, control1.x, control2.x, end.x, t), + Mathf.BezierInterpolate(y, control1.y, control2.y, end.y, t) + ); + } - return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3; + /// <summary> + /// Returns the derivative at the given <paramref name="t"/> on the Bezier curve defined by this vector + /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points. + /// </summary> + /// <param name="control1">Control point that defines the bezier curve.</param> + /// <param name="control2">Control point that defines the bezier curve.</param> + /// <param name="end">The destination value for the interpolation.</param> + /// <param name="t">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 readonly Vector2 BezierDerivative(Vector2 control1, Vector2 control2, Vector2 end, real_t t) + { + return new Vector2( + Mathf.BezierDerivative(x, control1.x, control2.x, end.x, t), + Mathf.BezierDerivative(y, control1.y, control2.y, end.y, t) + ); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 53bd0b0908..fefdee33a5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -234,7 +234,7 @@ namespace Godot /// <summary> /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector - /// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points. + /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points. /// </summary> /// <param name="control1">Control point that defines the bezier curve.</param> /// <param name="control2">Control point that defines the bezier curve.</param> @@ -243,14 +243,30 @@ namespace Godot /// <returns>The interpolated vector.</returns> public readonly Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t) { - // Formula from Wikipedia article on Bezier curves - real_t omt = 1 - t; - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; + return new Vector3 + ( + Mathf.BezierInterpolate(x, control1.x, control2.x, end.x, t), + Mathf.BezierInterpolate(y, control1.y, control2.y, end.y, t), + Mathf.BezierInterpolate(z, control1.z, control2.z, end.z, t) + ); + } - return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3; + /// <summary> + /// Returns the derivative at the given <paramref name="t"/> on the Bezier curve defined by this vector + /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points. + /// </summary> + /// <param name="control1">Control point that defines the bezier curve.</param> + /// <param name="control2">Control point that defines the bezier curve.</param> + /// <param name="end">The destination value for the interpolation.</param> + /// <param name="t">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 readonly Vector3 BezierDerivative(Vector3 control1, Vector3 control2, Vector3 end, real_t t) + { + return new Vector3( + Mathf.BezierDerivative(x, control1.x, control2.x, end.x, t), + Mathf.BezierDerivative(y, control1.y, control2.y, end.y, t), + Mathf.BezierDerivative(z, control1.z, control2.z, end.y, t) + ); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index e3fb254f49..85f7e36639 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -101,9 +101,9 @@ <Compile Include="Core\NativeInterop\InteropUtils.cs" /> <Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" /> <Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" /> - <Compile Include="Core\NativeInterop\VariantConversionCallbacks.cs" /> <Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" /> <Compile Include="Core\NativeInterop\VariantUtils.cs" /> + <Compile Include="Core\NativeInterop\VariantUtils.generic.cs" /> <Compile Include="Core\NodePath.cs" /> <Compile Include="Core\Object.base.cs" /> <Compile Include="Core\Object.exceptions.cs" /> @@ -123,6 +123,7 @@ <Compile Include="Core\StringName.cs" /> <Compile Include="Core\Transform2D.cs" /> <Compile Include="Core\Transform3D.cs" /> + <Compile Include="Core\Variant.cs" /> <Compile Include="Core\Vector2.cs" /> <Compile Include="Core\Vector2i.cs" /> <Compile Include="Core\Vector3.cs" /> @@ -131,7 +132,6 @@ <Compile Include="Core\Vector4i.cs" /> <Compile Include="GlobalUsings.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Variant.cs" /> </ItemGroup> <!-- We import a props file with auto-generated includes. This works well with Rider. diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp index ee69144123..569030cc11 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/openxr_opengl_extension.cpp @@ -160,16 +160,8 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex } void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) { -#ifdef WIN32 - p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8); - p_usable_swap_chains.push_back(GL_RGBA8); -#elif ANDROID_ENABLED p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8); p_usable_swap_chains.push_back(GL_RGBA8); -#else - p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8_EXT); - p_usable_swap_chains.push_back(GL_RGBA8_EXT); -#endif } void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) { @@ -294,59 +286,7 @@ void OpenXROpenGLExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g String OpenXROpenGLExtension::get_swapchain_format_name(int64_t p_swapchain_format) const { // These are somewhat different per platform, will need to weed some stuff out... switch (p_swapchain_format) { -#ifdef WIN32 - // using definitions from GLAD - ENUM_TO_STRING_CASE(GL_R8_SNORM) - ENUM_TO_STRING_CASE(GL_RG8_SNORM) - ENUM_TO_STRING_CASE(GL_RGB8_SNORM) - ENUM_TO_STRING_CASE(GL_RGBA8_SNORM) - ENUM_TO_STRING_CASE(GL_R16_SNORM) - ENUM_TO_STRING_CASE(GL_RG16_SNORM) - ENUM_TO_STRING_CASE(GL_RGB16_SNORM) - ENUM_TO_STRING_CASE(GL_RGBA16_SNORM) - ENUM_TO_STRING_CASE(GL_RGB4) - ENUM_TO_STRING_CASE(GL_RGB5) - ENUM_TO_STRING_CASE(GL_RGB8) - ENUM_TO_STRING_CASE(GL_RGB10) - ENUM_TO_STRING_CASE(GL_RGB12) - ENUM_TO_STRING_CASE(GL_RGB16) - ENUM_TO_STRING_CASE(GL_RGBA2) - ENUM_TO_STRING_CASE(GL_RGBA4) - ENUM_TO_STRING_CASE(GL_RGB5_A1) - ENUM_TO_STRING_CASE(GL_RGBA8) - ENUM_TO_STRING_CASE(GL_RGB10_A2) - ENUM_TO_STRING_CASE(GL_RGBA12) - ENUM_TO_STRING_CASE(GL_RGBA16) - ENUM_TO_STRING_CASE(GL_RGBA32F) - ENUM_TO_STRING_CASE(GL_RGB32F) - ENUM_TO_STRING_CASE(GL_RGBA16F) - ENUM_TO_STRING_CASE(GL_RGB16F) - ENUM_TO_STRING_CASE(GL_RGBA32UI) - ENUM_TO_STRING_CASE(GL_RGB32UI) - ENUM_TO_STRING_CASE(GL_RGBA16UI) - ENUM_TO_STRING_CASE(GL_RGB16UI) - ENUM_TO_STRING_CASE(GL_RGBA8UI) - ENUM_TO_STRING_CASE(GL_RGB8UI) - ENUM_TO_STRING_CASE(GL_RGBA32I) - ENUM_TO_STRING_CASE(GL_RGB32I) - ENUM_TO_STRING_CASE(GL_RGBA16I) - ENUM_TO_STRING_CASE(GL_RGB16I) - ENUM_TO_STRING_CASE(GL_RGBA8I) - ENUM_TO_STRING_CASE(GL_RGB8I) - ENUM_TO_STRING_CASE(GL_RGB10_A2UI) - ENUM_TO_STRING_CASE(GL_SRGB) - ENUM_TO_STRING_CASE(GL_SRGB8) - ENUM_TO_STRING_CASE(GL_SRGB_ALPHA) - ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8) - ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16) - ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24) - ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32) - ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8) - ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F) - ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32F) - ENUM_TO_STRING_CASE(GL_DEPTH32F_STENCIL8) - -#elif ANDROID_ENABLED +#ifdef ANDROID_ENABLED // using definitions from GLES3/gl3.h ENUM_TO_STRING_CASE(GL_RGBA4) @@ -418,44 +358,56 @@ String OpenXROpenGLExtension::get_swapchain_format_name(int64_t p_swapchain_form ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8) #else - // using definitions from GL/gl.h - ENUM_TO_STRING_CASE(GL_ALPHA4_EXT) - ENUM_TO_STRING_CASE(GL_ALPHA8_EXT) - ENUM_TO_STRING_CASE(GL_ALPHA12_EXT) - ENUM_TO_STRING_CASE(GL_ALPHA16_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE4_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE8_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE12_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE16_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE4_ALPHA4_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE6_ALPHA2_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE8_ALPHA8_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE12_ALPHA4_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE12_ALPHA12_EXT) - ENUM_TO_STRING_CASE(GL_LUMINANCE16_ALPHA16_EXT) - ENUM_TO_STRING_CASE(GL_INTENSITY_EXT) - ENUM_TO_STRING_CASE(GL_INTENSITY4_EXT) - ENUM_TO_STRING_CASE(GL_INTENSITY8_EXT) - ENUM_TO_STRING_CASE(GL_INTENSITY12_EXT) - ENUM_TO_STRING_CASE(GL_INTENSITY16_EXT) - ENUM_TO_STRING_CASE(GL_RGB2_EXT) - ENUM_TO_STRING_CASE(GL_RGB4_EXT) - ENUM_TO_STRING_CASE(GL_RGB5_EXT) - ENUM_TO_STRING_CASE(GL_RGB8_EXT) - ENUM_TO_STRING_CASE(GL_RGB10_EXT) - ENUM_TO_STRING_CASE(GL_RGB12_EXT) - ENUM_TO_STRING_CASE(GL_RGB16_EXT) - ENUM_TO_STRING_CASE(GL_RGBA2_EXT) - ENUM_TO_STRING_CASE(GL_RGBA4_EXT) - ENUM_TO_STRING_CASE(GL_RGB5_A1_EXT) - ENUM_TO_STRING_CASE(GL_RGBA8_EXT) - ENUM_TO_STRING_CASE(GL_RGB10_A2_EXT) - ENUM_TO_STRING_CASE(GL_RGBA12_EXT) - ENUM_TO_STRING_CASE(GL_RGBA16_EXT) - ENUM_TO_STRING_CASE(GL_SRGB_EXT) - ENUM_TO_STRING_CASE(GL_SRGB8_EXT) - ENUM_TO_STRING_CASE(GL_SRGB_ALPHA_EXT) - ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8_EXT) + // using definitions from GLAD + ENUM_TO_STRING_CASE(GL_R8_SNORM) + ENUM_TO_STRING_CASE(GL_RG8_SNORM) + ENUM_TO_STRING_CASE(GL_RGB8_SNORM) + ENUM_TO_STRING_CASE(GL_RGBA8_SNORM) + ENUM_TO_STRING_CASE(GL_R16_SNORM) + ENUM_TO_STRING_CASE(GL_RG16_SNORM) + ENUM_TO_STRING_CASE(GL_RGB16_SNORM) + ENUM_TO_STRING_CASE(GL_RGBA16_SNORM) + ENUM_TO_STRING_CASE(GL_RGB4) + ENUM_TO_STRING_CASE(GL_RGB5) + ENUM_TO_STRING_CASE(GL_RGB8) + ENUM_TO_STRING_CASE(GL_RGB10) + ENUM_TO_STRING_CASE(GL_RGB12) + ENUM_TO_STRING_CASE(GL_RGB16) + ENUM_TO_STRING_CASE(GL_RGBA2) + ENUM_TO_STRING_CASE(GL_RGBA4) + ENUM_TO_STRING_CASE(GL_RGB5_A1) + ENUM_TO_STRING_CASE(GL_RGBA8) + ENUM_TO_STRING_CASE(GL_RGB10_A2) + ENUM_TO_STRING_CASE(GL_RGBA12) + ENUM_TO_STRING_CASE(GL_RGBA16) + ENUM_TO_STRING_CASE(GL_RGBA32F) + ENUM_TO_STRING_CASE(GL_RGB32F) + ENUM_TO_STRING_CASE(GL_RGBA16F) + ENUM_TO_STRING_CASE(GL_RGB16F) + ENUM_TO_STRING_CASE(GL_RGBA32UI) + ENUM_TO_STRING_CASE(GL_RGB32UI) + ENUM_TO_STRING_CASE(GL_RGBA16UI) + ENUM_TO_STRING_CASE(GL_RGB16UI) + ENUM_TO_STRING_CASE(GL_RGBA8UI) + ENUM_TO_STRING_CASE(GL_RGB8UI) + ENUM_TO_STRING_CASE(GL_RGBA32I) + ENUM_TO_STRING_CASE(GL_RGB32I) + ENUM_TO_STRING_CASE(GL_RGBA16I) + ENUM_TO_STRING_CASE(GL_RGB16I) + ENUM_TO_STRING_CASE(GL_RGBA8I) + ENUM_TO_STRING_CASE(GL_RGB8I) + ENUM_TO_STRING_CASE(GL_RGB10_A2UI) + ENUM_TO_STRING_CASE(GL_SRGB) + ENUM_TO_STRING_CASE(GL_SRGB8) + ENUM_TO_STRING_CASE(GL_SRGB_ALPHA) + ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32) + ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8) + ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32F) + ENUM_TO_STRING_CASE(GL_DEPTH32F_STENCIL8) #endif default: { return String("Swapchain format 0x") + String::num_int64(p_swapchain_format, 16); diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h index b666653c8e..473c5157c0 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.h +++ b/modules/openxr/extensions/openxr_opengl_extension.h @@ -59,9 +59,8 @@ #include OPENGL_INCLUDE_H #define GL_GLEXT_PROTOTYPES 1 #define GL3_PROTOTYPES 1 -#include <GL/gl.h> -#include <GL/glext.h> -#include <GL/glx.h> +#include "thirdparty/glad/glad/gl.h" +#include "thirdparty/glad/glad/glx.h" #include <X11/Xlib.h> #endif diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index b7c95415d0..d6580ebfa6 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -64,9 +64,8 @@ #include OPENGL_INCLUDE_H #define GL_GLEXT_PROTOTYPES 1 #define GL3_PROTOTYPES 1 -#include <GL/gl.h> -#include <GL/glext.h> -#include <GL/glx.h> +#include "thirdparty/glad/glad/gl.h" +#include "thirdparty/glad/glad/glx.h" #include <X11/Xlib.h> #endif // X11_ENABLED #endif // GLES_ENABLED diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py index e31d88b741..527e02f855 100644 --- a/modules/raycast/godot_update_embree.py +++ b/modules/raycast/godot_update_embree.py @@ -1,5 +1,7 @@ import glob, os, shutil, subprocess, re +git_tag = "v3.13.5" + include_dirs = [ "common/tasking", "kernels/bvh", @@ -12,6 +14,7 @@ include_dirs = [ "common/lexers", "common/simd", "common/simd/arm", + "common/simd/wasm", "include/embree3", "kernels/subdiv", "kernels/geometry", @@ -76,6 +79,7 @@ if os.path.exists(dir_name): subprocess.run(["git", "clone", "https://github.com/embree/embree.git", "embree-tmp"]) os.chdir("embree-tmp") +subprocess.run(["git", "checkout", git_tag]) commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip() @@ -94,8 +98,7 @@ for f in all_files: with open(os.path.join(dest_dir, "kernels/hash.h"), "w") as hash_file: hash_file.write( - f""" -// Copyright 2009-2020 Intel Corporation + f"""// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #define RTC_HASH "{commit_hash}" @@ -104,8 +107,7 @@ with open(os.path.join(dest_dir, "kernels/hash.h"), "w") as hash_file: with open(os.path.join(dest_dir, "kernels/config.h"), "w") as config_file: config_file.write( - """ -// Copyright 2009-2020 Intel Corporation + """// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 /* #undef EMBREE_RAY_MASK */ @@ -126,6 +128,7 @@ with open(os.path.join(dest_dir, "kernels/config.h"), "w") as config_file: /* #undef EMBREE_COMPACT_POLYS */ #define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0 +#define EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE #if defined(EMBREE_GEOMETRY_TRIANGLE) #define IF_ENABLED_TRIS(x) x @@ -192,8 +195,7 @@ with open("CMakeLists.txt", "r") as cmake_file: with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as config_file: config_file.write( - f""" -// Copyright 2009-2021 Intel Corporation + f"""// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -209,14 +211,16 @@ with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as con #define EMBREE_MIN_WIDTH 0 #define RTC_MIN_WIDTH EMBREE_MIN_WIDTH -#define EMBREE_STATIC_LIB -/* #undef EMBREE_API_NAMESPACE */ +#if !defined(EMBREE_STATIC_LIB) +# define EMBREE_STATIC_LIB +#endif +/* #undef EMBREE_API_NAMESPACE*/ #if defined(EMBREE_API_NAMESPACE) # define RTC_NAMESPACE -# define RTC_NAMESPACE_BEGIN namespace {{ +# define RTC_NAMESPACE_BEGIN namespace {{ # define RTC_NAMESPACE_END }} -# define RTC_NAMESPACE_USE using namespace ; +# define RTC_NAMESPACE_USE using namespace; # define RTC_API_EXTERN_C # undef EMBREE_API_NAMESPACE #else |