diff options
Diffstat (limited to 'modules')
35 files changed, 632 insertions, 205 deletions
diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp index 8167fe8c73..ab20d00b5b 100644 --- a/modules/basis_universal/image_compress_basisu.cpp +++ b/modules/basis_universal/image_compress_basisu.cpp @@ -84,14 +84,12 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha decompress_format = BASIS_DECOMPRESS_RGBA; } break; case Image::USED_CHANNELS_R: { - decompress_format = BASIS_DECOMPRESS_RGB; + decompress_format = BASIS_DECOMPRESS_R; } break; case Image::USED_CHANNELS_RG: { - // Currently RG textures are compressed as DXT5/ETC2_RGBA8 with a RA -> RG swizzle, - // as BasisUniversal didn't use to support ETC2_RG11 transcoding. params.m_force_alpha = true; image->convert_rg_to_ra_rgba8(); - decompress_format = BASIS_DECOMPRESS_RG_AS_RA; + decompress_format = BASIS_DECOMPRESS_RG; } break; case Image::USED_CHANNELS_RGB: { decompress_format = BASIS_DECOMPRESS_RGB; @@ -219,15 +217,68 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { // Get supported compression formats. bool bptc_supported = RS::get_singleton()->has_os_feature("bptc"); bool astc_supported = RS::get_singleton()->has_os_feature("astc"); + bool rgtc_supported = RS::get_singleton()->has_os_feature("rgtc"); bool s3tc_supported = RS::get_singleton()->has_os_feature("s3tc"); bool etc2_supported = RS::get_singleton()->has_os_feature("etc2"); bool needs_ra_rg_swap = false; + bool needs_rg_trim = false; + + BasisDecompressFormat decompress_format = (BasisDecompressFormat)(*(uint32_t *)(src_ptr)); - switch (*(uint32_t *)(src_ptr)) { + switch (decompress_format) { + case BASIS_DECOMPRESS_R: { + if (rgtc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC4_R; + image_format = Image::FORMAT_RGTC_R; + } else if (s3tc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC1; + image_format = Image::FORMAT_DXT1; + } else if (etc2_supported) { + basisu_format = basist::transcoder_texture_format::cTFETC2_EAC_R11; + image_format = Image::FORMAT_ETC2_R11; + } else { + // No supported VRAM compression formats, decompress. + basisu_format = basist::transcoder_texture_format::cTFRGBA32; + image_format = Image::FORMAT_RGBA8; + needs_rg_trim = true; + } + + } break; case BASIS_DECOMPRESS_RG: { - // RGTC transcoding is currently performed with RG_AS_RA, fail. - ERR_FAIL_V(image); + if (rgtc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC5_RG; + image_format = Image::FORMAT_RGTC_RG; + } else if (s3tc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC3; + image_format = Image::FORMAT_DXT5_RA_AS_RG; + } else if (etc2_supported) { + basisu_format = basist::transcoder_texture_format::cTFETC2_EAC_RG11; + image_format = Image::FORMAT_ETC2_RG11; + } else { + // No supported VRAM compression formats, decompress. + basisu_format = basist::transcoder_texture_format::cTFRGBA32; + image_format = Image::FORMAT_RGBA8; + needs_ra_rg_swap = true; + needs_rg_trim = true; + } + + } break; + case BASIS_DECOMPRESS_RG_AS_RA: { + if (s3tc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC3; + image_format = Image::FORMAT_DXT5_RA_AS_RG; + } else if (etc2_supported) { + basisu_format = basist::transcoder_texture_format::cTFETC2; + image_format = Image::FORMAT_ETC2_RA_AS_RG; + } else { + // No supported VRAM compression formats, decompress. + basisu_format = basist::transcoder_texture_format::cTFRGBA32; + image_format = Image::FORMAT_RGBA8; + needs_ra_rg_swap = true; + needs_rg_trim = true; + } + } break; case BASIS_DECOMPRESS_RGB: { if (bptc_supported) { @@ -267,20 +318,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { basisu_format = basist::transcoder_texture_format::cTFRGBA32; image_format = Image::FORMAT_RGBA8; } - } break; - case BASIS_DECOMPRESS_RG_AS_RA: { - if (s3tc_supported) { - basisu_format = basist::transcoder_texture_format::cTFBC3; - image_format = Image::FORMAT_DXT5_RA_AS_RG; - } else if (etc2_supported) { - basisu_format = basist::transcoder_texture_format::cTFETC2; - image_format = Image::FORMAT_ETC2_RA_AS_RG; - } else { - // No supported VRAM compression formats, decompress. - basisu_format = basist::transcoder_texture_format::cTFRGBA32; - image_format = Image::FORMAT_RGBA8; - needs_ra_rg_swap = true; - } + } break; } @@ -324,6 +362,15 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { image->convert_ra_rgba8_to_rg(); } + if (needs_rg_trim) { + // Remove unnecessary color channels from uncompressed textures. + if (decompress_format == BASIS_DECOMPRESS_R) { + image->convert(Image::FORMAT_R8); + } else if (decompress_format == BASIS_DECOMPRESS_RG || decompress_format == BASIS_DECOMPRESS_RG_AS_RA) { + image->convert(Image::FORMAT_RG8); + } + } + return image; } diff --git a/modules/basis_universal/image_compress_basisu.h b/modules/basis_universal/image_compress_basisu.h index ac5d62ae73..5e36d448f6 100644 --- a/modules/basis_universal/image_compress_basisu.h +++ b/modules/basis_universal/image_compress_basisu.h @@ -38,6 +38,7 @@ enum BasisDecompressFormat { BASIS_DECOMPRESS_RGB, BASIS_DECOMPRESS_RGBA, BASIS_DECOMPRESS_RG_AS_RA, + BASIS_DECOMPRESS_R, }; void basis_universal_init(); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 8777651545..8c81c0ce4e 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -513,7 +513,7 @@ Ref<ConcavePolygonShape3D> CSGShape3D::bake_collision_shape() { } bool CSGShape3D::_is_debug_collision_shape_visible() { - return is_inside_tree() && (get_tree()->is_debugging_collisions_hint() || Engine::get_singleton()->is_editor_hint()); + return !Engine::get_singleton()->is_editor_hint() && is_inside_tree() && get_tree()->is_debugging_collisions_hint(); } void CSGShape3D::_update_debug_collision_shape() { @@ -604,11 +604,6 @@ void CSGShape3D::_notification(int p_what) { // Update this node's parent only if its own visibility has changed, not the visibility of parent nodes parent_shape->_make_dirty(); } - if (is_visible()) { - _update_debug_collision_shape(); - } else { - _clear_debug_collision_shape(); - } last_visible = is_visible(); } break; diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 72676f4a40..3712441e51 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -541,7 +541,7 @@ EditorPluginCSG::EditorPluginCSG() { Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); csg_shape_editor = memnew(CSGShapeEditor); - EditorNode::get_singleton()->get_main_screen_control()->add_child(csg_shape_editor); + EditorNode::get_singleton()->get_gui_base()->add_child(csg_shape_editor); } #endif // TOOLS_ENABLED diff --git a/modules/fbx/fbx_document.cpp b/modules/fbx/fbx_document.cpp index 8d4d0234da..ce097092fb 100644 --- a/modules/fbx/fbx_document.cpp +++ b/modules/fbx/fbx_document.cpp @@ -288,14 +288,8 @@ String FBXDocument::_gen_unique_name(HashSet<String> &unique_names, const String } String FBXDocument::_sanitize_animation_name(const String &p_name) { - // Animations disallow the normal node invalid characters as well as "," and "[" - // (See animation/animation_player.cpp::add_animation) - - // TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node. String anim_name = p_name.validate_node_name(); - anim_name = anim_name.replace(",", ""); - anim_name = anim_name.replace("[", ""); - return anim_name; + return AnimationLibrary::validate_library_name(anim_name); } String FBXDocument::_gen_unique_animation_name(Ref<FBXState> p_state, const String &p_name) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 524f528f76..cf1cd55355 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -3486,10 +3486,10 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c opt = opt.substr(1); } - // The path needs quotes if at least one of its components (excluding `/` separations) + // The path needs quotes if at least one of its components (excluding `%` prefix and `/` separations) // is not a valid identifier. bool path_needs_quote = false; - for (const String &part : opt.split("/")) { + for (const String &part : opt.trim_prefix("%").split("/")) { if (!part.is_valid_ascii_identifier()) { path_needs_quote = true; break; diff --git a/modules/gdscript/gdscript_tokenizer_buffer.cpp b/modules/gdscript/gdscript_tokenizer_buffer.cpp index e53bc5bc41..2046480f0e 100644 --- a/modules/gdscript/gdscript_tokenizer_buffer.cpp +++ b/modules/gdscript/gdscript_tokenizer_buffer.cpp @@ -296,6 +296,7 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code, encode_uint32(identifier_map.size(), &contents.write[0]); encode_uint32(constant_map.size(), &contents.write[4]); encode_uint32(token_lines.size(), &contents.write[8]); + encode_uint32(0, &contents.write[12]); // Unused, kept for compatibility. Please remove at next `TOKENIZER_VERSION` increment. encode_uint32(token_counter, &contents.write[16]); int buf_pos = 20; diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_unique.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_unique.cfg new file mode 100644 index 0000000000..36c150f6e3 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_unique.cfg @@ -0,0 +1,9 @@ +[input] +scene="res://completion/get_node/get_node.tscn" +[output] +include=[ + {"display": "%UniqueA"}, +] +exclude=[ + {"display": "\"%UniqueA\""}, +] diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_unique.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_unique.gd new file mode 100644 index 0000000000..def050e938 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_unique.gd @@ -0,0 +1,5 @@ +extends Node + +func a(): + $➡ + pass diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 4653df7afe..cf1a1ea4b3 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -491,14 +491,8 @@ String GLTFDocument::_gen_unique_name(Ref<GLTFState> p_state, const String &p_na } String GLTFDocument::_sanitize_animation_name(const String &p_name) { - // Animations disallow the normal node invalid characters as well as "," and "[" - // (See animation/animation_player.cpp::add_animation) - - // TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node. String anim_name = p_name.validate_node_name(); - anim_name = anim_name.replace(",", ""); - anim_name = anim_name.replace("[", ""); - return anim_name; + return AnimationLibrary::validate_library_name(anim_name); } String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name) { diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index ea63e07104..6b010335e6 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/input/input.h" #include "core/os/keyboard.h" +#include "editor/editor_main_screen.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/editor_string_names.h" @@ -958,7 +959,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { _update_selection_transform(); _update_paste_indicator(); - spatial_editor = Object::cast_to<Node3DEditorPlugin>(EditorNode::get_singleton()->get_editor_plugin_screen()); + spatial_editor = Object::cast_to<Node3DEditorPlugin>(EditorNode::get_singleton()->get_editor_main_screen()->get_selected_plugin()); if (!node) { set_process(false); diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 394213963a..e29fe9295a 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -159,6 +159,9 @@ Ref<AudioSamplePlayback> AudioStreamPlaybackMP3::get_sample_playback() const { void AudioStreamPlaybackMP3::set_sample_playback(const Ref<AudioSamplePlayback> &p_playback) { sample_playback = p_playback; + if (sample_playback.is_valid()) { + sample_playback->stream_playback = Ref<AudioStreamPlayback>(this); + } } void AudioStreamPlaybackMP3::set_parameter(const StringName &p_name, const Variant &p_value) { diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 2ec073e4fa..3222c58c4e 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -3448,6 +3448,12 @@ StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metada case GodotTypeInfo::METADATA_INT_IS_UINT64: return "ulong"; break; + case GodotTypeInfo::METADATA_INT_IS_CHAR16: + return "char"; + break; + case GodotTypeInfo::METADATA_INT_IS_CHAR32: + // To prevent breaking compatibility, C# bindings need to keep using `long`. + return "long"; default: // Assume INT64 return "long"; diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 7322a47630..df240a5965 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -41,6 +41,7 @@ #include "core/os/os.h" #include "core/version.h" #include "editor/debugger/editor_debugger_node.h" +#include "editor/editor_main_screen.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_settings.h" @@ -165,7 +166,7 @@ bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line, } void godot_icall_Internal_EditorNodeShowScriptScreen() { - EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT); + EditorNode::get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT); } void godot_icall_Internal_EditorRunPlay() { diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 3935854a29..039263b405 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -192,8 +192,14 @@ private: } } if (!has_data) { - // 3. Extract the data to a temporary location to load from there. - Ref<DirAccess> da = DirAccess::create_for_path(packed_path); + // 3. Extract the data to a temporary location to load from there, delete old data if it exists but is not up-to-date. + Ref<DirAccess> da; + if (DirAccess::exists(data_dir_root)) { + da = DirAccess::open(data_dir_root); + ERR_FAIL_COND(da.is_null()); + ERR_FAIL_COND(da->erase_contents_recursive() != OK); + } + da = DirAccess::create_for_path(packed_path); ERR_FAIL_COND(da.is_null()); ERR_FAIL_COND(da->copy_dir(packed_path, data_dir_root) != OK); } diff --git a/modules/navigation/2d/godot_navigation_server_2d.cpp b/modules/navigation/2d/godot_navigation_server_2d.cpp index bf69adc14c..2af125d434 100644 --- a/modules/navigation/2d/godot_navigation_server_2d.cpp +++ b/modules/navigation/2d/godot_navigation_server_2d.cpp @@ -318,6 +318,11 @@ int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid); Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int); Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int); +Vector2 GodotNavigationServer2D::region_get_closest_point(RID p_region, const Vector2 &p_point) const { + Vector3 result = NavigationServer3D::get_singleton()->region_get_closest_point(p_region, v2_to_v3(p_point)); + return v3_to_v2(result); +} + Vector2 GodotNavigationServer2D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const { Vector3 result = NavigationServer3D::get_singleton()->region_get_random_point(p_region, p_navigation_layers, p_uniformly); return v3_to_v2(result); diff --git a/modules/navigation/2d/godot_navigation_server_2d.h b/modules/navigation/2d/godot_navigation_server_2d.h index ea77fa5e6e..1579ca2907 100644 --- a/modules/navigation/2d/godot_navigation_server_2d.h +++ b/modules/navigation/2d/godot_navigation_server_2d.h @@ -101,6 +101,7 @@ public: virtual int region_get_connections_count(RID p_region) const override; virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; + virtual Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const override; virtual Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override; virtual RID link_create() override; diff --git a/modules/navigation/3d/godot_navigation_server_3d.cpp b/modules/navigation/3d/godot_navigation_server_3d.cpp index 11a5de608b..5dfc39f6f5 100644 --- a/modules/navigation/3d/godot_navigation_server_3d.cpp +++ b/modules/navigation/3d/godot_navigation_server_3d.cpp @@ -536,6 +536,27 @@ Vector3 GodotNavigationServer3D::region_get_connection_pathway_end(RID p_region, return Vector3(); } +Vector3 GodotNavigationServer3D::region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const { + const NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL_V(region, Vector3()); + + return region->get_closest_point_to_segment(p_from, p_to, p_use_collision); +} + +Vector3 GodotNavigationServer3D::region_get_closest_point(RID p_region, const Vector3 &p_point) const { + const NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL_V(region, Vector3()); + + return region->get_closest_point_info(p_point).point; +} + +Vector3 GodotNavigationServer3D::region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const { + const NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL_V(region, Vector3()); + + return region->get_closest_point_info(p_point).normal; +} + Vector3 GodotNavigationServer3D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const { const NavRegion *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL_V(region, Vector3()); diff --git a/modules/navigation/3d/godot_navigation_server_3d.h b/modules/navigation/3d/godot_navigation_server_3d.h index 12a1132f07..eae6ea2860 100644 --- a/modules/navigation/3d/godot_navigation_server_3d.h +++ b/modules/navigation/3d/godot_navigation_server_3d.h @@ -178,6 +178,9 @@ public: virtual int region_get_connections_count(RID p_region) const override; virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; + virtual Vector3 region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const override; + virtual Vector3 region_get_closest_point(RID p_region, const Vector3 &p_point) const override; + virtual Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const override; virtual Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override; virtual RID link_create() override; diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp index f37ed9b168..7f0cbc7b5e 100644 --- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp @@ -176,7 +176,7 @@ void NavigationMeshEditorPlugin::make_visible(bool p_visible) { NavigationMeshEditorPlugin::NavigationMeshEditorPlugin() { navigation_mesh_editor = memnew(NavigationMeshEditor); - EditorNode::get_singleton()->get_main_screen_control()->add_child(navigation_mesh_editor); + EditorNode::get_singleton()->get_gui_base()->add_child(navigation_mesh_editor); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, navigation_mesh_editor->bake_hbox); navigation_mesh_editor->hide(); navigation_mesh_editor->bake_hbox->hide(); diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp index 7a44adecbc..2c91b80af2 100644 --- a/modules/navigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -105,7 +105,22 @@ void NavRegion::set_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) { polygons_dirty = true; } +Vector3 NavRegion::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const { + RWLockRead read_lock(region_rwlock); + + return NavMeshQueries3D::polygons_get_closest_point_to_segment( + get_polygons(), p_from, p_to, p_use_collision); +} + +gd::ClosestPointQueryResult NavRegion::get_closest_point_info(const Vector3 &p_point) const { + RWLockRead read_lock(region_rwlock); + + return NavMeshQueries3D::polygons_get_closest_point_info(get_polygons(), p_point); +} + Vector3 NavRegion::get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const { + RWLockRead read_lock(region_rwlock); + if (!get_enabled()) { return Vector3(); } @@ -114,6 +129,8 @@ Vector3 NavRegion::get_random_point(uint32_t p_navigation_layers, bool p_uniform } bool NavRegion::sync() { + RWLockWrite write_lock(region_rwlock); + bool something_changed = polygons_dirty /* || something_dirty? */; update_polygons(); diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index 662a32c47a..c015802b92 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -38,6 +38,8 @@ #include "scene/resources/navigation_mesh.h" class NavRegion : public NavBase { + RWLock region_rwlock; + NavMap *map = nullptr; Transform3D transform; bool enabled = true; @@ -88,6 +90,8 @@ public: return polygons; } + Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const; + gd::ClosestPointQueryResult get_closest_point_info(const Vector3 &p_point) const; Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const; real_t get_surface_area() const { return surface_area; }; diff --git a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml index 6f4ac00f3e..341b50065c 100644 --- a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml +++ b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml @@ -10,6 +10,13 @@ <tutorials> </tutorials> <methods> + <method name="get_android_surface"> + <return type="JavaObject" /> + <description> + Returns a [JavaObject] representing an [code]android.view.Surface[/code] if [member use_android_surface] is enabled and OpenXR has created the surface. Otherwise, this will return [code]null[/code]. + [b]Note:[/b] The surface can only be created during an active OpenXR session. So, if [member use_android_surface] is enabled outside of an OpenXR session, it won't be created until a new session fully starts. + </description> + </method> <method name="intersects_ray" qualifiers="const"> <return type="Vector2" /> <param index="0" name="origin" type="Vector3" /> @@ -32,6 +39,9 @@ Enables the blending the layer using its alpha channel. Can be combined with [member Viewport.transparent_bg] to give the layer a transparent background. </member> + <member name="android_surface_size" type="Vector2i" setter="set_android_surface_size" getter="get_android_surface_size" default="Vector2i(1024, 1024)"> + The size of the Android surface to create if [member use_android_surface] is enabled. + </member> <member name="enable_hole_punch" type="bool" setter="set_enable_hole_punch" getter="get_enable_hole_punch" default="false"> Enables a technique called "hole punching", which allows putting the composition layer behind the main projection layer (i.e. setting [member sort_order] to a negative value) while "punching a hole" through everything rendered by Godot so that the layer is still visible. This can be used to create the illusion that the composition layer exists in the same 3D space as everything rendered by Godot, allowing objects to appear to pass both behind or in front of the composition layer. @@ -43,5 +53,10 @@ The sort order for this composition layer. Higher numbers will be shown in front of lower numbers. [b]Note:[/b] This will have no effect if a fallback mesh is being used. </member> + <member name="use_android_surface" type="bool" setter="set_use_android_surface" getter="get_use_android_surface" default="false"> + If enabled, an Android surface will be created (with the dimensions from [member android_surface_size]) which will provide the 2D content for the composition layer, rather than using [member layer_viewport]. + See [method get_android_surface] for information about how to get the surface so that your application can draw to it. + [b]Note:[/b] This will only work in Android builds. + </member> </members> </class> diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp index 8a448afc08..83e45ffe7f 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp @@ -30,6 +30,12 @@ #include "openxr_composition_layer_extension.h" +#ifdef ANDROID_ENABLED +#include <openxr/openxr.h> +#include <openxr/openxr_platform.h> +#endif + +#include "platform/android/api/java_class_wrapper.h" #include "servers/rendering/rendering_server_globals.h" //////////////////////////////////////////////////////////////////////////// @@ -55,18 +61,37 @@ HashMap<String, bool *> OpenXRCompositionLayerExtension::get_requested_extension request_extensions[XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME] = &cylinder_ext_available; request_extensions[XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME] = &equirect_ext_available; +#ifdef ANDROID_ENABLED + request_extensions[XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME] = &android_surface_ext_available; +#endif + return request_extensions; } +void OpenXRCompositionLayerExtension::on_instance_created(const XrInstance p_instance) { +#ifdef ANDROID_ENABLED + EXT_INIT_XR_FUNC(xrDestroySwapchain); + EXT_INIT_XR_FUNC(xrCreateSwapchainAndroidSurfaceKHR); +#endif +} + void OpenXRCompositionLayerExtension::on_session_created(const XrSession p_session) { OpenXRAPI::get_singleton()->register_composition_layer_provider(this); } void OpenXRCompositionLayerExtension::on_session_destroyed() { OpenXRAPI::get_singleton()->unregister_composition_layer_provider(this); + +#ifdef ANDROID_ENABLED + free_queued_android_surface_swapchains(); +#endif } void OpenXRCompositionLayerExtension::on_pre_render() { +#ifdef ANDROID_ENABLED + free_queued_android_surface_swapchains(); +#endif + for (OpenXRViewportCompositionLayerProvider *composition_layer : composition_layers) { composition_layer->on_pre_render(); } @@ -113,6 +138,37 @@ bool OpenXRCompositionLayerExtension::is_available(XrStructureType p_which) { } } +#ifdef ANDROID_ENABLED +bool OpenXRCompositionLayerExtension::create_android_surface_swapchain(XrSwapchainCreateInfo *p_info, XrSwapchain *r_swapchain, jobject *r_surface) { + if (android_surface_ext_available) { + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL_V(openxr_api, false); + + // @todo We need a way to add to the next pointer chain. + XrResult result = xrCreateSwapchainAndroidSurfaceKHR(openxr_api->get_session(), p_info, r_swapchain, r_surface); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create Android surface swapchain [", openxr_api->get_error_string(result), "]"); + return false; + } + + return true; + } + + return false; +} + +void OpenXRCompositionLayerExtension::free_android_surface_swapchain(XrSwapchain p_swapchain) { + android_surface_swapchain_free_queue.push_back(p_swapchain); +} + +void OpenXRCompositionLayerExtension::free_queued_android_surface_swapchains() { + for (XrSwapchain swapchain : android_surface_swapchain_free_queue) { + xrDestroySwapchain(swapchain); + } + android_surface_swapchain_free_queue.clear(); +} +#endif + //////////////////////////////////////////////////////////////////////////// // OpenXRViewportCompositionLayerProvider @@ -127,8 +183,12 @@ OpenXRViewportCompositionLayerProvider::~OpenXRViewportCompositionLayerProvider( extension->on_viewport_composition_layer_destroyed(composition_layer); } - // This will reset the viewport and free the swapchain too. - set_viewport(RID(), Size2i()); + if (use_android_surface) { + free_swapchain(); + } else { + // This will reset the viewport and free the swapchain too. + set_viewport(RID(), Size2i()); + } } void OpenXRViewportCompositionLayerProvider::set_alpha_blend(bool p_alpha_blend) { @@ -143,24 +203,92 @@ void OpenXRViewportCompositionLayerProvider::set_alpha_blend(bool p_alpha_blend) } void OpenXRViewportCompositionLayerProvider::set_viewport(RID p_viewport, Size2i p_size) { + ERR_FAIL_COND(use_android_surface); + RenderingServer *rs = RenderingServer::get_singleton(); ERR_FAIL_NULL(rs); - if (viewport != p_viewport) { - if (viewport.is_valid()) { - RID rt = rs->viewport_get_render_target(viewport); + if (subviewport.viewport != p_viewport) { + if (subviewport.viewport.is_valid()) { + RID rt = rs->viewport_get_render_target(subviewport.viewport); RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID()); } - viewport = p_viewport; + subviewport.viewport = p_viewport; - if (viewport.is_valid()) { - viewport_size = p_size; + if (subviewport.viewport.is_valid()) { + subviewport.viewport_size = p_size; } else { free_swapchain(); - viewport_size = Size2i(); + subviewport.viewport_size = Size2i(); + } + } +} + +void OpenXRViewportCompositionLayerProvider::set_use_android_surface(bool p_use_android_surface, Size2i p_size) { +#ifdef ANDROID_ENABLED + if (p_use_android_surface == use_android_surface) { + return; + } + + use_android_surface = p_use_android_surface; + + if (use_android_surface) { + if (!composition_layer_extension->is_android_surface_swapchain_available()) { + ERR_PRINT_ONCE("OpenXR: Cannot use Android surface for composition layer because the extension isn't available"); } + + if (subviewport.viewport.is_valid()) { + set_viewport(RID(), Size2i()); + } + + swapchain_size = p_size; + } else { + free_swapchain(); + } +#endif +} + +#ifdef ANDROID_ENABLED +void OpenXRViewportCompositionLayerProvider::create_android_surface() { + ERR_FAIL_COND(android_surface.swapchain != XR_NULL_HANDLE || android_surface.surface.is_valid()); + ERR_FAIL_COND(!openxr_api || !openxr_api->is_running()); + + // The XR_FB_android_surface_swapchain_create extension mandates that format, sampleCount, + // faceCount, arraySize, and mipCount must be zero. + XrSwapchainCreateInfo info = { + XR_TYPE_SWAPCHAIN_CREATE_INFO, // type + nullptr, // next + 0, // createFlags + XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, // usageFlags + 0, // format + 0, // sampleCount + (uint32_t)swapchain_size.x, // width + (uint32_t)swapchain_size.y, // height + 0, // faceCount + 0, // arraySize + 0, // mipCount + }; + + jobject surface; + composition_layer_extension->create_android_surface_swapchain(&info, &android_surface.swapchain, &surface); + + if (surface) { + android_surface.surface = Ref<JavaObject>(memnew(JavaObject(JavaClassWrapper::get_singleton()->wrap("android.view.Surface"), surface))); + } +} +#endif + +Ref<JavaObject> OpenXRViewportCompositionLayerProvider::get_android_surface() { +#ifdef ANDROID_ENABLED + if (use_android_surface) { + if (android_surface.surface.is_null()) { + create_android_surface(); + } + return android_surface.surface; } +#endif + return Ref<JavaObject>(); } void OpenXRViewportCompositionLayerProvider::set_extension_property_values(const Dictionary &p_extension_property_values) { @@ -169,16 +297,25 @@ void OpenXRViewportCompositionLayerProvider::set_extension_property_values(const } void OpenXRViewportCompositionLayerProvider::on_pre_render() { +#ifdef ANDROID_ENABLED + if (use_android_surface) { + if (android_surface.surface.is_null()) { + create_android_surface(); + } + return; + } +#endif + RenderingServer *rs = RenderingServer::get_singleton(); ERR_FAIL_NULL(rs); - if (viewport.is_valid() && openxr_api && openxr_api->is_running()) { - RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(viewport); + if (subviewport.viewport.is_valid() && openxr_api && openxr_api->is_running()) { + RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(subviewport.viewport); if (update_mode == RS::VIEWPORT_UPDATE_ONCE || update_mode == RS::VIEWPORT_UPDATE_ALWAYS) { // Update our XR swapchain if (update_and_acquire_swapchain(update_mode == RS::VIEWPORT_UPDATE_ONCE)) { // Render to our XR swapchain image. - RID rt = rs->viewport_get_render_target(viewport); + RID rt = rs->viewport_get_render_target(subviewport.viewport); RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID()); } } @@ -196,48 +333,36 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos return nullptr; } - if (swapchain_info.get_swapchain() == XR_NULL_HANDLE) { + XrSwapchainSubImage subimage = { + 0, // swapchain + { { 0, 0 }, { 0, 0 } }, // imageRect + 0, // imageArrayIndex + }; + update_swapchain_sub_image(subimage); + + if (subimage.swapchain == XR_NULL_HANDLE) { // Don't have a swapchain to display? Ignore our layer. return nullptr; } - if (swapchain_info.is_image_acquired()) { - swapchain_info.release(); - } - // Update the layer struct for the swapchain. switch (composition_layer->type) { case XR_TYPE_COMPOSITION_LAYER_QUAD: { XrCompositionLayerQuad *quad_layer = (XrCompositionLayerQuad *)composition_layer; quad_layer->space = openxr_api->get_play_space(); - quad_layer->subImage.swapchain = swapchain_info.get_swapchain(); - quad_layer->subImage.imageArrayIndex = 0; - quad_layer->subImage.imageRect.offset.x = 0; - quad_layer->subImage.imageRect.offset.y = 0; - quad_layer->subImage.imageRect.extent.width = swapchain_size.width; - quad_layer->subImage.imageRect.extent.height = swapchain_size.height; + quad_layer->subImage = subimage; } break; case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: { XrCompositionLayerCylinderKHR *cylinder_layer = (XrCompositionLayerCylinderKHR *)composition_layer; cylinder_layer->space = openxr_api->get_play_space(); - cylinder_layer->subImage.swapchain = swapchain_info.get_swapchain(); - cylinder_layer->subImage.imageArrayIndex = 0; - cylinder_layer->subImage.imageRect.offset.x = 0; - cylinder_layer->subImage.imageRect.offset.y = 0; - cylinder_layer->subImage.imageRect.extent.width = swapchain_size.width; - cylinder_layer->subImage.imageRect.extent.height = swapchain_size.height; + cylinder_layer->subImage = subimage; } break; case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: { XrCompositionLayerEquirect2KHR *equirect_layer = (XrCompositionLayerEquirect2KHR *)composition_layer; equirect_layer->space = openxr_api->get_play_space(); - equirect_layer->subImage.swapchain = swapchain_info.get_swapchain(); - equirect_layer->subImage.imageArrayIndex = 0; - equirect_layer->subImage.imageRect.offset.x = 0; - equirect_layer->subImage.imageRect.offset.y = 0; - equirect_layer->subImage.imageRect.extent.width = swapchain_size.width; - equirect_layer->subImage.imageRect.extent.height = swapchain_size.height; + equirect_layer->subImage = subimage; } break; default: { @@ -261,27 +386,49 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos return composition_layer; } +void OpenXRViewportCompositionLayerProvider::update_swapchain_sub_image(XrSwapchainSubImage &r_subimage) { +#ifdef ANDROID_ENABLED + if (use_android_surface) { + r_subimage.swapchain = android_surface.swapchain; + } else +#endif + { + XrSwapchain swapchain = subviewport.swapchain_info.get_swapchain(); + + if (swapchain && subviewport.swapchain_info.is_image_acquired()) { + subviewport.swapchain_info.release(); + } + + r_subimage.swapchain = swapchain; + } + + r_subimage.imageRect.extent.width = swapchain_size.width; + r_subimage.imageRect.extent.height = swapchain_size.height; +} + bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p_static_image) { + ERR_FAIL_COND_V(use_android_surface, false); + if (openxr_api == nullptr || composition_layer_extension == nullptr) { // OpenXR not initialized or we're in the editor? return false; } - if (!composition_layer_extension->is_available(composition_layer->type)) { + if (!composition_layer_extension->is_available(get_openxr_type())) { // Selected type is not supported? return false; } // See if our current swapchain is outdated. - if (swapchain_info.get_swapchain() != XR_NULL_HANDLE) { + if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) { // If this swap chain, or the previous one, were static, then we can't reuse it. - if (swapchain_size == viewport_size && !p_static_image && !static_image) { + if (swapchain_size == subviewport.viewport_size && !p_static_image && !subviewport.static_image) { // We're all good! Just acquire it. // We can ignore should_render here, return will be false. bool should_render = true; - return swapchain_info.acquire(should_render); + return subviewport.swapchain_info.acquire(should_render); } - swapchain_info.queue_free(); + subviewport.swapchain_info.queue_free(); } // Create our new swap chain @@ -292,7 +439,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p if (p_static_image) { create_flags |= XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT; } - if (!swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, viewport_size.width, viewport_size.height, sample_count, array_size)) { + if (!subviewport.swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, subviewport.viewport_size.width, subviewport.viewport_size.height, sample_count, array_size)) { swapchain_size = Size2i(); return false; } @@ -300,26 +447,40 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p // Acquire our image so we can start rendering into it, // we can ignore should_render here, ret will be false. bool should_render = true; - bool ret = swapchain_info.acquire(should_render); + bool ret = subviewport.swapchain_info.acquire(should_render); - swapchain_size = viewport_size; - static_image = p_static_image; + swapchain_size = subviewport.viewport_size; + subviewport.static_image = p_static_image; return ret; } void OpenXRViewportCompositionLayerProvider::free_swapchain() { - if (swapchain_info.get_swapchain() != XR_NULL_HANDLE) { - swapchain_info.queue_free(); +#ifdef ANDROID_ENABLED + if (use_android_surface) { + if (android_surface.swapchain != XR_NULL_HANDLE) { + composition_layer_extension->free_android_surface_swapchain(android_surface.swapchain); + + android_surface.swapchain = XR_NULL_HANDLE; + android_surface.surface.unref(); + } + } else +#endif + { + if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) { + subviewport.swapchain_info.queue_free(); + } + subviewport.static_image = false; } swapchain_size = Size2i(); - static_image = false; } RID OpenXRViewportCompositionLayerProvider::get_current_swapchain_texture() { + ERR_FAIL_COND_V(use_android_surface, RID()); + if (openxr_api == nullptr) { return RID(); } - return swapchain_info.get_image(); + return subviewport.swapchain_info.get_image(); } diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.h b/modules/openxr/extensions/openxr_composition_layer_extension.h index 34e330a60a..bce34f098c 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.h +++ b/modules/openxr/extensions/openxr_composition_layer_extension.h @@ -36,6 +36,15 @@ #include "../openxr_api.h" +#ifdef ANDROID_ENABLED +#include <jni.h> + +// Copied here from openxr_platform.h, in order to avoid including that whole header, +// which can cause compilation issues on some platforms. +typedef XrResult(XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo *info, XrSwapchain *swapchain, jobject *surface); +#endif + +class JavaObject; class OpenXRViewportCompositionLayerProvider; // This extension provides access to composition layers for displaying 2D content through the XR compositor. @@ -49,6 +58,7 @@ public: virtual ~OpenXRCompositionLayerExtension() override; virtual HashMap<String, bool *> get_requested_extensions() override; + virtual void on_instance_created(const XrInstance p_instance) override; virtual void on_session_created(const XrSession p_session) override; virtual void on_session_destroyed() override; virtual void on_pre_render() override; @@ -61,6 +71,12 @@ public: void unregister_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); bool is_available(XrStructureType p_which); + bool is_android_surface_swapchain_available() { return android_surface_ext_available; } + +#ifdef ANDROID_ENABLED + bool create_android_surface_swapchain(XrSwapchainCreateInfo *p_info, XrSwapchain *r_swapchain, jobject *r_surface); + void free_android_surface_swapchain(XrSwapchain p_swapchain); +#endif private: static OpenXRCompositionLayerExtension *singleton; @@ -69,6 +85,15 @@ private: bool cylinder_ext_available = false; bool equirect_ext_available = false; + bool android_surface_ext_available = false; + +#ifdef ANDROID_ENABLED + Vector<XrSwapchain> android_surface_swapchain_free_queue; + void free_queued_android_surface_swapchains(); + + EXT_PROTO_XRRESULT_FUNC1(xrDestroySwapchain, (XrSwapchain), swapchain) + EXT_PROTO_XRRESULT_FUNC4(xrCreateSwapchainAndroidSurfaceKHR, (XrSession), session, (const XrSwapchainCreateInfo *), info, (XrSwapchain *), swapchain, (jobject *), surface) +#endif }; class OpenXRViewportCompositionLayerProvider { @@ -78,20 +103,37 @@ class OpenXRViewportCompositionLayerProvider { Dictionary extension_property_values; bool extension_property_values_changed = true; - RID viewport; - Size2i viewport_size; - - OpenXRAPI::OpenXRSwapChainInfo swapchain_info; + struct { + RID viewport; + Size2i viewport_size; + OpenXRAPI::OpenXRSwapChainInfo swapchain_info; + bool static_image = false; + } subviewport; + +#ifdef ANDROID_ENABLED + struct { + XrSwapchain swapchain = XR_NULL_HANDLE; + Ref<JavaObject> surface; + } android_surface; +#endif + + bool use_android_surface = false; Size2i swapchain_size; - bool static_image = false; OpenXRAPI *openxr_api = nullptr; OpenXRCompositionLayerExtension *composition_layer_extension = nullptr; + // Only for SubViewports. bool update_and_acquire_swapchain(bool p_static_image); - void free_swapchain(); RID get_current_swapchain_texture(); + void update_swapchain_sub_image(XrSwapchainSubImage &r_swapchain_sub_image); + void free_swapchain(); + +#ifdef ANDROID_ENABLED + void create_android_surface(); +#endif + public: XrStructureType get_openxr_type() { return composition_layer->type; } @@ -102,7 +144,12 @@ public: bool get_alpha_blend() const { return alpha_blend; } void set_viewport(RID p_viewport, Size2i p_size); - RID get_viewport() const { return viewport; } + RID get_viewport() const { return subviewport.viewport; } + + void set_use_android_surface(bool p_enable, Size2i p_size); + bool get_use_android_surface() const { return use_android_surface; } + + Ref<JavaObject> get_android_surface(); void set_extension_property_values(const Dictionary &p_property_values); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index a19a75e722..73b6f6c1c9 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -273,7 +273,9 @@ Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers; bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) { if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) { - return GLOBAL_GET("xr/openxr/enabled.editor"); + // For now, don't start OpenXR when the editor starts up. In the future, this may change + // if we want to integrate more XR features into the editor experience. + return false; } else { return GLOBAL_GET("xr/openxr/enabled"); } diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp index f69a907be9..697369d516 100644 --- a/modules/openxr/scene/openxr_composition_layer.cpp +++ b/modules/openxr/scene/openxr_composition_layer.cpp @@ -38,6 +38,8 @@ #include "scene/3d/xr_nodes.h" #include "scene/main/viewport.h" +#include "platform/android/api/java_class_wrapper.h" + Vector<OpenXRCompositionLayer *> OpenXRCompositionLayer::composition_layer_nodes; static const char *HOLE_PUNCH_SHADER_CODE = @@ -47,7 +49,10 @@ static const char *HOLE_PUNCH_SHADER_CODE = "\tALBEDO = vec3(0.0, 0.0, 0.0);\n" "}\n"; -OpenXRCompositionLayer::OpenXRCompositionLayer() { +OpenXRCompositionLayer::OpenXRCompositionLayer(XrCompositionLayerBaseHeader *p_composition_layer) { + composition_layer_base_header = p_composition_layer; + openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider(composition_layer_base_header)); + openxr_api = OpenXRAPI::get_singleton(); composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton(); @@ -85,6 +90,12 @@ void OpenXRCompositionLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer_viewport", "viewport"), &OpenXRCompositionLayer::set_layer_viewport); ClassDB::bind_method(D_METHOD("get_layer_viewport"), &OpenXRCompositionLayer::get_layer_viewport); + ClassDB::bind_method(D_METHOD("set_use_android_surface", "enable"), &OpenXRCompositionLayer::set_use_android_surface); + ClassDB::bind_method(D_METHOD("get_use_android_surface"), &OpenXRCompositionLayer::get_use_android_surface); + + ClassDB::bind_method(D_METHOD("set_android_surface_size", "size"), &OpenXRCompositionLayer::set_android_surface_size); + ClassDB::bind_method(D_METHOD("get_android_surface_size"), &OpenXRCompositionLayer::get_android_surface_size); + ClassDB::bind_method(D_METHOD("set_enable_hole_punch", "enable"), &OpenXRCompositionLayer::set_enable_hole_punch); ClassDB::bind_method(D_METHOD("get_enable_hole_punch"), &OpenXRCompositionLayer::get_enable_hole_punch); @@ -94,11 +105,14 @@ void OpenXRCompositionLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_alpha_blend", "enabled"), &OpenXRCompositionLayer::set_alpha_blend); ClassDB::bind_method(D_METHOD("get_alpha_blend"), &OpenXRCompositionLayer::get_alpha_blend); + ClassDB::bind_method(D_METHOD("get_android_surface"), &OpenXRCompositionLayer::get_android_surface); ClassDB::bind_method(D_METHOD("is_natively_supported"), &OpenXRCompositionLayer::is_natively_supported); ClassDB::bind_method(D_METHOD("intersects_ray", "origin", "direction"), &OpenXRCompositionLayer::intersects_ray); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_android_surface", PROPERTY_HINT_NONE, ""), "set_use_android_surface", "get_use_android_surface"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "android_surface_size", PROPERTY_HINT_NONE, ""), "set_android_surface_size", "get_android_surface_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_hole_punch", PROPERTY_HINT_NONE, ""), "set_enable_hole_punch", "get_enable_hole_punch"); @@ -108,7 +122,7 @@ bool OpenXRCompositionLayer::_should_use_fallback_node() { if (Engine::get_singleton()->is_editor_hint()) { return true; } else if (openxr_session_running) { - return enable_hole_punch || !is_natively_supported(); + return enable_hole_punch || (!is_natively_supported() && !use_android_surface); } return false; } @@ -128,10 +142,36 @@ void OpenXRCompositionLayer::_remove_fallback_node() { fallback = nullptr; } +void OpenXRCompositionLayer::_setup_composition_layer_provider() { + if (use_android_surface || layer_viewport) { + if (composition_layer_extension) { + composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider); + } + + // NOTE: We don't setup/clear when using Android surfaces, so we don't destroy the surface unexpectedly. + if (layer_viewport) { + // Set our properties on the layer provider, which will create all the necessary resources (ex swap chains). + openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); + } + } +} + +void OpenXRCompositionLayer::_clear_composition_layer_provider() { + if (composition_layer_extension) { + composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider); + } + + // NOTE: We don't setup/clear when using Android surfaces, so we don't destroy the surface unexpectedly. + if (!use_android_surface) { + // This will reset the viewport and free all the resources (ex swap chains) used by the layer. + openxr_layer_provider->set_viewport(RID(), Size2i()); + } +} + void OpenXRCompositionLayer::_on_openxr_session_begun() { openxr_session_running = true; - if (layer_viewport && is_natively_supported() && is_visible() && is_inside_tree()) { - openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); + if (is_natively_supported() && is_visible() && is_inside_tree()) { + _setup_composition_layer_provider(); } if (!fallback && _should_use_fallback_node()) { _create_fallback_node(); @@ -142,9 +182,8 @@ void OpenXRCompositionLayer::_on_openxr_session_stopping() { openxr_session_running = false; if (fallback && !_should_use_fallback_node()) { _remove_fallback_node(); - } else { - openxr_layer_provider->set_viewport(RID(), Size2i()); } + _clear_composition_layer_provider(); } void OpenXRCompositionLayer::update_fallback_mesh() { @@ -162,6 +201,7 @@ XrPosef OpenXRCompositionLayer::get_openxr_pose() { } bool OpenXRCompositionLayer::is_viewport_in_use(SubViewport *p_viewport) { + ERR_FAIL_NULL_V(p_viewport, false); for (const OpenXRCompositionLayer *other_composition_layer : composition_layer_nodes) { if (other_composition_layer != this && other_composition_layer->is_inside_tree() && other_composition_layer->get_layer_viewport() == p_viewport) { return true; @@ -178,6 +218,9 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) { if (p_viewport != nullptr) { ERR_FAIL_COND_EDMSG(is_viewport_in_use(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first.")); } + if (use_android_surface) { + ERR_FAIL_COND_MSG(p_viewport != nullptr, RTR("Cannot set SubViewport on an OpenXR composition layer when using an Android surface.")); + } layer_viewport = p_viewport; @@ -200,6 +243,41 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) { } } +void OpenXRCompositionLayer::set_use_android_surface(bool p_use_android_surface) { + if (use_android_surface == p_use_android_surface) { + return; + } + + use_android_surface = p_use_android_surface; + if (use_android_surface) { + set_layer_viewport(nullptr); + openxr_layer_provider->set_use_android_surface(true, android_surface_size); + } else { + openxr_layer_provider->set_use_android_surface(false, Size2i()); + } + + notify_property_list_changed(); +} + +bool OpenXRCompositionLayer::get_use_android_surface() const { + return use_android_surface; +} + +void OpenXRCompositionLayer::set_android_surface_size(Size2i p_size) { + if (android_surface_size == p_size) { + return; + } + + android_surface_size = p_size; + if (use_android_surface) { + openxr_layer_provider->set_use_android_surface(true, android_surface_size); + } +} + +Size2i OpenXRCompositionLayer::get_android_surface_size() const { + return android_surface_size; +} + SubViewport *OpenXRCompositionLayer::get_layer_viewport() const { return layer_viewport; } @@ -228,33 +306,23 @@ bool OpenXRCompositionLayer::get_enable_hole_punch() const { } void OpenXRCompositionLayer::set_sort_order(int p_order) { - if (openxr_layer_provider) { - openxr_layer_provider->set_sort_order(p_order); - update_configuration_warnings(); - } + openxr_layer_provider->set_sort_order(p_order); + update_configuration_warnings(); } int OpenXRCompositionLayer::get_sort_order() const { - if (openxr_layer_provider) { - return openxr_layer_provider->get_sort_order(); - } - return 1; + return openxr_layer_provider->get_sort_order(); } void OpenXRCompositionLayer::set_alpha_blend(bool p_alpha_blend) { - if (openxr_layer_provider) { - openxr_layer_provider->set_alpha_blend(p_alpha_blend); - if (fallback) { - _reset_fallback_material(); - } + openxr_layer_provider->set_alpha_blend(p_alpha_blend); + if (fallback) { + _reset_fallback_material(); } } bool OpenXRCompositionLayer::get_alpha_blend() const { - if (openxr_layer_provider) { - return openxr_layer_provider->get_alpha_blend(); - } - return false; + return openxr_layer_provider->get_alpha_blend(); } bool OpenXRCompositionLayer::is_natively_supported() const { @@ -264,6 +332,10 @@ bool OpenXRCompositionLayer::is_natively_supported() const { return false; } +Ref<JavaObject> OpenXRCompositionLayer::get_android_surface() { + return openxr_layer_provider->get_android_surface(); +} + Vector2 OpenXRCompositionLayer::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const { return Vector2(-1.0, -1.0); } @@ -301,10 +373,7 @@ void OpenXRCompositionLayer::_reset_fallback_material() { Ref<ViewportTexture> texture = material->get_texture(StandardMaterial3D::TEXTURE_ALBEDO); if (texture.is_null()) { - texture.instantiate(); - // ViewportTexture can't be configured without a local scene, so use this hack to set it. - HashMap<Ref<Resource>, Ref<Resource>> remap_cache; - texture->configure_for_local_scene(this, remap_cache); + texture = layer_viewport->get_texture(); } Node *loc_scene = texture->get_local_scene(); @@ -321,12 +390,10 @@ void OpenXRCompositionLayer::_notification(int p_what) { case NOTIFICATION_POSTINITIALIZE: { composition_layer_nodes.push_back(this); - if (openxr_layer_provider) { - for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { - extension_property_values.merge(extension->get_viewport_composition_layer_extension_property_defaults()); - } - openxr_layer_provider->set_extension_property_values(extension_property_values); + for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { + extension_property_values.merge(extension->get_viewport_composition_layer_extension_property_defaults()); } + openxr_layer_provider->set_extension_property_values(extension_property_values); } break; case NOTIFICATION_INTERNAL_PROCESS: { if (fallback) { @@ -339,10 +406,10 @@ void OpenXRCompositionLayer::_notification(int p_what) { } break; case NOTIFICATION_VISIBILITY_CHANGED: { if (!fallback && openxr_session_running && is_inside_tree()) { - if (layer_viewport && is_visible()) { - openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); + if (is_visible()) { + _setup_composition_layer_provider(); } else { - openxr_layer_provider->set_viewport(RID(), Size2i()); + _clear_composition_layer_provider(); } } update_configuration_warnings(); @@ -351,25 +418,15 @@ void OpenXRCompositionLayer::_notification(int p_what) { update_configuration_warnings(); } break; case NOTIFICATION_ENTER_TREE: { - if (composition_layer_extension) { - composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider); - } - - if (is_viewport_in_use(layer_viewport)) { - set_layer_viewport(nullptr); - } else if (!fallback && layer_viewport && openxr_session_running && is_visible()) { - openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size()); + if (layer_viewport && is_viewport_in_use(layer_viewport)) { + _clear_composition_layer_provider(); + } else if (openxr_session_running && is_visible()) { + _setup_composition_layer_provider(); } } break; case NOTIFICATION_EXIT_TREE: { - if (composition_layer_extension) { - composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider); - } - - if (!fallback) { - // This will clean up existing resources. - openxr_layer_provider->set_viewport(RID(), Size2i()); - } + // This will clean up existing resources. + _clear_composition_layer_provider(); } break; } } @@ -401,13 +458,27 @@ bool OpenXRCompositionLayer::_get(const StringName &p_property, Variant &r_value bool OpenXRCompositionLayer::_set(const StringName &p_property, const Variant &p_value) { extension_property_values[p_property] = p_value; - if (openxr_layer_provider) { - openxr_layer_provider->set_extension_property_values(extension_property_values); - } + openxr_layer_provider->set_extension_property_values(extension_property_values); return true; } +void OpenXRCompositionLayer::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "layer_viewport") { + if (use_android_surface) { + p_property.usage &= ~PROPERTY_USAGE_EDITOR; + } else { + p_property.usage |= PROPERTY_USAGE_EDITOR; + } + } else if (p_property.name == "android_surface_size") { + if (use_android_surface) { + p_property.usage |= PROPERTY_USAGE_EDITOR; + } else { + p_property.usage &= ~PROPERTY_USAGE_EDITOR; + } + } +} + PackedStringArray OpenXRCompositionLayer::get_configuration_warnings() const { PackedStringArray warnings = Node3D::get_configuration_warnings(); diff --git a/modules/openxr/scene/openxr_composition_layer.h b/modules/openxr/scene/openxr_composition_layer.h index 55cae27d23..26b40236d2 100644 --- a/modules/openxr/scene/openxr_composition_layer.h +++ b/modules/openxr/scene/openxr_composition_layer.h @@ -35,6 +35,7 @@ #include "scene/3d/node_3d.h" +class JavaObject; class MeshInstance3D; class Mesh; class OpenXRAPI; @@ -45,7 +46,12 @@ class SubViewport; class OpenXRCompositionLayer : public Node3D { GDCLASS(OpenXRCompositionLayer, Node3D); + XrCompositionLayerBaseHeader *composition_layer_base_header = nullptr; + OpenXRViewportCompositionLayerProvider *openxr_layer_provider = nullptr; + SubViewport *layer_viewport = nullptr; + bool use_android_surface = false; + Size2i android_surface_size = Size2i(1024, 1024); bool enable_hole_punch = false; MeshInstance3D *fallback = nullptr; bool should_update_fallback_mesh = false; @@ -58,10 +64,12 @@ class OpenXRCompositionLayer : public Node3D { void _reset_fallback_material(); void _remove_fallback_node(); + void _setup_composition_layer_provider(); + void _clear_composition_layer_provider(); + protected: OpenXRAPI *openxr_api = nullptr; OpenXRCompositionLayerExtension *composition_layer_extension = nullptr; - OpenXRViewportCompositionLayerProvider *openxr_layer_provider = nullptr; static void _bind_methods(); @@ -69,6 +77,7 @@ protected: void _get_property_list(List<PropertyInfo> *p_property_list) const; bool _get(const StringName &p_property, Variant &r_value) const; bool _set(const StringName &p_property, const Variant &p_value); + void _validate_property(PropertyInfo &p_property) const; virtual void _on_openxr_session_begun(); virtual void _on_openxr_session_stopping(); @@ -82,10 +91,18 @@ protected: static Vector<OpenXRCompositionLayer *> composition_layer_nodes; bool is_viewport_in_use(SubViewport *p_viewport); + OpenXRCompositionLayer(XrCompositionLayerBaseHeader *p_composition_layer); + public: void set_layer_viewport(SubViewport *p_viewport); SubViewport *get_layer_viewport() const; + void set_use_android_surface(bool p_use_android_surface); + bool get_use_android_surface() const; + + void set_android_surface_size(Size2i p_size); + Size2i get_android_surface_size() const; + void set_enable_hole_punch(bool p_enable); bool get_enable_hole_punch() const; @@ -95,13 +112,13 @@ public: void set_alpha_blend(bool p_alpha_blend); bool get_alpha_blend() const; + Ref<JavaObject> get_android_surface(); bool is_natively_supported() const; virtual PackedStringArray get_configuration_warnings() const override; virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const; - OpenXRCompositionLayer(); ~OpenXRCompositionLayer(); }; diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp index 6c8d2fc885..727586467a 100644 --- a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp +++ b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp @@ -38,20 +38,8 @@ #include "scene/main/viewport.h" #include "scene/resources/mesh.h" -OpenXRCompositionLayerCylinder::OpenXRCompositionLayerCylinder() { - composition_layer = { - XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, // type - nullptr, // next - 0, // layerFlags - XR_NULL_HANDLE, // space - XR_EYE_VISIBILITY_BOTH, // eyeVisibility - {}, // subImage - { { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose - radius, // radius - central_angle, // centralAngle - aspect_ratio, // aspectRatio - }; - openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer)); +OpenXRCompositionLayerCylinder::OpenXRCompositionLayerCylinder() : + OpenXRCompositionLayer((XrCompositionLayerBaseHeader *)&composition_layer) { XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerCylinder::update_transform)); } diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.h b/modules/openxr/scene/openxr_composition_layer_cylinder.h index 9bd5a42d36..a701575972 100644 --- a/modules/openxr/scene/openxr_composition_layer_cylinder.h +++ b/modules/openxr/scene/openxr_composition_layer_cylinder.h @@ -38,7 +38,18 @@ class OpenXRCompositionLayerCylinder : public OpenXRCompositionLayer { GDCLASS(OpenXRCompositionLayerCylinder, OpenXRCompositionLayer); - XrCompositionLayerCylinderKHR composition_layer; + XrCompositionLayerCylinderKHR composition_layer = { + XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, // type + nullptr, // next + 0, // layerFlags + XR_NULL_HANDLE, // space + XR_EYE_VISIBILITY_BOTH, // eyeVisibility + {}, // subImage + { { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose + 1.0, // radius + Math_PI / 2.0, // centralAngle + 1.0, // aspectRatio + }; float radius = 1.0; float aspect_ratio = 1.0; diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.cpp b/modules/openxr/scene/openxr_composition_layer_equirect.cpp index b6f5d27ffe..2fce26c965 100644 --- a/modules/openxr/scene/openxr_composition_layer_equirect.cpp +++ b/modules/openxr/scene/openxr_composition_layer_equirect.cpp @@ -38,21 +38,8 @@ #include "scene/main/viewport.h" #include "scene/resources/mesh.h" -OpenXRCompositionLayerEquirect::OpenXRCompositionLayerEquirect() { - composition_layer = { - XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, // type - nullptr, // next - 0, // layerFlags - XR_NULL_HANDLE, // space - XR_EYE_VISIBILITY_BOTH, // eyeVisibility - {}, // subImage - { { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose - radius, // radius - central_horizontal_angle, // centralHorizontalAngle - upper_vertical_angle, // upperVerticalAngle - -lower_vertical_angle, // lowerVerticalAngle - }; - openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer)); +OpenXRCompositionLayerEquirect::OpenXRCompositionLayerEquirect() : + OpenXRCompositionLayer((XrCompositionLayerBaseHeader *)&composition_layer) { XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerEquirect::update_transform)); } diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.h b/modules/openxr/scene/openxr_composition_layer_equirect.h index af6cd92cbe..45a65fe5aa 100644 --- a/modules/openxr/scene/openxr_composition_layer_equirect.h +++ b/modules/openxr/scene/openxr_composition_layer_equirect.h @@ -38,7 +38,19 @@ class OpenXRCompositionLayerEquirect : public OpenXRCompositionLayer { GDCLASS(OpenXRCompositionLayerEquirect, OpenXRCompositionLayer); - XrCompositionLayerEquirect2KHR composition_layer; + XrCompositionLayerEquirect2KHR composition_layer = { + XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, // type + nullptr, // next + 0, // layerFlags + XR_NULL_HANDLE, // space + XR_EYE_VISIBILITY_BOTH, // eyeVisibility + {}, // subImage + { { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose + 1.0, // radius + Math_PI / 2.0, // centralHorizontalAngle + Math_PI / 4.0, // upperVerticalAngle + -Math_PI / 4.0, // lowerVerticalAngle + }; float radius = 1.0; float central_horizontal_angle = Math_PI / 2.0; diff --git a/modules/openxr/scene/openxr_composition_layer_quad.cpp b/modules/openxr/scene/openxr_composition_layer_quad.cpp index 21919496d6..4a00fd371e 100644 --- a/modules/openxr/scene/openxr_composition_layer_quad.cpp +++ b/modules/openxr/scene/openxr_composition_layer_quad.cpp @@ -38,18 +38,8 @@ #include "scene/main/viewport.h" #include "scene/resources/3d/primitive_meshes.h" -OpenXRCompositionLayerQuad::OpenXRCompositionLayerQuad() { - composition_layer = { - XR_TYPE_COMPOSITION_LAYER_QUAD, // type - nullptr, // next - 0, // layerFlags - XR_NULL_HANDLE, // space - XR_EYE_VISIBILITY_BOTH, // eyeVisibility - {}, // subImage - { { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose - { (float)quad_size.x, (float)quad_size.y }, // size - }; - openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider((XrCompositionLayerBaseHeader *)&composition_layer)); +OpenXRCompositionLayerQuad::OpenXRCompositionLayerQuad() : + OpenXRCompositionLayer((XrCompositionLayerBaseHeader *)&composition_layer) { XRServer::get_singleton()->connect("reference_frame_changed", callable_mp(this, &OpenXRCompositionLayerQuad::update_transform)); } diff --git a/modules/openxr/scene/openxr_composition_layer_quad.h b/modules/openxr/scene/openxr_composition_layer_quad.h index 0c3172dbb2..a4ccfc6d8e 100644 --- a/modules/openxr/scene/openxr_composition_layer_quad.h +++ b/modules/openxr/scene/openxr_composition_layer_quad.h @@ -38,7 +38,16 @@ class OpenXRCompositionLayerQuad : public OpenXRCompositionLayer { GDCLASS(OpenXRCompositionLayerQuad, OpenXRCompositionLayer); - XrCompositionLayerQuad composition_layer; + XrCompositionLayerQuad composition_layer = { + XR_TYPE_COMPOSITION_LAYER_QUAD, // type + nullptr, // next + 0, // layerFlags + XR_NULL_HANDLE, // space + XR_EYE_VISIBILITY_BOTH, // eyeVisibility + {}, // subImage + { { 0, 0, 0, 0 }, { 0, 0, 0 } }, // pose + { 1.0, 1.0 }, // size + }; Size2 quad_size = Size2(1.0, 1.0); diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index ff032c88c6..c89534a60c 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -390,6 +390,9 @@ Ref<AudioSamplePlayback> AudioStreamPlaybackOggVorbis::get_sample_playback() con void AudioStreamPlaybackOggVorbis::set_sample_playback(const Ref<AudioSamplePlayback> &p_playback) { sample_playback = p_playback; + if (sample_playback.is_valid()) { + sample_playback->stream_playback = Ref<AudioStreamPlayback>(this); + } } AudioStreamPlaybackOggVorbis::~AudioStreamPlaybackOggVorbis() { |