summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bmp/image_loader_bmp.cpp2
-rw-r--r--modules/bmp/image_loader_bmp.h2
-rw-r--r--modules/bmp/register_types.cpp7
-rw-r--r--modules/gltf/SCsub2
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml3
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml8
-rw-r--r--modules/gltf/extensions/SCsub9
-rw-r--r--modules/gltf/gltf_defines.h2
-rw-r--r--modules/gltf/gltf_document.cpp95
-rw-r--r--modules/gltf/gltf_document.h4
-rw-r--r--modules/gltf/gltf_document_extension.cpp7
-rw-r--r--modules/gltf/gltf_document_extension.h2
-rw-r--r--modules/gltf/gltf_state.cpp12
-rw-r--r--modules/gltf/gltf_state.h4
-rw-r--r--modules/hdr/image_loader_hdr.cpp2
-rw-r--r--modules/hdr/image_loader_hdr.h2
-rw-r--r--modules/hdr/register_types.cpp7
-rw-r--r--modules/jpg/image_loader_jpegd.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.h2
-rw-r--r--modules/jpg/register_types.cpp7
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs70
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs4
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp4
-rw-r--r--modules/multiplayer/multiplayer_spawner.h2
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp4
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.h2
-rw-r--r--modules/navigation/godot_navigation_server.cpp26
-rw-r--r--modules/navigation/godot_navigation_server.h2
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/svg/image_loader_svg.h2
-rw-r--r--modules/svg/register_types.cpp12
-rw-r--r--modules/text_server_adv/text_server_adv.cpp17
-rw-r--r--modules/tga/image_loader_tga.cpp2
-rw-r--r--modules/tga/image_loader_tga.h2
-rw-r--r--modules/tga/register_types.cpp7
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.h2
-rw-r--r--modules/tinyexr/register_types.cpp7
-rw-r--r--modules/webp/image_loader_webp.cpp2
-rw-r--r--modules/webp/image_loader_webp.h2
-rw-r--r--modules/webp/register_types.cpp11
-rw-r--r--modules/websocket/websocket_macros.h50
-rw-r--r--modules/webxr/config.py2
-rw-r--r--modules/webxr/godot_webxr.h3
-rw-r--r--modules/webxr/native/library_godot_webxr.js191
-rw-r--r--modules/webxr/webxr_interface_js.cpp56
-rw-r--r--modules/webxr/webxr_interface_js.h1
49 files changed, 322 insertions, 356 deletions
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index ae03abca50..cc21ed28e8 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -200,7 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
return err;
}
-Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
bmp_header_s bmp_header;
Error err = ERR_INVALID_DATA;
diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h
index cf8346ecad..0ca54de1dc 100644
--- a/modules/bmp/image_loader_bmp.h
+++ b/modules/bmp/image_loader_bmp.h
@@ -83,7 +83,7 @@ protected:
const bmp_header_s &p_header);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderBMP();
};
diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp
index 7c4a2085b2..67858e9d46 100644
--- a/modules/bmp/register_types.cpp
+++ b/modules/bmp/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_bmp.h"
-static ImageLoaderBMP *image_loader_bmp = nullptr;
+static Ref<ImageLoaderBMP> image_loader_bmp;
void initialize_bmp_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_bmp = memnew(ImageLoaderBMP);
+ image_loader_bmp.instantiate();
ImageLoader::add_image_format_loader(image_loader_bmp);
}
@@ -48,5 +48,6 @@ void uninitialize_bmp_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_bmp);
+ ImageLoader::remove_image_format_loader(image_loader_bmp);
+ image_loader_bmp.unref();
}
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub
index 71f3ba58d9..5f111165fd 100644
--- a/modules/gltf/SCsub
+++ b/modules/gltf/SCsub
@@ -7,7 +7,7 @@ env_gltf = env_modules.Clone()
# Godot source files
env_gltf.add_source_files(env.modules_sources, "*.cpp")
-env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp")
env_gltf.add_source_files(env.modules_sources, "structures/*.cpp")
+SConscript("extensions/SCsub")
if env["tools"]:
env_gltf.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index d2a9022445..936794976d 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFDocumentExtension" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ [GLTFDocument] extension class.
</brief_description>
<description>
+ Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export.
</description>
<tutorials>
</tutorials>
@@ -28,6 +30,12 @@
<description>
</description>
</method>
+ <method name="_get_supported_extensions" qualifiers="virtual">
+ <return type="PackedStringArray" />
+ <description>
+ Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded.
+ </description>
+ </method>
<method name="_import_node" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index e933e6046a..4d1aa89ac9 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ GLTF node class.
</brief_description>
<description>
+ Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes).
</description>
<tutorials>
+ <link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 1dbd89aed8..6c2f488c1c 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -7,6 +7,14 @@
<tutorials>
</tutorials>
<methods>
+ <method name="add_used_extension">
+ <return type="void" />
+ <param index="0" name="extension_name" type="String" />
+ <param index="1" name="required" type="bool" />
+ <description>
+ Appends an extension to the list of extensions used by this GLTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically.
+ </description>
+ </method>
<method name="get_accessors">
<return type="GLTFAccessor[]" />
<description>
diff --git a/modules/gltf/extensions/SCsub b/modules/gltf/extensions/SCsub
new file mode 100644
index 0000000000..ad214bb79c
--- /dev/null
+++ b/modules/gltf/extensions/SCsub
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_gltf = env_modules.Clone()
+
+# Godot source files
+env_gltf.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h
index c20c87f798..9ee2397968 100644
--- a/modules/gltf/gltf_defines.h
+++ b/modules/gltf/gltf_defines.h
@@ -66,9 +66,9 @@ using GLTFBufferIndex = int;
using GLTFBufferViewIndex = int;
using GLTFCameraIndex = int;
using GLTFImageIndex = int;
+using GLTFLightIndex = int;
using GLTFMaterialIndex = int;
using GLTFMeshIndex = int;
-using GLTFLightIndex = int;
using GLTFNodeIndex = int;
using GLTFSkeletonIndex = int;
using GLTFSkinIndex = int;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index f5730e7137..8d2e37be3a 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -191,14 +191,14 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return Error::FAILED;
}
- /* STEP SERIALIZE SCENE */
+ /* STEP SERIALIZE LIGHTS */
err = _serialize_lights(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE EXTENSIONS */
- err = _serialize_extensions(state);
+ err = _serialize_gltf_extensions(state);
if (err != OK) {
return Error::FAILED;
}
@@ -219,9 +219,9 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return OK;
}
-Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
- Array extensions_used;
- Array extensions_required;
+Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> state) const {
+ Vector<String> extensions_used = state->extensions_used;
+ Vector<String> extensions_required = state->extensions_required;
if (!state->lights.is_empty()) {
extensions_used.push_back("KHR_lights_punctual");
}
@@ -230,9 +230,11 @@ Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
extensions_required.push_back("KHR_texture_transform");
}
if (!extensions_used.is_empty()) {
+ extensions_used.sort();
state->json["extensionsUsed"] = extensions_used;
}
if (!extensions_required.is_empty()) {
+ extensions_required.sort();
state->json["extensionsRequired"] = extensions_required;
}
return OK;
@@ -401,47 +403,47 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
Array nodes;
for (int i = 0; i < state->nodes.size(); i++) {
Dictionary node;
- Ref<GLTFNode> n = state->nodes[i];
+ Ref<GLTFNode> gltf_node = state->nodes[i];
Dictionary extensions;
node["extensions"] = extensions;
- if (!n->get_name().is_empty()) {
- node["name"] = n->get_name();
+ if (!gltf_node->get_name().is_empty()) {
+ node["name"] = gltf_node->get_name();
}
- if (n->camera != -1) {
- node["camera"] = n->camera;
+ if (gltf_node->camera != -1) {
+ node["camera"] = gltf_node->camera;
}
- if (n->light != -1) {
+ if (gltf_node->light != -1) {
Dictionary lights_punctual;
extensions["KHR_lights_punctual"] = lights_punctual;
- lights_punctual["light"] = n->light;
+ lights_punctual["light"] = gltf_node->light;
}
- if (n->mesh != -1) {
- node["mesh"] = n->mesh;
+ if (gltf_node->mesh != -1) {
+ node["mesh"] = gltf_node->mesh;
}
- if (n->skin != -1) {
- node["skin"] = n->skin;
+ if (gltf_node->skin != -1) {
+ node["skin"] = gltf_node->skin;
}
- if (n->skeleton != -1 && n->skin < 0) {
+ if (gltf_node->skeleton != -1 && gltf_node->skin < 0) {
}
- if (n->xform != Transform3D()) {
- node["matrix"] = _xform_to_array(n->xform);
+ if (gltf_node->xform != Transform3D()) {
+ node["matrix"] = _xform_to_array(gltf_node->xform);
}
- if (!n->rotation.is_equal_approx(Quaternion())) {
- node["rotation"] = _quaternion_to_array(n->rotation);
+ if (!gltf_node->rotation.is_equal_approx(Quaternion())) {
+ node["rotation"] = _quaternion_to_array(gltf_node->rotation);
}
- if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
- node["scale"] = _vec3_to_arr(n->scale);
+ if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
+ node["scale"] = _vec3_to_arr(gltf_node->scale);
}
- if (!n->position.is_zero_approx()) {
- node["translation"] = _vec3_to_arr(n->position);
+ if (!gltf_node->position.is_zero_approx()) {
+ node["translation"] = _vec3_to_arr(gltf_node->position);
}
- if (n->children.size()) {
+ if (gltf_node->children.size()) {
Array children;
- for (int j = 0; j < n->children.size(); j++) {
- children.push_back(n->children[j]);
+ for (int j = 0; j < gltf_node->children.size(); j++) {
+ children.push_back(gltf_node->children[j]);
}
node["children"] = children;
}
@@ -450,7 +452,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
ERR_CONTINUE(ext.is_null());
ERR_CONTINUE(!state->scene_nodes.find(i));
- Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]);
+ Error err = ext->export_node(state, gltf_node, node, state->scene_nodes[i]);
ERR_CONTINUE(err != OK);
}
@@ -5046,7 +5048,7 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta
return mi;
}
-Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
+Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr);
@@ -5102,6 +5104,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeInde
return spatial;
}
+
void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
bool retflag = true;
_check_visibility(p_current, retflag);
@@ -6916,12 +6919,32 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR);
- if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) {
- Array extensions_required = state->json["extensionsRequired"];
- if (extensions_required.find("KHR_draco_mesh_compression") != -1) {
- ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported.");
- return ERR_UNAVAILABLE;
+ if (state->json.has("extensionsUsed")) {
+ Vector<String> ext_array = state->json["extensionsUsed"];
+ state->extensions_used = ext_array;
+ }
+ if (state->json.has("extensionsRequired")) {
+ Vector<String> ext_array = state->json["extensionsRequired"];
+ state->extensions_required = ext_array;
+ }
+ HashSet<String> supported_extensions;
+ supported_extensions.insert("KHR_lights_punctual");
+ supported_extensions.insert("KHR_materials_pbrSpecularGlossiness");
+ supported_extensions.insert("KHR_texture_transform");
+ for (int ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Vector<String> ext_supported_extensions = ext->get_supported_extensions();
+ for (int i = 0; i < ext_supported_extensions.size(); ++i) {
+ supported_extensions.insert(ext_supported_extensions[i]);
}
}
- return OK;
+ Error ret = Error::OK;
+ for (int i = 0; i < state->extensions_required.size(); i++) {
+ if (!supported_extensions.has(state->extensions_required[i])) {
+ ERR_PRINT("GLTF: Can't import file '" + state->filename + "', required extension '" + String(state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?");
+ ret = ERR_UNAVAILABLE;
+ }
+ }
+ return ret;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 36a2f94a4e..750d3d403e 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -188,7 +188,7 @@ private:
const GLTFNodeIndex bone_index);
ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index);
Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
+ Light3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index);
void _assign_scene_names(Ref<GLTFState> state);
template <class T>
@@ -265,7 +265,7 @@ private:
Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material);
Error _serialize_version(Ref<GLTFState> state);
Error _serialize_file(Ref<GLTFState> state, const String p_path);
- Error _serialize_extensions(Ref<GLTFState> state) const;
+ Error _serialize_gltf_extensions(Ref<GLTFState> state) const;
public:
// https://www.itu.int/rec/R-REC-BT.601
diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp
index d0bd7651e0..3b952f8246 100644
--- a/modules/gltf/gltf_document_extension.cpp
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -31,6 +31,7 @@
#include "gltf_document_extension.h"
void GLTFDocumentExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_supported_extensions);
GDVIRTUAL_BIND(_import_preflight, "state");
GDVIRTUAL_BIND(_import_post_parse, "state");
GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
@@ -40,6 +41,12 @@ void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_export_post, "state");
}
+Vector<String> GLTFDocumentExtension::get_supported_extensions() {
+ Vector<String> ret;
+ GDVIRTUAL_CALL(_get_supported_extensions, ret);
+ return ret;
+}
+
Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h
index 0ef9109584..d4bb3993dc 100644
--- a/modules/gltf/gltf_document_extension.h
+++ b/modules/gltf/gltf_document_extension.h
@@ -41,6 +41,7 @@ protected:
static void _bind_methods();
public:
+ virtual Vector<String> get_supported_extensions();
virtual Error import_preflight(Ref<GLTFState> p_state);
virtual Error import_post_parse(Ref<GLTFState> p_state);
virtual Error export_post(Ref<GLTFState> p_state);
@@ -48,6 +49,7 @@ public:
virtual Error export_preflight(Node *p_state);
virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
+ GDVIRTUAL0R(Vector<String>, _get_supported_extensions);
GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>);
GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>);
GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 85bac446cc..a23fb39503 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -31,6 +31,7 @@
#include "gltf_state.h"
void GLTFState::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension);
ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json);
ClassDB::bind_method(D_METHOD("get_major_version"), &GLTFState::get_major_version);
@@ -112,6 +113,17 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
}
+void GLTFState::add_used_extension(const String &p_extension_name, bool p_required) {
+ if (!extensions_used.has(p_extension_name)) {
+ extensions_used.push_back(p_extension_name);
+ }
+ if (p_required) {
+ if (!extensions_required.has(p_extension_name)) {
+ extensions_required.push_back(p_extension_name);
+ }
+ }
+}
+
Dictionary GLTFState::get_json() {
return json;
}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 6b2d1ca228..791431f376 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -78,6 +78,8 @@ class GLTFState : public Resource {
Vector<int> root_nodes;
Vector<Ref<GLTFTexture>> textures;
Vector<Ref<Texture2D>> images;
+ Vector<String> extensions_used;
+ Vector<String> extensions_required;
Vector<Ref<GLTFSkin>> skins;
Vector<Ref<GLTFCamera>> cameras;
@@ -97,6 +99,8 @@ protected:
static void _bind_methods();
public:
+ void add_used_extension(const String &p_extension, bool p_required = false);
+
Dictionary get_json();
void set_json(Dictionary p_json);
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index e7c6fe592d..6f0bc16a26 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
String header = f->get_token();
ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + ".");
diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h
index 1bff05129b..5f817f0ba8 100644
--- a/modules/hdr/image_loader_hdr.h
+++ b/modules/hdr/image_loader_hdr.h
@@ -35,7 +35,7 @@
class ImageLoaderHDR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderHDR();
};
diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp
index b988bf4587..18b1a73f1c 100644
--- a/modules/hdr/register_types.cpp
+++ b/modules/hdr/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_hdr.h"
-static ImageLoaderHDR *image_loader_hdr = nullptr;
+static Ref<ImageLoaderHDR> image_loader_hdr;
void initialize_hdr_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_hdr = memnew(ImageLoaderHDR);
+ image_loader_hdr.instantiate();
ImageLoader::add_image_format_loader(image_loader_hdr);
}
@@ -48,5 +48,6 @@ void uninitialize_hdr_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_hdr);
+ ImageLoader::remove_image_format_loader(image_loader_hdr);
+ image_loader_hdr.unref();
}
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index 3e138bf633..ce20ac9060 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -104,7 +104,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
return OK;
}
-Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h
index caa0461d05..f63db51521 100644
--- a/modules/jpg/image_loader_jpegd.h
+++ b/modules/jpg/image_loader_jpegd.h
@@ -35,7 +35,7 @@
class ImageLoaderJPG : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderJPG();
};
diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp
index b8b48a550f..7da216bbe2 100644
--- a/modules/jpg/register_types.cpp
+++ b/modules/jpg/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_jpegd.h"
-static ImageLoaderJPG *image_loader_jpg = nullptr;
+static Ref<ImageLoaderJPG> image_loader_jpg;
void initialize_jpg_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_jpg = memnew(ImageLoaderJPG);
+ image_loader_jpg.instantiate();
ImageLoader::add_image_format_loader(image_loader_jpg);
}
@@ -48,5 +48,6 @@ void uninitialize_jpg_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_jpg);
+ ImageLoader::remove_image_format_loader(image_loader_jpg);
+ image_loader_jpg.unref();
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 1df41a905b..eeda1042ca 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -235,6 +235,8 @@ namespace Godot.SourceGenerators
.Append(signalName)
.Append(";\n");
+ source.Append($" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedName()}\"/>\n");
+
source.Append(" public event ")
.Append(signalDelegate.DelegateSymbol.FullQualifiedName())
.Append(" ")
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index ad4fce8daa..4d40724a83 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -69,51 +69,41 @@ namespace GodotTools.Build
private void LoadIssuesFromFile(string csvFile)
{
- using (var file = new Godot.File())
+ using var file = FileAccess.Open(csvFile, FileAccess.ModeFlags.Read);
+
+ if (file == null)
+ return;
+
+ while (!file.EofReached())
{
- try
- {
- Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read);
+ string[] csvColumns = file.GetCsvLine();
- if (openError != Error.Ok)
- return;
+ if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
+ return;
- while (!file.EofReached())
- {
- string[] csvColumns = file.GetCsvLine();
-
- if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
- return;
-
- if (csvColumns.Length != 7)
- {
- GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
- continue;
- }
-
- var issue = new BuildIssue
- {
- Warning = csvColumns[0] == "warning",
- File = csvColumns[1],
- Line = int.Parse(csvColumns[2]),
- Column = int.Parse(csvColumns[3]),
- Code = csvColumns[4],
- Message = csvColumns[5],
- ProjectFile = csvColumns[6]
- };
-
- if (issue.Warning)
- WarningCount += 1;
- else
- ErrorCount += 1;
-
- _issues.Add(issue);
- }
- }
- finally
+ if (csvColumns.Length != 7)
{
- file.Close(); // Disposing it is not enough. We need to call Close()
+ GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
+ continue;
}
+
+ var issue = new BuildIssue
+ {
+ Warning = csvColumns[0] == "warning",
+ File = csvColumns[1],
+ Line = int.Parse(csvColumns[2]),
+ Column = int.Parse(csvColumns[3]),
+ Code = csvColumns[4],
+ Message = csvColumns[5],
+ ProjectFile = csvColumns[6]
+ };
+
+ if (issue.Warning)
+ WarningCount += 1;
+ else
+ ErrorCount += 1;
+
+ _issues.Add(issue);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index 44f951e314..d77baab24b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -1245,12 +1245,12 @@ namespace Godot
/// <summary>
/// If the string is a path, this concatenates <paramref name="file"/>
/// at the end of the string as a subpath.
- /// E.g. <c>"this/is".PlusFile("path") == "this/is/path"</c>.
+ /// E.g. <c>"this/is".PathJoin("path") == "this/is/path"</c>.
/// </summary>
/// <param name="instance">The path that will be concatenated.</param>
/// <param name="file">File name to concatenate with the path.</param>
/// <returns>The concatenated path with the given file name.</returns>
- public static string PlusFile(this string instance, string file)
+ public static string PathJoin(this string instance, string file)
{
if (instance.Length > 0 && instance[instance.Length - 1] == '/')
return instance + file;
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index c68e2e5a99..9d28feef09 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -87,8 +87,8 @@ void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const {
}
#endif
-TypedArray<String> MultiplayerSpawner::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray MultiplayerSpawner::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (spawn_path.is_empty() || !has_node(spawn_path)) {
warnings.push_back(RTR("A valid NodePath must be set in the \"Spawn Path\" property in order for MultiplayerSpawner to be able to spawn Nodes."));
diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h
index f038c3b2f9..587c99efd1 100644
--- a/modules/multiplayer/multiplayer_spawner.h
+++ b/modules/multiplayer/multiplayer_spawner.h
@@ -91,7 +91,7 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
#endif
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
Node *get_spawn_node() const {
return spawn_node.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)) : nullptr;
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index 01ecd1a7de..2c3ebccaeb 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -94,8 +94,8 @@ void MultiplayerSynchronizer::_update_process() {
}
}
-TypedArray<String> MultiplayerSynchronizer::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray MultiplayerSynchronizer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (root_path.is_empty() || !has_node(root_path)) {
warnings.push_back(RTR("A valid NodePath must be set in the \"Root Path\" property in order for MultiplayerSynchronizer to be able to synchronize properties."));
diff --git a/modules/multiplayer/multiplayer_synchronizer.h b/modules/multiplayer/multiplayer_synchronizer.h
index 9b9067a910..f10a95a1d4 100644
--- a/modules/multiplayer/multiplayer_synchronizer.h
+++ b/modules/multiplayer/multiplayer_synchronizer.h
@@ -66,7 +66,7 @@ public:
static Error get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs);
static Error set_state(const List<NodePath> &p_properties, Object *p_obj, const Vector<Variant> &p_state);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_replication_interval(double p_interval);
double get_replication_interval() const;
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 9e5d666a51..8ca73a3adb 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -810,6 +810,32 @@ void GodotNavigationServer::process(real_t p_delta_time) {
}
}
+NavigationUtilities::PathQueryResult GodotNavigationServer::_query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const {
+ NavigationUtilities::PathQueryResult r_query_result;
+
+ const NavMap *map = map_owner.get_or_null(p_parameters.map);
+ ERR_FAIL_COND_V(map == nullptr, r_query_result);
+
+ // run the pathfinding
+
+ if (p_parameters.pathfinding_algorithm == NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) {
+ // while postprocessing is still part of map.get_path() need to check and route it here for the correct "optimize" post-processing
+ if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) {
+ r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, true, p_parameters.navigation_layers);
+ } else if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) {
+ r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, false, p_parameters.navigation_layers);
+ }
+ } else {
+ return r_query_result;
+ }
+
+ // add path postprocessing
+
+ // add path stats
+
+ return r_query_result;
+}
+
#undef COMMAND_1
#undef COMMAND_2
#undef COMMAND_4
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index e6ef7e3bb1..ab5e722d35 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -175,6 +175,8 @@ public:
void flush_queries();
virtual void process(real_t p_delta_time) override;
+
+ virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override;
};
#undef COMMAND_1
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index cd6081f91b..f43f2784c7 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -142,7 +142,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("svg");
}
-Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) {
+Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
String svg = p_fileaccess->get_as_utf8_string();
if (p_flags & FLAG_CONVERT_COLORS) {
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index e6f73ab18f..b0b0963c15 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -43,7 +43,7 @@ public:
void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) override;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
};
diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp
index 5b4d1d31ca..323b1d652a 100644
--- a/modules/svg/register_types.cpp
+++ b/modules/svg/register_types.cpp
@@ -34,7 +34,7 @@
#include <thorvg.h>
-static ImageLoaderSVG *image_loader_svg = nullptr;
+static Ref<ImageLoaderSVG> image_loader_svg;
void initialize_svg_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
@@ -45,7 +45,8 @@ void initialize_svg_module(ModuleInitializationLevel p_level) {
if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) {
return;
}
- image_loader_svg = memnew(ImageLoaderSVG);
+
+ image_loader_svg.instantiate();
ImageLoader::add_image_format_loader(image_loader_svg);
}
@@ -54,9 +55,12 @@ void uninitialize_svg_module(ModuleInitializationLevel p_level) {
return;
}
- if (!image_loader_svg) {
+ if (image_loader_svg.is_null()) {
+ // It failed to initialize so it was not added.
return;
}
- memdelete(image_loader_svg);
+
+ ImageLoader::remove_image_format_loader(image_loader_svg);
+ image_loader_svg.unref();
tvg::Initializer::term(tvg::CanvasEngine::Sw);
}
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index d90870107b..b0f414f7f0 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -45,7 +45,6 @@ using namespace godot;
// Headers for building as built-in module.
#include "core/config/project_settings.h"
-#include "core/core_bind.h"
#include "core/error/error_macros.h"
#include "core/object/worker_thread_pool.h"
#include "core/string/print_string.h"
@@ -53,8 +52,6 @@ using namespace godot;
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
-using namespace core_bind;
-
#endif
// Built-in ICU data.
@@ -408,13 +405,12 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
if (!icu_data_loaded) {
String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
- Ref<File> f;
- f.instantiate();
- if (f->open(filename, File::READ) != OK) {
+ Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);
+ if (f.is_null()) {
return false;
}
uint64_t len = f->get_length();
- PackedByteArray icu_data = f->get_buffer(len);
+ PackedByteArray icu_data = f->_get_buffer(len);
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -455,16 +451,15 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const {
// Store data to the res file if it's available.
- Ref<File> f;
- f.instantiate();
- if (f->open(p_filename, File::WRITE) != OK) {
+ Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);
+ if (f.is_null()) {
return false;
}
PackedByteArray icu_data;
icu_data.resize(U_ICUDATA_SIZE);
memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
- f->store_buffer(icu_data);
+ f->_store_buffer(icu_data);
return true;
#else
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 16d9bf7b93..00ba32eae1 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
return OK;
}
-Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index d95c5ff30b..b257ed110d 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader {
static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTGA();
};
diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp
index 520ed5f799..3a9d2324e7 100644
--- a/modules/tga/register_types.cpp
+++ b/modules/tga/register_types.cpp
@@ -32,14 +32,14 @@
#include "image_loader_tga.h"
-static ImageLoaderTGA *image_loader_tga = nullptr;
+static Ref<ImageLoaderTGA> image_loader_tga;
void initialize_tga_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_tga = memnew(ImageLoaderTGA);
+ image_loader_tga.instantiate();
ImageLoader::add_image_format_loader(image_loader_tga);
}
@@ -48,5 +48,6 @@ void uninitialize_tga_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_tga);
+ ImageLoader::remove_image_format_loader(image_loader_tga);
+ image_loader_tga.unref();
}
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 6f61251f9b..5c43bfc8b7 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -37,7 +37,7 @@
#include "thirdparty/tinyexr/tinyexr.h"
-Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h
index 8da2a0d4af..ab34a59da5 100644
--- a/modules/tinyexr/image_loader_tinyexr.h
+++ b/modules/tinyexr/image_loader_tinyexr.h
@@ -35,7 +35,7 @@
class ImageLoaderTinyEXR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTinyEXR();
};
diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp
index c5897f37c3..b1a9f18e3b 100644
--- a/modules/tinyexr/register_types.cpp
+++ b/modules/tinyexr/register_types.cpp
@@ -33,14 +33,14 @@
#include "image_loader_tinyexr.h"
#include "image_saver_tinyexr.h"
-static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr;
+static Ref<ImageLoaderTinyEXR> image_loader_tinyexr;
void initialize_tinyexr_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
- image_loader_tinyexr = memnew(ImageLoaderTinyEXR);
+ image_loader_tinyexr.instantiate();
ImageLoader::add_image_format_loader(image_loader_tinyexr);
Image::save_exr_func = save_exr;
@@ -52,7 +52,8 @@ void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_tinyexr);
+ ImageLoader::remove_image_format_loader(image_loader_tinyexr);
+ image_loader_tinyexr.unref();
Image::save_exr_func = nullptr;
}
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index 705ab508ab..dd387db554 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -48,7 +48,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) {
return img;
}
-Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h
index d868ae3f7f..0522e4ef91 100644
--- a/modules/webp/image_loader_webp.h
+++ b/modules/webp/image_loader_webp.h
@@ -35,7 +35,7 @@
class ImageLoaderWebP : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderWebP();
};
diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp
index 29f633743e..e523f43cfe 100644
--- a/modules/webp/register_types.cpp
+++ b/modules/webp/register_types.cpp
@@ -33,7 +33,7 @@
#include "image_loader_webp.h"
#include "resource_saver_webp.h"
-static ImageLoaderWebP *image_loader_webp = nullptr;
+static Ref<ImageLoaderWebP> image_loader_webp;
static Ref<ResourceSaverWebP> resource_saver_webp;
void initialize_webp_module(ModuleInitializationLevel p_level) {
@@ -41,9 +41,10 @@ void initialize_webp_module(ModuleInitializationLevel p_level) {
return;
}
- image_loader_webp = memnew(ImageLoaderWebP);
- resource_saver_webp.instantiate();
+ image_loader_webp.instantiate();
ImageLoader::add_image_format_loader(image_loader_webp);
+
+ resource_saver_webp.instantiate();
ResourceSaver::add_resource_format_saver(resource_saver_webp);
}
@@ -52,7 +53,9 @@ void uninitialize_webp_module(ModuleInitializationLevel p_level) {
return;
}
- memdelete(image_loader_webp);
+ ImageLoader::remove_image_format_loader(image_loader_webp);
+ image_loader_webp.unref();
+
ResourceSaver::remove_resource_format_saver(resource_saver_webp);
resource_saver_webp.unref();
}
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
index a01ae65c56..b03bd8f45c 100644
--- a/modules/websocket/websocket_macros.h
+++ b/modules/websocket/websocket_macros.h
@@ -35,34 +35,32 @@
#define DEF_PKT_SHIFT 10
#define DEF_BUF_SHIFT 16
-/* clang-format off */
-#define GDCICLASS(CNAME) \
-public:\
- static CNAME *(*_create)();\
-\
- static Ref<CNAME > create_ref() {\
-\
- if (!_create)\
- return Ref<CNAME >();\
- return Ref<CNAME >(_create());\
- }\
-\
- static CNAME *create() {\
-\
- if (!_create)\
- return nullptr;\
- return _create();\
- }\
-protected:\
+#define GDCICLASS(CNAME) \
+public: \
+ static CNAME *(*_create)(); \
+ \
+ static Ref<CNAME> create_ref() { \
+ if (!_create) \
+ return Ref<CNAME>(); \
+ return Ref<CNAME>(_create()); \
+ } \
+ \
+ static CNAME *create() { \
+ if (!_create) \
+ return nullptr; \
+ return _create(); \
+ } \
+ \
+protected:
#define GDCINULL(CNAME) \
-CNAME *(*CNAME::_create)() = nullptr;
+ CNAME *(*CNAME::_create)() = nullptr;
-#define GDCIIMPL(IMPNAME, CNAME) \
-public:\
- static CNAME *_create() { return memnew(IMPNAME); }\
- static void make_default() { CNAME::_create = IMPNAME::_create; }\
-protected:\
-/* clang-format on */
+#define GDCIIMPL(IMPNAME, CNAME) \
+public: \
+ static CNAME *_create() { return memnew(IMPNAME); } \
+ static void make_default() { CNAME::_create = IMPNAME::_create; } \
+ \
+protected:
#endif // WEBSOCKET_MACROS_H
diff --git a/modules/webxr/config.py b/modules/webxr/config.py
index f676ef3483..8d75e7f531 100644
--- a/modules/webxr/config.py
+++ b/modules/webxr/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return not env["disable_3d"]
+ return env["opengl3"] and not env["disable_3d"]
def configure(env):
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
index 52104895d4..34d068be3e 100644
--- a/modules/webxr/godot_webxr.h
+++ b/modules/webxr/godot_webxr.h
@@ -65,8 +65,7 @@ extern int godot_webxr_get_view_count();
extern int *godot_webxr_get_render_target_size();
extern float *godot_webxr_get_transform_for_eye(int p_eye);
extern float *godot_webxr_get_projection_for_eye(int p_eye);
-extern int godot_webxr_get_external_texture_for_eye(int p_eye);
-extern void godot_webxr_commit_for_eye(int p_eye);
+extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo);
extern void godot_webxr_sample_controller_data();
extern int godot_webxr_get_controller_count();
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index c4b21defce..9b75796ee5 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -32,9 +32,6 @@ const GodotWebXR = {
$GodotWebXR: {
gl: null,
- texture_ids: [null, null],
- textures: [null, null],
-
session: null,
space: null,
frame: null,
@@ -77,110 +74,6 @@ const GodotWebXR = {
}, 0);
},
- // Some custom WebGL code for blitting our eye textures to the
- // framebuffer we get from WebXR.
- shaderProgram: null,
- programInfo: null,
- buffer: null,
- // Vertex shader source.
- vsSource: `
- const vec2 scale = vec2(0.5, 0.5);
- attribute vec4 aVertexPosition;
-
- varying highp vec2 vTextureCoord;
-
- void main () {
- gl_Position = aVertexPosition;
- vTextureCoord = aVertexPosition.xy * scale + scale;
- }
- `,
- // Fragment shader source.
- fsSource: `
- varying highp vec2 vTextureCoord;
-
- uniform sampler2D uSampler;
-
- void main() {
- gl_FragColor = texture2D(uSampler, vTextureCoord);
- }
- `,
-
- initShaderProgram: (gl, vsSource, fsSource) => {
- const vertexShader = GodotWebXR.loadShader(gl, gl.VERTEX_SHADER, vsSource);
- const fragmentShader = GodotWebXR.loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
-
- const shaderProgram = gl.createProgram();
- gl.attachShader(shaderProgram, vertexShader);
- gl.attachShader(shaderProgram, fragmentShader);
- gl.linkProgram(shaderProgram);
-
- if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
- GodotRuntime.error(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
- return null;
- }
-
- return shaderProgram;
- },
- loadShader: (gl, type, source) => {
- const shader = gl.createShader(type);
- gl.shaderSource(shader, source);
- gl.compileShader(shader);
-
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
- GodotRuntime.error(`An error occurred compiling the shader: ${gl.getShaderInfoLog(shader)}`);
- gl.deleteShader(shader);
- return null;
- }
-
- return shader;
- },
- initBuffer: (gl) => {
- const positionBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
- const positions = [
- -1.0, -1.0,
- 1.0, -1.0,
- -1.0, 1.0,
- 1.0, 1.0,
- ];
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
- return positionBuffer;
- },
- blitTexture: (gl, texture) => {
- if (GodotWebXR.shaderProgram === null) {
- GodotWebXR.shaderProgram = GodotWebXR.initShaderProgram(gl, GodotWebXR.vsSource, GodotWebXR.fsSource);
- GodotWebXR.programInfo = {
- program: GodotWebXR.shaderProgram,
- attribLocations: {
- vertexPosition: gl.getAttribLocation(GodotWebXR.shaderProgram, 'aVertexPosition'),
- },
- uniformLocations: {
- uSampler: gl.getUniformLocation(GodotWebXR.shaderProgram, 'uSampler'),
- },
- };
- GodotWebXR.buffer = GodotWebXR.initBuffer(gl);
- }
-
- const orig_program = gl.getParameter(gl.CURRENT_PROGRAM);
- gl.useProgram(GodotWebXR.shaderProgram);
-
- gl.bindBuffer(gl.ARRAY_BUFFER, GodotWebXR.buffer);
- gl.vertexAttribPointer(GodotWebXR.programInfo.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0);
- gl.enableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.uniform1i(GodotWebXR.programInfo.uniformLocations.uSampler, 0);
-
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
-
- // Restore state.
- gl.bindTexture(gl.TEXTURE_2D, null);
- gl.disableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
- gl.useProgram(orig_program);
- },
-
// Holds the controllers list between function calls.
controllers: [],
@@ -370,22 +263,6 @@ const GodotWebXR = {
.catch((e) => { });
}
- // Clean-up the textures we allocated for each view.
- const gl = GodotWebXR.gl;
- for (let i = 0; i < GodotWebXR.textures.length; i++) {
- const texture = GodotWebXR.textures[i];
- if (texture !== null) {
- gl.deleteTexture(texture);
- }
- GodotWebXR.textures[i] = null;
-
- const texture_id = GodotWebXR.texture_ids[i];
- if (texture_id !== null) {
- GL.textures[texture_id] = null;
- }
- GodotWebXR.texture_ids[i] = null;
- }
-
GodotWebXR.session = null;
GodotWebXR.space = null;
GodotWebXR.frame = null;
@@ -460,50 +337,9 @@ const GodotWebXR = {
return buf;
},
- godot_webxr_get_external_texture_for_eye__proxy: 'sync',
- godot_webxr_get_external_texture_for_eye__sig: 'ii',
- godot_webxr_get_external_texture_for_eye: function (p_eye) {
- if (!GodotWebXR.session) {
- return 0;
- }
-
- const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
- if (GodotWebXR.texture_ids[view_index]) {
- return GodotWebXR.texture_ids[view_index];
- }
-
- // Check pose separately and after returning the cached texture id,
- // because we won't get a pose in some cases if we lose tracking, and
- // we don't want to return 0 just because tracking was lost.
- if (!GodotWebXR.pose) {
- return 0;
- }
-
- const glLayer = GodotWebXR.session.renderState.baseLayer;
- const view = GodotWebXR.pose.views[view_index];
- const viewport = glLayer.getViewport(view);
- const gl = GodotWebXR.gl;
-
- const texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, viewport.width, viewport.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
-
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- const texture_id = GL.getNewId(GL.textures);
- GL.textures[texture_id] = texture;
- GodotWebXR.textures[view_index] = texture;
- GodotWebXR.texture_ids[view_index] = texture_id;
- return texture_id;
- },
-
godot_webxr_commit_for_eye__proxy: 'sync',
- godot_webxr_commit_for_eye__sig: 'vi',
- godot_webxr_commit_for_eye: function (p_eye) {
+ godot_webxr_commit_for_eye__sig: 'vii',
+ godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) {
if (!GodotWebXR.session || !GodotWebXR.pose) {
return;
}
@@ -514,18 +350,29 @@ const GodotWebXR = {
const viewport = glLayer.getViewport(view);
const gl = GodotWebXR.gl;
+ const framebuffer = GL.framebuffers[p_destination_fbo];
+
const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
- const orig_viewport = gl.getParameter(gl.VIEWPORT);
+ const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING);
+ const orig_read_buffer = gl.getParameter(gl.READ_BUFFER);
+ const orig_draw_framebuffer = gl.getParameter(gl.DRAW_FRAMEBUFFER_BINDING);
- // Bind to WebXR's framebuffer.
- gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
- gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+ // Copy from Godot render target into framebuffer from WebXR.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer);
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer);
- GodotWebXR.blitTexture(gl, GodotWebXR.textures[view_index]);
+ // Flip Y upside down on destination.
+ gl.blitFramebuffer(0, 0, viewport.width, viewport.height,
+ viewport.x, viewport.height, viewport.width, viewport.y,
+ gl.COLOR_BUFFER_BIT, gl.NEAREST);
// Restore state.
gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
- gl.viewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, orig_read_framebuffer);
+ gl.readBuffer(orig_read_buffer);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, orig_draw_framebuffer);
},
godot_webxr_sample_controller_data__proxy: 'sync',
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 7d97dbfa0b..d0c7484aa1 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -34,9 +34,11 @@
#include "core/input/input.h"
#include "core/os/os.h"
+#include "drivers/gles3/storage/texture_storage.h"
#include "emscripten.h"
#include "godot_webxr.h"
#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/rendering_server_globals.h"
#include <stdlib.h>
@@ -232,6 +234,8 @@ bool WebXRInterfaceJS::initialize() {
}
// we must create a tracker for our head
+ head_transform.basis = Basis();
+ head_transform.origin = Vector3();
head_tracker.instantiate();
head_tracker->set_tracker_type(XRServer::TRACKER_HEAD);
head_tracker->set_tracker_name("head");
@@ -334,15 +338,17 @@ Transform3D WebXRInterfaceJS::get_camera_transform() {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, transform_for_eye);
- float *js_matrix = godot_webxr_get_transform_for_eye(0);
- if (!initialized || js_matrix == nullptr) {
- return transform_for_eye;
- }
+ if (initialized) {
+ float world_scale = xr_server->get_world_scale();
- transform_for_eye = _js_matrix_to_transform(js_matrix);
- free(js_matrix);
+ // just scale our origin point of our transform
+ Transform3D _head_transform = head_transform;
+ _head_transform.origin *= world_scale;
+
+ transform_for_eye = (xr_server->get_reference_frame()) * _head_transform;
+ }
- return xr_server->get_reference_frame() * transform_for_eye;
+ return transform_for_eye;
};
Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
@@ -360,6 +366,14 @@ Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Tran
transform_for_eye = _js_matrix_to_transform(js_matrix);
free(js_matrix);
+ float world_scale = xr_server->get_world_scale();
+ // Scale only the center point of our eye transform, so we don't scale the
+ // distance between the eyes.
+ Transform3D _head_transform = head_transform;
+ transform_for_eye.origin -= _head_transform.origin;
+ _head_transform.origin *= world_scale;
+ transform_for_eye.origin += _head_transform.origin;
+
return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
};
@@ -394,29 +408,33 @@ Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c
return blit_to_screen;
}
- // @todo Refactor this to be based on "views" rather than "eyes".
- godot_webxr_commit_for_eye(1);
- if (godot_webxr_get_view_count() > 1) {
- godot_webxr_commit_for_eye(2);
+ GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage);
+ if (!texture_storage) {
+ return blit_to_screen;
}
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
+
+ // @todo Support multiple eyes!
+ godot_webxr_commit_for_eye(1, rt->fbo);
+
return blit_to_screen;
};
void WebXRInterfaceJS::process() {
if (initialized) {
- godot_webxr_sample_controller_data();
-
+ // Get the "head" position.
+ float *js_matrix = godot_webxr_get_transform_for_eye(0);
+ if (js_matrix != nullptr) {
+ head_transform = _js_matrix_to_transform(js_matrix);
+ free(js_matrix);
+ }
if (head_tracker.is_valid()) {
- // TODO set default pose to our head location (i.e. get_camera_transform without world scale and reference frame applied)
- // head_tracker->set_pose("default", head_transform, Vector3(), Vector3());
+ head_tracker->set_pose("default", head_transform, Vector3(), Vector3());
}
+ godot_webxr_sample_controller_data();
int controller_count = godot_webxr_get_controller_count();
- if (controller_count == 0) {
- return;
- }
-
for (int i = 0; i < controller_count; i++) {
_update_tracker(i);
}
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index dbe89dad83..319adc2ac9 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -45,6 +45,7 @@ class WebXRInterfaceJS : public WebXRInterface {
private:
bool initialized;
Ref<XRPositionalTracker> head_tracker;
+ Transform3D head_transform;
String session_mode;
String required_features;