summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml4
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd2
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd2
-rw-r--r--modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd3
-rw-r--r--modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd3
-rw-r--r--modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd3
-rw-r--r--modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd3
-rw-r--r--modules/gdscript/editor/script_templates/RichTextEffect/default.gd7
-rw-r--r--modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd9
-rw-r--r--modules/gdscript/gdscript.h5
-rw-r--r--modules/gdscript/gdscript_editor.cpp20
-rw-r--r--modules/gdscript/gdscript_vm.cpp6
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp9
-rw-r--r--modules/gdscript/language_server/godot_lsp.h11
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp4
-rw-r--r--modules/mono/csharp_script.cpp25
-rw-r--r--modules/mono/csharp_script.h8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs11
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h2
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp7
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp4
-rw-r--r--modules/openxr/SCsub2
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml13
-rw-r--r--modules/openxr/extensions/openxr_fb_foveation_extension.cpp168
-rw-r--r--modules/openxr/extensions/openxr_fb_foveation_extension.h96
-rw-r--r--modules/openxr/extensions/openxr_fb_update_swapchain_extension.cpp102
-rw-r--r--modules/openxr/extensions/openxr_fb_update_swapchain_extension.h73
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.h34
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.h19
-rw-r--r--modules/openxr/openxr_api.cpp84
-rw-r--r--modules/openxr/openxr_api.h11
-rw-r--r--modules/openxr/openxr_interface.cpp53
-rw-r--r--modules/openxr/openxr_interface.h8
-rw-r--r--modules/openxr/openxr_platform_inc.h78
35 files changed, 768 insertions, 123 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 18045e323c..806ab1e3df 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -557,7 +557,7 @@
<description>
Export an [int] or [float] property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [code]EditorSettings.interface/inspector/default_float_step[/code] setting.
If hints [code]"or_greater"[/code] and [code]"or_less"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"hide_slider"[/code] hint will hide the slider element of the editor widget.
- Hints also allow to indicate the units for the edited value. Using [code]"radians"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock. [code]"degrees"[/code] allows to add a degree sign as a unit suffix. Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string.
+ Hints also allow to indicate the units for the edited value. Using [code]"radians_as_degrees"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock (the range values are also in degrees). [code]"degrees"[/code] allows to add a degree sign as a unit suffix (the value is unchanged). Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string.
See also [constant PROPERTY_HINT_RANGE].
[codeblock]
@export_range(0, 20) var number
@@ -567,7 +567,7 @@
@export_range(0, 100, 1, "or_greater") var power_percent
@export_range(0, 100, 1, "or_greater", "or_less") var health_delta
- @export_range(-3.14, 3.14, 0.001, "radians") var angle_radians
+ @export_range(-180, 180, 0.001, "radians_as_degrees") var angle_radians
@export_range(0, 360, 1, "degrees") var angle_degrees
@export_range(-8, 8, 2, "suffix:px") var target_offset
[/codeblock]
diff --git a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
index b8fc8c75dc..28ab080dd2 100644
--- a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
@@ -15,7 +15,7 @@ func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y += gravity * delta
- # Handle Jump.
+ # Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
diff --git a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
index 53bc606c9a..9b0e4be4ed 100644
--- a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
@@ -15,7 +15,7 @@ func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y -= gravity * delta
- # Handle Jump.
+ # Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
diff --git a/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
index b27b3e5655..547943b910 100644
--- a/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
+++ b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
@@ -1,6 +1,7 @@
# meta-description: Basic plugin template
+
@tool
-extends EditorPlugin
+extends _BASE_
func _enter_tree() -> void:
diff --git a/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd b/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
index 556afe994b..6772ea4a26 100644
--- a/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
+++ b/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
@@ -1,6 +1,7 @@
# meta-description: Basic import script template
+
@tool
-extends EditorScenePostImport
+extends _BASE_
# Called by the editor when a scene has this script set as the import script in the import tab.
diff --git a/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd b/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
index 875afb4fc0..e8f907f43b 100644
--- a/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
+++ b/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
@@ -1,6 +1,7 @@
# meta-description: Basic import script template (no comments)
+
@tool
-extends EditorScenePostImport
+extends _BASE_
func _post_import(scene: Node) -> Object:
diff --git a/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
index fdb8550d43..fee7353f0d 100644
--- a/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
+++ b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
@@ -1,6 +1,7 @@
# meta-description: Basic editor script template
+
@tool
-extends EditorScript
+extends _BASE_
# Called when the script is executed (using File -> Run in Script Editor).
diff --git a/modules/gdscript/editor/script_templates/RichTextEffect/default.gd b/modules/gdscript/editor/script_templates/RichTextEffect/default.gd
index c79eeb91ec..c7a999ef24 100644
--- a/modules/gdscript/editor/script_templates/RichTextEffect/default.gd
+++ b/modules/gdscript/editor/script_templates/RichTextEffect/default.gd
@@ -1,15 +1,16 @@
# meta-description: Base template for rich text effects
@tool
-class_name _CLASS_
+# Having a class name is handy for picking the effect in the Inspector.
+class_name RichText_CLASS_
extends _BASE_
# To use this effect:
# - Enable BBCode on a RichTextLabel.
# - Register this effect on the label.
-# - Use [_CLASS_ param=2.0]hello[/_CLASS_] in text.
-var bbcode := "_CLASS_"
+# - Use [_CLASS_SNAKE_CASE_ param=2.0]hello[/_CLASS_SNAKE_CASE_] in text.
+var bbcode := "_CLASS_SNAKE_CASE_"
func _process_custom_fx(char_fx: CharFXTransform) -> bool:
diff --git a/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
index 283a95d3b4..458e22dae4 100644
--- a/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
+++ b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
@@ -1,6 +1,7 @@
# meta-description: Visual shader's node plugin template
@tool
+# Having a class name is required for a custom node.
class_name VisualShaderNode_CLASS_
extends _BASE_
@@ -17,7 +18,7 @@ func _get_description() -> String:
return ""
-func _get_return_icon_type() -> int:
+func _get_return_icon_type() -> PortType:
return PORT_TYPE_SCALAR
@@ -29,7 +30,7 @@ func _get_input_port_name(port: int) -> String:
return ""
-func _get_input_port_type(port: int) -> int:
+func _get_input_port_type(port: int) -> PortType:
return PORT_TYPE_SCALAR
@@ -41,10 +42,10 @@ func _get_output_port_name(port: int) -> String:
return "result"
-func _get_output_port_type(port: int) -> int:
+func _get_output_port_type(port: int) -> PortType:
return PORT_TYPE_SCALAR
func _get_code(input_vars: Array[String], output_vars: Array[String],
- mode: int, type: int) -> String:
+ mode: Shader.Mode, type: VisualShader.Type) -> String:
return output_vars[0] + " = 0.0;"
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 2fd2ec236a..2b698d75d4 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -195,6 +195,7 @@ public:
void clear(GDScript::ClearData *p_clear_data = nullptr);
virtual bool is_valid() const override { return valid; }
+ virtual bool is_abstract() const override { return false; } // GDScript does not support abstract classes.
bool inherits_script(const Ref<Script> &p_script) const override;
@@ -501,7 +502,9 @@ public:
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override;
virtual Script *create_script() const override;
- virtual bool has_named_classes() const override;
+#ifndef DISABLE_DEPRECATED
+ virtual bool has_named_classes() const override { return false; }
+#endif
virtual bool supports_builtin_mode() const override;
virtual bool supports_documentation() const override;
virtual bool can_inherit_from_file() const override { return true; }
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 00d3df8fd0..adfe4a3290 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -76,19 +76,25 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri
#endif
if (!type_hints) {
processed_template = processed_template.replace(": int", "")
+ .replace(": Shader.Mode", "")
+ .replace(": VisualShader.Type", "")
+ .replace(": float", "")
.replace(": String", "")
.replace(": Array[String]", "")
- .replace(": float", "")
+ .replace(": Node", "")
.replace(": CharFXTransform", "")
.replace(":=", "=")
- .replace(" -> String", "")
- .replace(" -> int", "")
+ .replace(" -> void", "")
.replace(" -> bool", "")
- .replace(" -> void", "");
+ .replace(" -> int", "")
+ .replace(" -> PortType", "")
+ .replace(" -> String", "")
+ .replace(" -> Object", "");
}
processed_template = processed_template.replace("_BASE_", p_base_class_name)
- .replace("_CLASS_", p_class_name.to_pascal_case())
+ .replace("_CLASS_SNAKE_CASE_", p_class_name.to_snake_case().validate_identifier())
+ .replace("_CLASS_", p_class_name.to_pascal_case().validate_identifier())
.replace("_TS_", _get_indentation());
scr->set_source_code(processed_template);
return scr;
@@ -191,10 +197,6 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
return true;
}
-bool GDScriptLanguage::has_named_classes() const {
- return false;
-}
-
bool GDScriptLanguage::supports_builtin_mode() const {
return true;
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index c0644e089c..be18dee2cf 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -398,7 +398,13 @@ void (*type_init_function_table[])(Variant *) = {
#define OPCODES_END
#define OPCODES_OUT
#define DISPATCH_OPCODE continue
+#ifdef _MSC_VER
+#define OPCODE_SWITCH(m_test) \
+ __assume(m_test <= OPCODE_END); \
+ switch (m_test)
+#else
#define OPCODE_SWITCH(m_test) switch (m_test)
+#endif
#define OPCODE_BREAK break
#define OPCODE_OUT break
#endif
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 1e927f9f6e..d6779dc71c 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -346,6 +346,15 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
}
}
+ if (item.kind == lsp::CompletionItemKind::Method) {
+ bool is_trigger_character = params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter;
+ bool is_quote_character = params.context.triggerCharacter == "\"" || params.context.triggerCharacter == "'";
+
+ if (is_trigger_character && is_quote_character && item.insertText.is_quoted()) {
+ item.insertText = item.insertText.unquote();
+ }
+ }
+
return item.to_json(true);
}
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index 1ac4267c7b..e09adb74bd 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -1429,6 +1429,17 @@ struct CompletionParams : public TextDocumentPositionParams {
TextDocumentPositionParams::load(p_params);
context.load(p_params["context"]);
}
+
+ Dictionary to_json() {
+ Dictionary ctx;
+ ctx["triggerCharacter"] = context.triggerCharacter;
+ ctx["triggerKind"] = context.triggerKind;
+
+ Dictionary dict;
+ dict = TextDocumentPositionParams::to_json();
+ dict["context"] = ctx;
+ return dict;
+ }
};
/**
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 6a20768583..b5a53fa1bf 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -1291,14 +1291,14 @@ GridMapEditor::GridMapEditor() {
search_box->connect("gui_input", callable_mp(this, &GridMapEditor::_sbox_input));
mode_thumbnail = memnew(Button);
- mode_thumbnail->set_flat(true);
+ mode_thumbnail->set_theme_type_variation("FlatButton");
mode_thumbnail->set_toggle_mode(true);
mode_thumbnail->set_pressed(true);
hb->add_child(mode_thumbnail);
mode_thumbnail->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_THUMBNAIL));
mode_list = memnew(Button);
- mode_list->set_flat(true);
+ mode_list->set_theme_type_variation("FlatButton");
mode_list->set_toggle_mode(true);
mode_list->set_pressed(false);
hb->add_child(mode_list);
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 26c684f769..95bf848cbf 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -392,10 +392,6 @@ Script *CSharpLanguage::create_script() const {
return memnew(CSharpScript);
}
-bool CSharpLanguage::has_named_classes() const {
- return false;
-}
-
bool CSharpLanguage::supports_builtin_mode() const {
return false;
}
@@ -554,13 +550,13 @@ bool CSharpLanguage::handles_global_class_type(const String &p_type) const {
String CSharpLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
Ref<CSharpScript> scr = ResourceLoader::load(p_path, get_type());
- if (!scr.is_valid() || !scr->valid || !scr->global_class) {
- // Invalid script or the script is not a global class.
- return String();
- }
+ // Always assign r_base_type and r_icon_path, even if the script
+ // is not a global one. In the case that it is not a global script,
+ // return an empty string AFTER assigning the return parameters.
+ // See GDScriptLanguage::get_global_class_name() in modules/gdscript/gdscript.cpp
- String name = scr->class_name;
- if (unlikely(name.is_empty())) {
+ if (!scr.is_valid() || !scr->valid) {
+ // Invalid script.
return String();
}
@@ -587,7 +583,8 @@ String CSharpLanguage::get_global_class_name(const String &p_path, String *r_bas
*r_base_type = scr->get_instance_base_type();
}
}
- return name;
+
+ return scr->global_class ? scr->class_name : String();
}
String CSharpLanguage::debug_get_error() const {
@@ -2300,6 +2297,7 @@ void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) {
void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
bool tool = false;
bool global_class = false;
+ bool abstract_class = false;
// TODO: Use GDExtension godot_dictionary
Array methods_array;
@@ -2313,12 +2311,13 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
String icon_path;
Ref<CSharpScript> base_script;
GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo(
- p_script.ptr(), &class_name, &tool, &global_class, &icon_path,
+ p_script.ptr(), &class_name, &tool, &global_class, &abstract_class, &icon_path,
&methods_array, &rpc_functions_dict, &signals_dict, &base_script);
p_script->class_name = class_name;
p_script->tool = tool;
p_script->global_class = global_class;
+ p_script->abstract_class = abstract_class;
p_script->icon_path = icon_path;
p_script->rpc_config.clear();
@@ -2408,7 +2407,7 @@ bool CSharpScript::can_instantiate() const {
ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'. Make sure the script exists and contains a class definition with a name that matches the filename of the script exactly (it's case-sensitive).");
}
- return valid && extra_cond;
+ return valid && !abstract_class && extra_cond;
}
StringName CSharpScript::get_instance_base_type() const {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index fd9e281e63..2ab80c132d 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -63,6 +63,7 @@ class CSharpScript : public Script {
bool tool = false;
bool global_class = false;
+ bool abstract_class = false;
bool valid = false;
bool reload_invalidated = false;
@@ -188,6 +189,9 @@ public:
bool is_valid() const override {
return valid;
}
+ bool is_abstract() const override {
+ return abstract_class;
+ }
bool inherits_script(const Ref<Script> &p_script) const override;
@@ -425,7 +429,9 @@ public:
}
String validate_path(const String &p_path) const override;
Script *create_script() const override;
- bool has_named_classes() const override;
+#ifndef DISABLE_DEPRECATED
+ virtual bool has_named_classes() const override { return false; }
+#endif
bool supports_builtin_mode() const override;
/* TODO? */ int find_function(const String &p_function, const String &p_code) const override {
return -1;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
index 5d6583b404..a78cb0bba9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -25,7 +25,7 @@ namespace Godot.Bridge
public delegate* unmanaged<godot_string*, godot_ref*, void> ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
public delegate* unmanaged<IntPtr, godot_bool> ScriptManagerBridge_TryReloadRegisteredScriptWithClass;
- public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, godot_bool*, godot_string*, godot_array*, godot_dictionary*, godot_dictionary*, godot_ref*, void> ScriptManagerBridge_UpdateScriptClassInfo;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, godot_bool*, godot_bool*, godot_string*, godot_array*, godot_dictionary*, godot_dictionary*, godot_ref*, void> ScriptManagerBridge_UpdateScriptClassInfo;
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 1a7d2d9075..9a7e19024b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -131,6 +132,8 @@ namespace Godot.Bridge
// Performance is not critical here as this will be replaced with source generators.
Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
+ Debug.Assert(!scriptType.IsAbstract, $"Cannot create script instance. The class '{scriptType.FullName}' is abstract.");
+
var ctor = scriptType
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(c => c.GetParameters().Length == argCount)
@@ -146,7 +149,7 @@ namespace Godot.Bridge
else
{
throw new MissingMemberException(
- $"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
+ $"The class '{scriptType.FullName}' does not define a constructor that takes {argCount} parameters.");
}
}
@@ -597,7 +600,7 @@ namespace Godot.Bridge
[UnmanagedCallersOnly]
internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, godot_string* outClassName,
- godot_bool* outTool, godot_bool* outGlobal, godot_string* outIconPath,
+ godot_bool* outTool, godot_bool* outGlobal, godot_bool* outAbstract, godot_string* outIconPath,
godot_array* outMethodsDest, godot_dictionary* outRpcFunctionsDest,
godot_dictionary* outEventSignalsDest, godot_ref* outBaseScript)
{
@@ -631,9 +634,10 @@ namespace Godot.Bridge
var iconAttr = scriptType.GetCustomAttributes(inherit: false)
.OfType<IconAttribute>()
.FirstOrDefault();
-
*outIconPath = Marshaling.ConvertStringToNative(iconAttr?.Path);
+ *outAbstract = scriptType.IsAbstract.ToGodotBool();
+
// Methods
// Performance is not critical here as this will be replaced with source generators.
@@ -799,6 +803,7 @@ namespace Godot.Bridge
*outClassName = default;
*outTool = godot_bool.False;
*outGlobal = godot_bool.False;
+ *outAbstract = godot_bool.False;
*outIconPath = default;
*outMethodsDest = NativeFuncs.godotsharp_array_new();
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 6ddc688ea0..dac8cdcaef 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -91,7 +91,7 @@ struct ManagedCallbacks {
using FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath = void(GD_CLR_STDCALL *)(const String *, Ref<CSharpScript> *);
using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *);
using FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass = bool(GD_CLR_STDCALL *)(const CSharpScript *);
- using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, String *, bool *, bool *, String *, Array *, Dictionary *, Dictionary *, Ref<CSharpScript> *);
+ using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, String *, bool *, bool *, bool *, String *, Array *, Dictionary *, Dictionary *, Ref<CSharpScript> *);
using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add);
using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add);
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 1c7546436b..89249dd369 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -245,24 +245,29 @@ ReplicationEditor::ReplicationEditor() {
add_pick_button->connect("pressed", callable_mp(this, &ReplicationEditor::_pick_new_property));
add_pick_button->set_text(TTR("Add property to sync..."));
hb->add_child(add_pick_button);
+
VSeparator *vs = memnew(VSeparator);
vs->set_custom_minimum_size(Size2(30 * EDSCALE, 0));
hb->add_child(vs);
hb->add_child(memnew(Label(TTR("Path:"))));
+
np_line_edit = memnew(LineEdit);
np_line_edit->set_placeholder(":property");
np_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
np_line_edit->connect("text_submitted", callable_mp(this, &ReplicationEditor::_np_text_submitted));
hb->add_child(np_line_edit);
+
add_from_path_button = memnew(Button);
add_from_path_button->connect("pressed", callable_mp(this, &ReplicationEditor::_add_pressed));
add_from_path_button->set_text(TTR("Add from path"));
hb->add_child(add_from_path_button);
+
vs = memnew(VSeparator);
vs->set_custom_minimum_size(Size2(30 * EDSCALE, 0));
hb->add_child(vs);
+
pin = memnew(Button);
- pin->set_flat(true);
+ pin->set_theme_type_variation("FlatButton");
pin->set_toggle_mode(true);
hb->add_child(pin);
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
index 85948e7547..d6c31ca35e 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
@@ -134,7 +134,7 @@ NavigationMeshEditor::NavigationMeshEditor() {
bake_hbox = memnew(HBoxContainer);
button_bake = memnew(Button);
- button_bake->set_flat(true);
+ button_bake->set_theme_type_variation("FlatButton");
bake_hbox->add_child(button_bake);
button_bake->set_toggle_mode(true);
button_bake->set_text(TTR("Bake NavigationMesh"));
@@ -142,7 +142,7 @@ NavigationMeshEditor::NavigationMeshEditor() {
button_bake->connect("pressed", callable_mp(this, &NavigationMeshEditor::_bake_pressed));
button_reset = memnew(Button);
- button_reset->set_flat(true);
+ button_reset->set_theme_type_variation("FlatButton");
bake_hbox->add_child(button_reset);
button_reset->set_text(TTR("Clear NavigationMesh"));
button_reset->set_tooltip_text(TTR("Clears the internal NavigationMesh vertices and polygons."));
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 1bd10f1009..c3a5d82fc4 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -110,6 +110,8 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_htc_controller_extens
env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_huawei_controller_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_fb_foveation_extension.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_fb_update_swapchain_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_pico_controller_extension.cpp")
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index 8d8cbf1a29..d0630626e6 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -77,6 +77,13 @@
Returns [code]true[/code] if the given action set is active.
</description>
</method>
+ <method name="is_foveation_supported" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if OpenXRs foveation extension is supported, the interface must be initialised before this returns a valid value.
+ [b]Note:[/b] This feature is only available on the compatibility renderer and currently only available on some stand alone headsets. For Vulkan set [member Viewport.vrs_mode] to [code]VRS_XR[/code] on desktop.
+ </description>
+ </method>
<method name="set_action_set_active">
<return type="void" />
<param index="0" name="name" type="String" />
@@ -98,6 +105,12 @@
<member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
The display refresh rate for the current HMD. Only functional if this feature is supported by the OpenXR runtime and after the interface has been initialized.
</member>
+ <member name="foveation_dynamic" type="bool" setter="set_foveation_dynamic" getter="get_foveation_dynamic" default="false">
+ Enable dynamic foveation adjustment, the interface must be initialised before this is accessible. If enabled foveation will automatically adjusted between low and [member foveation_level].
+ </member>
+ <member name="foveation_level" type="int" setter="set_foveation_level" getter="get_foveation_level" default="0">
+ Set foveation level from 0 (off) to 3 (high), the interface must be initialised before this is accessible.
+ </member>
<member name="render_target_size_multiplier" type="float" setter="set_render_target_size_multiplier" getter="get_render_target_size_multiplier" default="1.0">
The render size multiplier for the current HMD. Must be set before the interface has been initialized.
</member>
diff --git a/modules/openxr/extensions/openxr_fb_foveation_extension.cpp b/modules/openxr/extensions/openxr_fb_foveation_extension.cpp
new file mode 100644
index 0000000000..7277f85b12
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_foveation_extension.cpp
@@ -0,0 +1,168 @@
+/**************************************************************************/
+/* openxr_fb_foveation_extension.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_fb_foveation_extension.h"
+#include "core/config/project_settings.h"
+
+OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::singleton = nullptr;
+
+OpenXRFBFoveationExtension *OpenXRFBFoveationExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRFBFoveationExtension::OpenXRFBFoveationExtension(const String &p_rendering_driver) {
+ singleton = this;
+ rendering_driver = p_rendering_driver;
+ swapchain_update_state_ext = OpenXRFBUpdateSwapchainExtension::get_singleton();
+ int fov_level = GLOBAL_GET("xr/openxr/foveation_level");
+ if (fov_level >= 0 && fov_level < 4) {
+ foveation_level = XrFoveationLevelFB(fov_level);
+ }
+ bool fov_dyn = GLOBAL_GET("xr/openxr/foveation_dynamic");
+ foveation_dynamic = fov_dyn ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB;
+
+ swapchain_create_info_foveation_fb.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
+ swapchain_create_info_foveation_fb.next = nullptr;
+ swapchain_create_info_foveation_fb.flags = 0;
+}
+
+OpenXRFBFoveationExtension::~OpenXRFBFoveationExtension() {
+ singleton = nullptr;
+ swapchain_update_state_ext = nullptr;
+}
+
+HashMap<String, bool *> OpenXRFBFoveationExtension::get_requested_extensions() {
+ HashMap<String, bool *> request_extensions;
+
+ if (rendering_driver == "vulkan") {
+ // This is currently only supported on OpenGL, but we may add Vulkan support in the future...
+
+ } else if (rendering_driver == "opengl3") {
+ request_extensions[XR_FB_FOVEATION_EXTENSION_NAME] = &fb_foveation_ext;
+ request_extensions[XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME] = &fb_foveation_configuration_ext;
+ }
+
+ return request_extensions;
+}
+
+void OpenXRFBFoveationExtension::on_instance_created(const XrInstance p_instance) {
+ if (fb_foveation_ext) {
+ EXT_INIT_XR_FUNC(xrCreateFoveationProfileFB);
+ EXT_INIT_XR_FUNC(xrDestroyFoveationProfileFB);
+ }
+
+ if (fb_foveation_configuration_ext) {
+ // nothing to register here...
+ }
+}
+
+void OpenXRFBFoveationExtension::on_instance_destroyed() {
+ fb_foveation_ext = false;
+ fb_foveation_configuration_ext = false;
+}
+
+bool OpenXRFBFoveationExtension::is_enabled() const {
+ return swapchain_update_state_ext != nullptr && swapchain_update_state_ext->is_enabled() && fb_foveation_ext && fb_foveation_configuration_ext;
+}
+
+void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {
+ if (is_enabled()) {
+ swapchain_create_info_foveation_fb.next = p_next_pointer;
+ return &swapchain_create_info_foveation_fb;
+ } else {
+ return p_next_pointer;
+ }
+}
+
+void OpenXRFBFoveationExtension::on_state_ready() {
+ update_profile();
+}
+
+XrFoveationLevelFB OpenXRFBFoveationExtension::get_foveation_level() const {
+ return foveation_level;
+}
+
+void OpenXRFBFoveationExtension::set_foveation_level(XrFoveationLevelFB p_foveation_level) {
+ foveation_level = p_foveation_level;
+
+ // Update profile will do nothing if we're not yet initialised
+ update_profile();
+}
+
+XrFoveationDynamicFB OpenXRFBFoveationExtension::get_foveation_dynamic() const {
+ return foveation_dynamic;
+}
+
+void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic) {
+ foveation_dynamic = p_foveation_dynamic;
+
+ // Update profile will do nothing if we're not yet initialised
+ update_profile();
+}
+
+void OpenXRFBFoveationExtension::update_profile() {
+ if (!is_enabled()) {
+ return;
+ }
+
+ XrFoveationLevelProfileCreateInfoFB level_profile_create_info;
+ level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
+ level_profile_create_info.next = nullptr;
+ level_profile_create_info.level = foveation_level;
+ level_profile_create_info.verticalOffset = 0.0f;
+ level_profile_create_info.dynamic = foveation_dynamic;
+
+ XrFoveationProfileCreateInfoFB profile_create_info;
+ profile_create_info.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
+ profile_create_info.next = &level_profile_create_info;
+
+ XrFoveationProfileFB foveation_profile;
+ XrResult result = xrCreateFoveationProfileFB(OpenXRAPI::get_singleton()->get_session(), &profile_create_info, &foveation_profile);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Unable to create the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
+ return;
+ }
+
+ XrSwapchainStateFoveationFB foveation_update_state;
+ foveation_update_state.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
+ foveation_update_state.profile = foveation_profile;
+
+ result = swapchain_update_state_ext->xrUpdateSwapchainFB(OpenXRAPI::get_singleton()->get_color_swapchain(), (XrSwapchainStateBaseHeaderFB *)&foveation_update_state);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Unable to update the swapchain [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
+
+ // We still want to destroy our profile so keep going...
+ }
+
+ result = xrDestroyFoveationProfileFB(foveation_profile);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Unable to destroy the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
+ }
+}
diff --git a/modules/openxr/extensions/openxr_fb_foveation_extension.h b/modules/openxr/extensions/openxr_fb_foveation_extension.h
new file mode 100644
index 0000000000..1c5e722731
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_foveation_extension.h
@@ -0,0 +1,96 @@
+/**************************************************************************/
+/* openxr_fb_foveation_extension.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_FB_FOVEATION_EXTENSION_H
+#define OPENXR_FB_FOVEATION_EXTENSION_H
+
+// This extension implements the FB Foveation extension.
+// This is an extension Meta added due to VRS being unavailable on Android.
+// Other Android based devices are implementing this as well, see:
+// https://github.khronos.org/OpenXR-Inventory/extension_support.html#XR_FB_foveation
+
+// Note: Currently we only support this for OpenGL.
+// This extension works on enabling foveated rendering on the swapchain.
+// Vulkan does not render 3D content directly to the swapchain image
+// hence this extension can't be used.
+
+#include "../openxr_api.h"
+#include "../util.h"
+#include "openxr_extension_wrapper.h"
+#include "openxr_fb_update_swapchain_extension.h"
+
+class OpenXRFBFoveationExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRFBFoveationExtension *get_singleton();
+
+ OpenXRFBFoveationExtension(const String &p_rendering_driver);
+ virtual ~OpenXRFBFoveationExtension() override;
+
+ virtual HashMap<String, bool *> get_requested_extensions() override;
+
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void on_instance_destroyed() override;
+
+ virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
+
+ virtual void on_state_ready() override;
+
+ bool is_enabled() const;
+
+ XrFoveationLevelFB get_foveation_level() const;
+ void set_foveation_level(XrFoveationLevelFB p_foveation_level);
+
+ XrFoveationDynamicFB get_foveation_dynamic() const;
+ void set_foveation_dynamic(XrFoveationDynamicFB p_foveation_dynamic);
+
+private:
+ static OpenXRFBFoveationExtension *singleton;
+
+ // Setup
+ String rendering_driver;
+ bool fb_foveation_ext = false;
+ bool fb_foveation_configuration_ext = false;
+
+ // Configuration
+ XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;
+ XrFoveationDynamicFB foveation_dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB;
+
+ void update_profile();
+
+ // Enable foveation on this swapchain
+ XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb;
+ OpenXRFBUpdateSwapchainExtension *swapchain_update_state_ext = nullptr;
+
+ // OpenXR API call wrappers
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateFoveationProfileFB, (XrSession), session, (const XrFoveationProfileCreateInfoFB *), create_info, (XrFoveationProfileFB *), profile);
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroyFoveationProfileFB, (XrFoveationProfileFB), profile);
+};
+
+#endif // OPENXR_FB_FOVEATION_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_fb_update_swapchain_extension.cpp b/modules/openxr/extensions/openxr_fb_update_swapchain_extension.cpp
new file mode 100644
index 0000000000..1289183ea4
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_update_swapchain_extension.cpp
@@ -0,0 +1,102 @@
+/**************************************************************************/
+/* openxr_fb_update_swapchain_extension.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_fb_update_swapchain_extension.h"
+
+// always include this as late as possible
+#include "../openxr_platform_inc.h"
+
+OpenXRFBUpdateSwapchainExtension *OpenXRFBUpdateSwapchainExtension::singleton = nullptr;
+
+OpenXRFBUpdateSwapchainExtension *OpenXRFBUpdateSwapchainExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRFBUpdateSwapchainExtension::OpenXRFBUpdateSwapchainExtension(const String &p_rendering_driver) {
+ singleton = this;
+ rendering_driver = p_rendering_driver;
+}
+
+OpenXRFBUpdateSwapchainExtension::~OpenXRFBUpdateSwapchainExtension() {
+ singleton = nullptr;
+}
+
+HashMap<String, bool *> OpenXRFBUpdateSwapchainExtension::get_requested_extensions() {
+ HashMap<String, bool *> request_extensions;
+
+ request_extensions[XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME] = &fb_swapchain_update_state_ext;
+
+ if (rendering_driver == "vulkan") {
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+ request_extensions[XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME] = &fb_swapchain_update_state_vulkan_ext;
+#endif
+ } else if (rendering_driver == "opengl3") {
+#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
+ request_extensions[XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME] = &fb_swapchain_update_state_opengles_ext;
+#endif
+ }
+
+ return request_extensions;
+}
+
+void OpenXRFBUpdateSwapchainExtension::on_instance_created(const XrInstance p_instance) {
+ if (fb_swapchain_update_state_ext) {
+ EXT_INIT_XR_FUNC(xrUpdateSwapchainFB);
+ EXT_INIT_XR_FUNC(xrGetSwapchainStateFB);
+ }
+
+ if (fb_swapchain_update_state_vulkan_ext) {
+ // nothing to register here...
+ }
+
+ if (fb_swapchain_update_state_opengles_ext) {
+ // nothing to register here...
+ }
+}
+
+void OpenXRFBUpdateSwapchainExtension::on_instance_destroyed() {
+ fb_swapchain_update_state_ext = false;
+ fb_swapchain_update_state_vulkan_ext = false;
+ fb_swapchain_update_state_opengles_ext = false;
+}
+
+bool OpenXRFBUpdateSwapchainExtension::is_enabled() const {
+ if (rendering_driver == "vulkan") {
+ return fb_swapchain_update_state_ext && fb_swapchain_update_state_vulkan_ext;
+ } else if (rendering_driver == "opengl3") {
+#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
+ return fb_swapchain_update_state_ext && fb_swapchain_update_state_opengles_ext;
+#else
+ return fb_swapchain_update_state_ext;
+#endif
+ }
+
+ return false;
+}
diff --git a/modules/openxr/extensions/openxr_fb_update_swapchain_extension.h b/modules/openxr/extensions/openxr_fb_update_swapchain_extension.h
new file mode 100644
index 0000000000..a02b550e58
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_update_swapchain_extension.h
@@ -0,0 +1,73 @@
+/**************************************************************************/
+/* openxr_fb_update_swapchain_extension.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_FB_UPDATE_SWAPCHAIN_EXTENSION_H
+#define OPENXR_FB_UPDATE_SWAPCHAIN_EXTENSION_H
+
+// This extension implements the FB update swapchain extension.
+// This is an extension Meta added to further configure the swapchain.
+// Other Android based devices are implementing this as well, see:
+// https://github.khronos.org/OpenXR-Inventory/extension_support.html#XR_FB_swapchain_update_state
+
+#include "../openxr_api.h"
+#include "../util.h"
+#include "openxr_extension_wrapper.h"
+
+class OpenXRFBUpdateSwapchainExtension : public OpenXRExtensionWrapper {
+ friend class OpenXRFBFoveationExtension;
+
+public:
+ static OpenXRFBUpdateSwapchainExtension *get_singleton();
+
+ OpenXRFBUpdateSwapchainExtension(const String &p_rendering_driver);
+ virtual ~OpenXRFBUpdateSwapchainExtension() override;
+
+ virtual HashMap<String, bool *> get_requested_extensions() override;
+
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void on_instance_destroyed() override;
+
+ bool is_enabled() const;
+
+private:
+ static OpenXRFBUpdateSwapchainExtension *singleton;
+
+ // Setup
+ String rendering_driver;
+ bool fb_swapchain_update_state_ext = false;
+ bool fb_swapchain_update_state_vulkan_ext = false;
+ bool fb_swapchain_update_state_opengles_ext = false;
+
+ // OpenXR API call wrappers
+ EXT_PROTO_XRRESULT_FUNC2(xrUpdateSwapchainFB, (XrSwapchain), swapchain, (const XrSwapchainStateBaseHeaderFB *), state);
+ EXT_PROTO_XRRESULT_FUNC2(xrGetSwapchainStateFB, (XrSwapchain), swapchain, (XrSwapchainStateBaseHeaderFB *), state);
+};
+
+#endif // OPENXR_FB_UPDATE_SWAPCHAIN_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h
index 1537f13067..3b0aa0bce9 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.h
+++ b/modules/openxr/extensions/openxr_opengl_extension.h
@@ -39,38 +39,8 @@
#include "core/templates/vector.h"
-#ifdef ANDROID_ENABLED
-#define XR_USE_GRAPHICS_API_OPENGL_ES
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#else
-#define XR_USE_GRAPHICS_API_OPENGL
-#endif
-
-#ifdef WINDOWS_ENABLED
-// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
-// however due to the way the openxr headers are put together, we have no choice.
-#include <windows.h>
-#endif
-
-#ifdef X11_ENABLED
-#define GL_GLEXT_PROTOTYPES 1
-#define GL3_PROTOTYPES 1
-#include "thirdparty/glad/glad/gl.h"
-#include "thirdparty/glad/glad/glx.h"
-
-#include <X11/Xlib.h>
-#endif
-
-#ifdef ANDROID_ENABLED
-// The jobject type from jni.h is used by openxr_platform.h on Android.
-#include <jni.h>
-#endif
-
-// Include platform dependent structs.
-#include <openxr/openxr_platform.h>
+// always include this as late as possible
+#include "../openxr_platform_inc.h"
class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
public:
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h
index 4add6f6fa2..f31621fda0 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/openxr_vulkan_extension.h
@@ -36,24 +36,9 @@
#include "openxr_extension_wrapper.h"
#include "core/templates/vector.h"
-#include "drivers/vulkan/vulkan_context.h"
-// Need to include Vulkan so we know of type definitions.
-#define XR_USE_GRAPHICS_API_VULKAN
-
-#ifdef WINDOWS_ENABLED
-// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
-// however due to the way the openxr headers are put together, we have no choice.
-#include <windows.h>
-#endif
-
-#ifdef ANDROID_ENABLED
-// The jobject type from jni.h is used by openxr_platform.h on Android.
-#include <jni.h>
-#endif
-
-// Include platform dependent structs.
-#include <openxr/openxr_platform.h>
+// always include this as late as possible
+#include "../openxr_platform_inc.h"
class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
public:
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 972b6539e3..b1c7ab1615 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -43,30 +43,7 @@
#include "editor/editor_settings.h"
#endif
-// We need to have all the graphics API defines before the Vulkan or OpenGL
-// extensions are included, otherwise we'll only get one graphics API.
-#ifdef VULKAN_ENABLED
-#define XR_USE_GRAPHICS_API_VULKAN
-#endif
-#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
-#ifdef ANDROID_ENABLED
-#define XR_USE_GRAPHICS_API_OPENGL_ES
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#else
-#define XR_USE_GRAPHICS_API_OPENGL
-#endif // ANDROID_ENABLED
-#ifdef X11_ENABLED
-#define GL_GLEXT_PROTOTYPES 1
-#define GL3_PROTOTYPES 1
-#include "thirdparty/glad/glad/gl.h"
-#include "thirdparty/glad/glad/glx.h"
-
-#include <X11/Xlib.h>
-#endif // X11_ENABLED
-#endif // GLES_ENABLED
+#include "openxr_platform_inc.h"
#ifdef VULKAN_ENABLED
#include "extensions/openxr_vulkan_extension.h"
@@ -78,7 +55,9 @@
#include "extensions/openxr_composition_layer_depth_extension.h"
#include "extensions/openxr_fb_display_refresh_rate_extension.h"
+#include "extensions/openxr_fb_foveation_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
+#include "extensions/openxr_fb_update_swapchain_extension.h"
#ifdef ANDROID_ENABLED
#define OPENXR_LOADER_NAME "libopenxr_loader.so"
@@ -1340,6 +1319,10 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
ERR_FAIL_V_MSG(false, "OpenXR: Unsupported rendering device.");
}
+ // Also register our rendering extensions
+ register_extension_wrapper(memnew(OpenXRFBUpdateSwapchainExtension(p_rendering_driver)));
+ register_extension_wrapper(memnew(OpenXRFBFoveationExtension(p_rendering_driver)));
+
// initialize
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_before_instance_created();
@@ -1859,6 +1842,10 @@ bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {
return true;
}
+XrSwapchain OpenXRAPI::get_color_swapchain() {
+ return swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain;
+}
+
RID OpenXRAPI::get_color_texture() {
if (swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_COLOR].image_index);
@@ -2010,6 +1997,55 @@ void OpenXRAPI::set_render_target_size_multiplier(double multiplier) {
render_target_size_multiplier = multiplier;
}
+bool OpenXRAPI::is_foveation_supported() const {
+ OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
+ return fov_ext != nullptr && fov_ext->is_enabled();
+}
+
+int OpenXRAPI::get_foveation_level() const {
+ OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
+ if (fov_ext != nullptr && fov_ext->is_enabled()) {
+ switch (fov_ext->get_foveation_level()) {
+ case XR_FOVEATION_LEVEL_NONE_FB:
+ return 0;
+ case XR_FOVEATION_LEVEL_LOW_FB:
+ return 1;
+ case XR_FOVEATION_LEVEL_MEDIUM_FB:
+ return 2;
+ case XR_FOVEATION_LEVEL_HIGH_FB:
+ return 3;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+void OpenXRAPI::set_foveation_level(int p_foveation_level) {
+ ERR_FAIL_UNSIGNED_INDEX(p_foveation_level, 4);
+ OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
+ if (fov_ext != nullptr && fov_ext->is_enabled()) {
+ XrFoveationLevelFB levels[] = { XR_FOVEATION_LEVEL_NONE_FB, XR_FOVEATION_LEVEL_LOW_FB, XR_FOVEATION_LEVEL_MEDIUM_FB, XR_FOVEATION_LEVEL_HIGH_FB };
+ fov_ext->set_foveation_level(levels[p_foveation_level]);
+ }
+}
+
+bool OpenXRAPI::get_foveation_dynamic() const {
+ OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
+ if (fov_ext != nullptr && fov_ext->is_enabled()) {
+ return fov_ext->get_foveation_dynamic() == XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB;
+ }
+ return false;
+}
+
+void OpenXRAPI::set_foveation_dynamic(bool p_foveation_dynamic) {
+ OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
+ if (fov_ext != nullptr && fov_ext->is_enabled()) {
+ fov_ext->set_foveation_dynamic(p_foveation_dynamic ? XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB : XR_FOVEATION_DYNAMIC_DISABLED_FB);
+ }
+}
+
OpenXRAPI::OpenXRAPI() {
// OpenXRAPI is only constructed if OpenXR is enabled.
singleton = this;
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 26de535153..89f8f3cbec 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -54,7 +54,6 @@
// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set.
// forward declarations, we don't want to include these fully
-class OpenXRVulkanExtension;
class OpenXRInterface;
class OpenXRAPI {
@@ -356,6 +355,7 @@ public:
void pre_render();
bool pre_draw_viewport(RID p_render_target);
+ XrSwapchain get_color_swapchain();
RID get_color_texture();
RID get_depth_texture();
void post_draw_viewport(RID p_render_target);
@@ -370,6 +370,15 @@ public:
double get_render_target_size_multiplier() const;
void set_render_target_size_multiplier(double multiplier);
+ // Foveation settings
+ bool is_foveation_supported() const;
+
+ int get_foveation_level() const;
+ void set_foveation_level(int p_foveation_level);
+
+ bool get_foveation_dynamic() const;
+ void set_foveation_dynamic(bool p_foveation_dynamic);
+
// action map
String get_default_action_map_resource_name();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index cf8d1654b1..7b1530677f 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -54,10 +54,23 @@ void OpenXRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_render_target_size_multiplier", "multiplier"), &OpenXRInterface::set_render_target_size_multiplier);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "render_target_size_multiplier"), "set_render_target_size_multiplier", "get_render_target_size_multiplier");
+ // Foveation level
+ ClassDB::bind_method(D_METHOD("is_foveation_supported"), &OpenXRInterface::is_foveation_supported);
+
+ ClassDB::bind_method(D_METHOD("get_foveation_level"), &OpenXRInterface::get_foveation_level);
+ ClassDB::bind_method(D_METHOD("set_foveation_level", "foveation_level"), &OpenXRInterface::set_foveation_level);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "foveation_level"), "set_foveation_level", "get_foveation_level");
+
+ ClassDB::bind_method(D_METHOD("get_foveation_dynamic"), &OpenXRInterface::get_foveation_dynamic);
+ ClassDB::bind_method(D_METHOD("set_foveation_dynamic", "foveation_dynamic"), &OpenXRInterface::set_foveation_dynamic);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "foveation_dynamic"), "set_foveation_dynamic", "get_foveation_dynamic");
+
+ // Action sets
ClassDB::bind_method(D_METHOD("is_action_set_active", "name"), &OpenXRInterface::is_action_set_active);
ClassDB::bind_method(D_METHOD("set_action_set_active", "name", "active"), &OpenXRInterface::set_action_set_active);
ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRInterface::get_action_sets);
+ // Refresh rates
ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
// Hand tracking.
@@ -740,6 +753,46 @@ void OpenXRInterface::set_render_target_size_multiplier(double multiplier) {
}
}
+bool OpenXRInterface::is_foveation_supported() const {
+ if (openxr_api == nullptr) {
+ return false;
+ } else {
+ return openxr_api->is_foveation_supported();
+ }
+}
+
+int OpenXRInterface::get_foveation_level() const {
+ if (openxr_api == nullptr) {
+ return 0;
+ } else {
+ return openxr_api->get_foveation_level();
+ }
+}
+
+void OpenXRInterface::set_foveation_level(int p_foveation_level) {
+ if (openxr_api == nullptr) {
+ return;
+ } else {
+ openxr_api->set_foveation_level(p_foveation_level);
+ }
+}
+
+bool OpenXRInterface::get_foveation_dynamic() const {
+ if (openxr_api == nullptr) {
+ return false;
+ } else {
+ return openxr_api->get_foveation_dynamic();
+ }
+}
+
+void OpenXRInterface::set_foveation_dynamic(bool p_foveation_dynamic) {
+ if (openxr_api == nullptr) {
+ return;
+ } else {
+ openxr_api->set_foveation_dynamic(p_foveation_dynamic);
+ }
+}
+
Size2 OpenXRInterface::get_render_target_size() {
if (openxr_api == nullptr) {
return Size2();
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 81efbd6777..38cf4bdbe8 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -130,6 +130,14 @@ public:
double get_render_target_size_multiplier() const;
void set_render_target_size_multiplier(double multiplier);
+ bool is_foveation_supported() const;
+
+ int get_foveation_level() const;
+ void set_foveation_level(int p_foveation_level);
+
+ bool get_foveation_dynamic() const;
+ void set_foveation_dynamic(bool p_foveation_dynamic);
+
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
diff --git a/modules/openxr/openxr_platform_inc.h b/modules/openxr/openxr_platform_inc.h
new file mode 100644
index 0000000000..6288d1e380
--- /dev/null
+++ b/modules/openxr/openxr_platform_inc.h
@@ -0,0 +1,78 @@
+/**************************************************************************/
+/* openxr_platform_inc.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_PLATFORM_INC_H
+#define OPENXR_PLATFORM_INC_H
+
+// In various places we need to include platform definitions but we can't
+// include these in our normal header files as we'll end up with issues.
+
+#ifdef VULKAN_ENABLED
+#define XR_USE_GRAPHICS_API_VULKAN
+#include "drivers/vulkan/vulkan_context.h"
+#endif // VULKAN_ENABLED
+
+#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
+#ifdef ANDROID_ENABLED
+#define XR_USE_GRAPHICS_API_OPENGL_ES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#else
+#define XR_USE_GRAPHICS_API_OPENGL
+#endif // ANDROID_ENABLED
+#ifdef X11_ENABLED
+#define GL_GLEXT_PROTOTYPES 1
+#define GL3_PROTOTYPES 1
+#include "thirdparty/glad/glad/gl.h"
+#include "thirdparty/glad/glad/glx.h"
+#endif // X11_ENABLED
+#endif // defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
+
+#ifdef X11_ENABLED
+#include <X11/Xlib.h>
+#endif // X11_ENABLED
+
+#ifdef WINDOWS_ENABLED
+// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
+// however due to the way the openxr headers are put together, we have no choice.
+#include <windows.h>
+#endif // WINDOWS_ENABLED
+
+#ifdef ANDROID_ENABLED
+// The jobject type from jni.h is used by openxr_platform.h on Android.
+#include <jni.h>
+#endif // ANDROID_ENABLED
+
+// Include platform dependent structs.
+#include <openxr/openxr_platform.h>
+
+#endif // OPENXR_PLATFORM_INC_H