diff options
Diffstat (limited to 'modules')
41 files changed, 822 insertions, 170 deletions
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index ba9b96db74..73771b3639 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -57,7 +57,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { } String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d()); if (Object::cast_to<CSGSphere3D>(cs)) { return "Radius"; @@ -79,7 +79,7 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, } Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d()); if (Object::cast_to<CSGSphere3D>(cs)) { CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs); @@ -105,7 +105,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo } void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d()); Transform3D gt = cs->get_global_transform(); //gt.orthonormalize(); @@ -208,7 +208,7 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i } void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d()); if (Object::cast_to<CSGSphere3D>(cs)) { CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs); @@ -308,7 +308,7 @@ bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const { void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->clear(); - CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d()); Vector<Vector3> faces = cs->get_brush_faces(); diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 46a9b33eb0..fa7e5924f9 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -437,11 +437,11 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { if (!p_docs_down) { // inline comment String inline_comment = lines[p_line]; - int comment_start = inline_comment.find("#"); + int comment_start = inline_comment.find("##"); if (comment_start != -1) { inline_comment = inline_comment.substr(comment_start, inline_comment.length()).strip_edges(); if (inline_comment.length() > 1) { - doc_lines.push_back(inline_comment.substr(1, inline_comment.length())); + doc_lines.push_back(inline_comment.substr(2, inline_comment.length())); } } } @@ -454,8 +454,8 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { } String line_comment = lines[i].strip_edges(true, false); - if (line_comment.begins_with("#")) { - line_comment = line_comment.substr(1, line_comment.length()); + if (line_comment.begins_with("##")) { + line_comment = line_comment.substr(2, line_comment.length()); if (p_docs_down) { doc_lines.push_back(line_comment); } else { diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index ccde0521f2..189e7fcc71 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -42,6 +42,7 @@ void GDScriptTextDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose); ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange); + ClassDB::bind_method(D_METHOD("willSaveWaitUntil"), &GDScriptTextDocument::willSaveWaitUntil); ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave); ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol); ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol); @@ -81,6 +82,16 @@ void GDScriptTextDocument::didChange(const Variant &p_param) { sync_script_content(doc.uri, doc.text); } +void GDScriptTextDocument::willSaveWaitUntil(const Variant &p_param) { + lsp::TextDocumentItem doc = load_document_item(p_param); + + String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); + Ref<Script> script = ResourceLoader::load(path); + if (script.is_valid()) { + ScriptEditor::get_singleton()->clear_docs_from_script(script); + } +} + void GDScriptTextDocument::didSave(const Variant &p_param) { lsp::TextDocumentItem doc = load_document_item(p_param); Dictionary dict = p_param; @@ -88,11 +99,16 @@ void GDScriptTextDocument::didSave(const Variant &p_param) { sync_script_content(doc.uri, text); - /*String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); - + String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); Ref<GDScript> script = ResourceLoader::load(path); - script->load_source_code(path); - script->reload(true);*/ + if (script.is_valid() && (script->load_source_code(path) == OK)) { + if (script->is_tool()) { + script->get_language()->reload_tool_script(script, true); + } else { + script->reload(true); + } + ScriptEditor::get_singleton()->update_docs_from_script(script); + } } lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) { @@ -417,14 +433,6 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); EditorFileSystem::get_singleton()->update_file(path); - Error error; - Ref<GDScript> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error); - if (error == OK) { - if (script->load_source_code(path) == OK) { - script->reload(true); - ScriptEditor::get_singleton()->reload_scripts(true); // Refresh scripts opened in the internal editor. - } - } } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 87bc08a34e..456c7d71fe 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -45,6 +45,7 @@ protected: void didOpen(const Variant &p_param); void didClose(const Variant &p_param); void didChange(const Variant &p_param); + void willSaveWaitUntil(const Variant &p_param); void didSave(const Variant &p_param); void sync_script_content(const String &p_path, const String &p_content); diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h index fbd40796c4..024da1cab7 100644 --- a/modules/gdscript/language_server/godot_lsp.h +++ b/modules/gdscript/language_server/godot_lsp.h @@ -546,7 +546,7 @@ struct TextDocumentSyncOptions { * If present will save wait until requests are sent to the server. If omitted the request should not be * sent. */ - bool willSaveWaitUntil = false; + bool willSaveWaitUntil = true; /** * If present save notifications are sent to the server. If omitted the notification should not be diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.out b/modules/gdscript/tests/scripts/parser/features/dictionary.out index 5f999f573a..e1eeb46f78 100644 --- a/modules/gdscript/tests/scripts/parser/features/dictionary.out +++ b/modules/gdscript/tests/scripts/parser/features/dictionary.out @@ -7,8 +7,8 @@ null false empty array zero Vector2i -{22:{4:["nesting", "arrays"]}} -{4:["nesting", "arrays"]} +{ 22: { 4: ["nesting", "arrays"] } } +{ 4: ["nesting", "arrays"] } ["nesting", "arrays"] nesting arrays diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out index 5143d040a9..553d40d953 100644 --- a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out @@ -1,2 +1,2 @@ GDTEST_OK -{"a":1, "b":2, "with spaces":3, "2":4} +{ "a": 1, "b": 2, "with spaces": 3, "2": 4 } diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out index dd28609850..cf79845f53 100644 --- a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out @@ -1,2 +1,2 @@ GDTEST_OK -{"hello":{"world":{"is":"beautiful"}}} +{ "hello": { "world": { "is": "beautiful" } } } diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out index 8b8c33202f..508f0ff217 100644 --- a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out +++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out @@ -1,5 +1,5 @@ GDTEST_OK -{8:{"key":"value"}} -{"key":"value"} +{ 8: { "key": "value" } } +{ "key": "value" } value value diff --git a/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out b/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out index 5e7ccf534a..22929bf636 100644 --- a/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out +++ b/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out @@ -1,6 +1,6 @@ GDTEST_OK -{1:(2, 0)} -{3:(4, 0)} +{ 1: (2, 0) } +{ 3: (4, 0) } [[(5, 0)]] [[(6, 0)]] [[(7, 0)]] diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out index d4468737a5..1f33de00cc 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.out +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out @@ -21,7 +21,7 @@ hello/world RID(0) Node::get_name Node::[signal]property_list_changed -{"hello":123} +{ "hello": 123 } ["hello", 123] [255, 0, 1] [-1, 0, 1] diff --git a/modules/gltf/config.py b/modules/gltf/config.py index 189b5a831a..130c06d264 100644 --- a/modules/gltf/config.py +++ b/modules/gltf/config.py @@ -26,6 +26,7 @@ def get_doc_classes(): "GLTFSpecGloss", "GLTFState", "GLTFTexture", + "GLTFTextureSampler", ] diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 6c2f488c1c..56f3a70631 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -93,6 +93,12 @@ <description> </description> </method> + <method name="get_texture_samplers"> + <return type="GLTFTextureSampler[]" /> + <description> + Retrieves the array of texture samplers that are used by the textures contained in the GLTF. + </description> + </method> <method name="get_textures"> <return type="GLTFTexture[]" /> <description> @@ -180,6 +186,13 @@ <description> </description> </method> + <method name="set_texture_samplers"> + <return type="void" /> + <param index="0" name="texture_samplers" type="GLTFTextureSampler[]" /> + <description> + Sets the array of texture samplers that are used by the textures contained in the GLTF. + </description> + </method> <method name="set_textures"> <return type="void" /> <param index="0" name="textures" type="GLTFTexture[]" /> diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml index c0bc424168..f4486fd504 100644 --- a/modules/gltf/doc_classes/GLTFTexture.xml +++ b/modules/gltf/doc_classes/GLTFTexture.xml @@ -7,6 +7,9 @@ <tutorials> </tutorials> <members> + <member name="sampler" type="int" setter="set_sampler" getter="get_sampler" default="-1"> + ID of the texture sampler to use when sampling the image. If -1, then the default texture sampler is used (linear filtering, and repeat wrapping in both axes). + </member> <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0"> </member> </members> diff --git a/modules/gltf/doc_classes/GLTFTextureSampler.xml b/modules/gltf/doc_classes/GLTFTextureSampler.xml new file mode 100644 index 0000000000..1cc69bfe73 --- /dev/null +++ b/modules/gltf/doc_classes/GLTFTextureSampler.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="GLTFTextureSampler" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Represents a GLTF texture sampler + </brief_description> + <description> + Represents a texture sampler as defined by the base GLTF spec. Texture samplers in GLTF specify how to sample data from the texture's base image, when rendering the texture on an object. + </description> + <tutorials> + </tutorials> + <members> + <member name="mag_filter" type="int" setter="set_mag_filter" getter="get_mag_filter" default="9729"> + Texture's magnification filter, used when texture appears larger on screen than the source image. + </member> + <member name="min_filter" type="int" setter="set_min_filter" getter="get_min_filter" default="9987"> + Texture's minification filter, used when the texture appears smaller on screen than the source image. + </member> + <member name="wrap_s" type="int" setter="set_wrap_s" getter="get_wrap_s" default="10497"> + Wrapping mode to use for S-axis (horizontal) texture coordinates. + </member> + <member name="wrap_t" type="int" setter="set_wrap_t" getter="get_wrap_t" default="10497"> + Wrapping mode to use for T-axis (vertical) texture coordinates. + </member> + </members> +</class> diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index f79731dd22..dcf59bce24 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -77,20 +77,19 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ } else { parameters_arg += "export_extras=False,"; } - if (p_options.has(SNAME("blender/meshes/skins")) && p_options[SNAME("blender/meshes/skins")]) { + if (p_options.has(SNAME("blender/meshes/skins"))) { int32_t skins = p_options["blender/meshes/skins"]; if (skins == BLEND_BONE_INFLUENCES_NONE) { - parameters_arg += "export_all_influences=False,"; + parameters_arg += "export_skins=False,"; } else if (skins == BLEND_BONE_INFLUENCES_COMPATIBLE) { - parameters_arg += "export_all_influences=False,"; + parameters_arg += "export_all_influences=False,export_skins=True,"; } else if (skins == BLEND_BONE_INFLUENCES_ALL) { - parameters_arg += "export_all_influences=True,"; + parameters_arg += "export_all_influences=True,export_skins=True,"; } - parameters_arg += "export_skins=True,"; } else { parameters_arg += "export_skins=False,"; } - if (p_options.has(SNAME("blender/materials/export_materials")) && p_options[SNAME("blender/materials/export_materials")]) { + if (p_options.has(SNAME("blender/materials/export_materials"))) { int32_t exports = p_options["blender/materials/export_materials"]; if (exports == BLEND_MATERIAL_EXPORT_PLACEHOLDER) { parameters_arg += "export_materials='PLACEHOLDER',"; @@ -115,7 +114,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ } else { parameters_arg += "export_colors=False,"; } - if (p_options.has(SNAME("blender/nodes/visible")) && p_options[SNAME("blender/nodes/visible")]) { + if (p_options.has(SNAME("blender/nodes/visible"))) { int32_t visible = p_options["blender/nodes/visible"]; if (visible == BLEND_VISIBLE_VISIBLE_ONLY) { parameters_arg += "use_visible=True,"; diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h index 9ee2397968..23bf33869e 100644 --- a/modules/gltf/gltf_defines.h +++ b/modules/gltf/gltf_defines.h @@ -58,6 +58,7 @@ class GLTFSkin; class GLTFSpecGloss; class GLTFState; class GLTFTexture; +class GLTFTextureSampler; // GLTF index aliases. using GLTFAccessorIndex = int; @@ -73,6 +74,7 @@ using GLTFNodeIndex = int; using GLTFSkeletonIndex = int; using GLTFSkinIndex = int; using GLTFTextureIndex = int; +using GLTFTextureSamplerIndex = int; enum GLTFType { TYPE_SCALAR, diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 8d2e37be3a..35358734d6 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -145,6 +145,12 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { return Error::FAILED; } + /* STEP SERIALIZE TEXTURE SAMPLERS */ + err = _serialize_texture_samplers(state); + if (err != OK) { + return Error::FAILED; + } + /* STEP SERIALIZE ANIMATIONS */ err = _serialize_animations(state); if (err != OK) { @@ -3219,6 +3225,11 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) { Ref<GLTFTexture> t = state->textures[i]; ERR_CONTINUE(t->get_src_image() == -1); d["source"] = t->get_src_image(); + + GLTFTextureSamplerIndex sampler_index = t->get_sampler(); + if (sampler_index != -1) { + d["sampler"] = sampler_index; + } textures.push_back(d); } state->json["textures"] = textures; @@ -3240,13 +3251,18 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { Ref<GLTFTexture> t; t.instantiate(); t->set_src_image(d["source"]); + if (d.has("sampler")) { + t->set_sampler(d["sampler"]); + } else { + t->set_sampler(-1); + } state->textures.push_back(t); } return OK; } -GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture) { +GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { ERR_FAIL_COND_V(p_texture.is_null(), -1); Ref<GLTFTexture> gltf_texture; gltf_texture.instantiate(); @@ -3254,6 +3270,7 @@ GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> GLTFImageIndex gltf_src_image_i = state->images.size(); state->images.push_back(p_texture); gltf_texture->set_src_image(gltf_src_image_i); + gltf_texture->set_sampler(_set_sampler_for_mode(state, p_filter_mode, p_repeats)); GLTFTextureIndex gltf_texture_i = state->textures.size(); state->textures.push_back(gltf_texture); return gltf_texture_i; @@ -3268,6 +3285,102 @@ Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> state, const GLTFTextur return state->images[image]; } +GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { + for (int i = 0; i < state->texture_samplers.size(); ++i) { + if (state->texture_samplers[i]->get_filter_mode() == p_filter_mode) { + return i; + } + } + + GLTFTextureSamplerIndex gltf_sampler_i = state->texture_samplers.size(); + Ref<GLTFTextureSampler> gltf_sampler; + gltf_sampler.instantiate(); + gltf_sampler->set_filter_mode(p_filter_mode); + gltf_sampler->set_wrap_mode(p_repeats); + state->texture_samplers.push_back(gltf_sampler); + return gltf_sampler_i; +} + +Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture) { + ERR_FAIL_INDEX_V(p_texture, state->textures.size(), Ref<Texture2D>()); + const GLTFTextureSamplerIndex sampler = state->textures[p_texture]->get_sampler(); + + if (sampler == -1) { + return state->default_texture_sampler; + } else { + ERR_FAIL_INDEX_V(sampler, state->texture_samplers.size(), Ref<GLTFTextureSampler>()); + + return state->texture_samplers[sampler]; + } +} + +Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> state) { + if (!state->texture_samplers.size()) { + return OK; + } + + Array samplers; + for (int32_t i = 0; i < state->texture_samplers.size(); ++i) { + Dictionary d; + Ref<GLTFTextureSampler> s = state->texture_samplers[i]; + d["magFilter"] = s->get_mag_filter(); + d["minFilter"] = s->get_min_filter(); + d["wrapS"] = s->get_wrap_s(); + d["wrapT"] = s->get_wrap_t(); + samplers.push_back(d); + } + state->json["samplers"] = samplers; + + return OK; +} + +Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> state) { + state->default_texture_sampler.instantiate(); + state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); + state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); + state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT); + state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT); + + if (!state->json.has("samplers")) { + return OK; + } + + const Array &samplers = state->json["samplers"]; + for (int i = 0; i < samplers.size(); ++i) { + const Dictionary &d = samplers[i]; + + Ref<GLTFTextureSampler> sampler; + sampler.instantiate(); + + if (d.has("minFilter")) { + sampler->set_min_filter(d["minFilter"]); + } else { + sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); + } + if (d.has("magFilter")) { + sampler->set_mag_filter(d["magFilter"]); + } else { + sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); + } + + if (d.has("wrapS")) { + sampler->set_wrap_s(d["wrapS"]); + } else { + sampler->set_wrap_s(GLTFTextureSampler::WrapMode::DEFAULT); + } + + if (d.has("wrapT")) { + sampler->set_wrap_t(d["wrapT"]); + } else { + sampler->set_wrap_t(GLTFTextureSampler::WrapMode::DEFAULT); + } + + state->texture_samplers.push_back(sampler); + } + + return OK; +} + Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Array materials; for (int32_t i = 0; i < state->materials.size(); i++) { @@ -3299,7 +3412,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { albedo_texture->set_name(material->get_name() + "_albedo"); - gltf_texture_index = _set_texture(state, albedo_texture); + gltf_texture_index = _set_texture(state, albedo_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } if (gltf_texture_index != -1) { bct["index"] = gltf_texture_index; @@ -3429,7 +3542,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { GLTFTextureIndex orm_texture_index = -1; if (has_ao || has_roughness || has_metalness) { orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(state, orm_texture); + orm_texture_index = _set_texture(state, orm_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } if (has_ao) { Dictionary occt; @@ -3484,7 +3597,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); - gltf_texture_index = _set_texture(state, tex); + gltf_texture_index = _set_texture(state, tex, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } nt["scale"] = material->get_normal_scale(); if (gltf_texture_index != -1) { @@ -3507,7 +3620,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { GLTFTextureIndex gltf_texture_index = -1; if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { emission_texture->set_name(material->get_name() + "_emission"); - gltf_texture_index = _set_texture(state, emission_texture); + gltf_texture_index = _set_texture(state, emission_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } if (gltf_texture_index != -1) { @@ -3566,6 +3679,11 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (sgm.has("diffuseTexture")) { const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"]; if (diffuse_texture_dict.has("index")) { + Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(state, diffuse_texture_dict["index"]); + if (diffuse_sampler.is_valid()) { + material->set_texture_filter(diffuse_sampler->get_filter_mode()); + material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode()); + } Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]); if (diffuse_texture.is_valid()) { spec_gloss->diffuse_img = diffuse_texture->get_image(); @@ -3614,6 +3732,9 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (mr.has("baseColorTexture")) { const Dictionary &bct = mr["baseColorTexture"]; if (bct.has("index")) { + Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(state, bct["index"]); + material->set_texture_filter(bct_sampler->get_filter_mode()); + material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode()); material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"])); } if (!mr.has("baseColorFactor")) { @@ -6477,8 +6598,10 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> err = ext->import_preflight(state); ERR_FAIL_COND_V(err != OK, err); } + err = _parse_gltf_state(state, p_path, p_bake_fps); ERR_FAIL_COND_V(err != OK, err); + return OK; } @@ -6834,6 +6957,11 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + /* PARSE TEXTURE SAMPLERS */ + err = _parse_texture_samplers(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + /* PARSE TEXTURES */ err = _parse_textures(state); diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 750d3d403e..62b6e29fe0 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -95,9 +95,14 @@ private: String _gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name); - GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture); + GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture, + StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats); Ref<Texture2D> _get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture); + GLTFTextureSamplerIndex _set_sampler_for_mode(Ref<GLTFState> state, + StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats); + Ref<GLTFTextureSampler> _get_sampler_for_texture(Ref<GLTFState> state, + const GLTFTextureIndex p_texture); Error _parse_json(const String &p_path, Ref<GLTFState> state); Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state); void _compute_node_heights(Ref<GLTFState> state); @@ -145,10 +150,12 @@ private: const bool p_for_vertex); Error _parse_meshes(Ref<GLTFState> state); Error _serialize_textures(Ref<GLTFState> state); + Error _serialize_texture_samplers(Ref<GLTFState> state); Error _serialize_images(Ref<GLTFState> state, const String &p_path); Error _serialize_lights(Ref<GLTFState> state); Error _parse_images(Ref<GLTFState> state, const String &p_base_path); Error _parse_textures(Ref<GLTFState> state); + Error _parse_texture_samplers(Ref<GLTFState> state); Error _parse_materials(Ref<GLTFState> state); void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material); void spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index a23fb39503..60192c67e6 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -64,6 +64,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_nodes", "root_nodes"), &GLTFState::set_root_nodes); ClassDB::bind_method(D_METHOD("get_textures"), &GLTFState::get_textures); ClassDB::bind_method(D_METHOD("set_textures", "textures"), &GLTFState::set_textures); + ClassDB::bind_method(D_METHOD("get_texture_samplers"), &GLTFState::get_texture_samplers); + ClassDB::bind_method(D_METHOD("set_texture_samplers", "texture_samplers"), &GLTFState::set_texture_samplers); ClassDB::bind_method(D_METHOD("get_images"), &GLTFState::get_images); ClassDB::bind_method(D_METHOD("set_images", "images"), &GLTFState::set_images); ClassDB::bind_method(D_METHOD("get_skins"), &GLTFState::get_skins); @@ -101,6 +103,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_path"), "set_base_path", "get_base_path"); // String ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "root_nodes"), "set_root_nodes", "get_root_nodes"); // Vector<int> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_textures", "get_textures"); // Vector<Ref<GLTFTexture>> + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "texture_samplers", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_texture_samplers", "get_texture_samplers"); //Vector<Ref<GLTFTextureSampler>> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_images", "get_images"); // Vector<Ref<Texture> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skins", "get_skins"); // Vector<Ref<GLTFSkin>> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "cameras", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_cameras", "get_cameras"); // Vector<Ref<GLTFCamera>> @@ -236,6 +239,14 @@ void GLTFState::set_textures(TypedArray<GLTFTexture> p_textures) { GLTFTemplateConvert::set_from_array(textures, p_textures); } +TypedArray<GLTFTextureSampler> GLTFState::get_texture_samplers() { + return GLTFTemplateConvert::to_array(texture_samplers); +} + +void GLTFState::set_texture_samplers(TypedArray<GLTFTextureSampler> p_texture_samplers) { + GLTFTemplateConvert::set_from_array(texture_samplers, p_texture_samplers); +} + TypedArray<Texture2D> GLTFState::get_images() { return GLTFTemplateConvert::to_array(images); } diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 791431f376..afe7e82010 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -42,6 +42,7 @@ #include "structures/gltf_skeleton.h" #include "structures/gltf_skin.h" #include "structures/gltf_texture.h" +#include "structures/gltf_texture_sampler.h" #include "core/templates/rb_map.h" #include "scene/animation/animation_player.h" @@ -77,6 +78,8 @@ class GLTFState : public Resource { String scene_name; Vector<int> root_nodes; Vector<Ref<GLTFTexture>> textures; + Vector<Ref<GLTFTextureSampler>> texture_samplers; + Ref<GLTFTextureSampler> default_texture_sampler; Vector<Ref<Texture2D>> images; Vector<String> extensions_used; Vector<String> extensions_required; @@ -149,6 +152,9 @@ public: TypedArray<GLTFTexture> get_textures(); void set_textures(TypedArray<GLTFTexture> p_textures); + TypedArray<GLTFTextureSampler> get_texture_samplers(); + void set_texture_samplers(TypedArray<GLTFTextureSampler> p_texture_samplers); + TypedArray<Texture2D> get_images(); void set_images(TypedArray<Texture2D> p_images); diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 6e7f7d6fed..b9027f6e3d 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -47,6 +47,7 @@ #include "structures/gltf_skeleton.h" #include "structures/gltf_skin.h" #include "structures/gltf_texture.h" +#include "structures/gltf_texture_sampler.h" #ifdef TOOLS_ENABLED #include "core/config/project_settings.h" @@ -126,6 +127,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(GLTFSpecGloss); GDREGISTER_CLASS(GLTFState); GDREGISTER_CLASS(GLTFTexture); + GDREGISTER_CLASS(GLTFTextureSampler); } #ifdef TOOLS_ENABLED diff --git a/modules/gltf/structures/gltf_texture.cpp b/modules/gltf/structures/gltf_texture.cpp index 2a21cb3df8..5cc96e3221 100644 --- a/modules/gltf/structures/gltf_texture.cpp +++ b/modules/gltf/structures/gltf_texture.cpp @@ -33,8 +33,11 @@ void GLTFTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_src_image"), &GLTFTexture::get_src_image); ClassDB::bind_method(D_METHOD("set_src_image", "src_image"), &GLTFTexture::set_src_image); + ClassDB::bind_method(D_METHOD("get_sampler"), &GLTFTexture::get_sampler); + ClassDB::bind_method(D_METHOD("set_sampler", "sampler"), &GLTFTexture::set_sampler); ADD_PROPERTY(PropertyInfo(Variant::INT, "src_image"), "set_src_image", "get_src_image"); // int + ADD_PROPERTY(PropertyInfo(Variant::INT, "sampler"), "set_sampler", "get_sampler"); // int } GLTFImageIndex GLTFTexture::get_src_image() const { @@ -44,3 +47,11 @@ GLTFImageIndex GLTFTexture::get_src_image() const { void GLTFTexture::set_src_image(GLTFImageIndex val) { src_image = val; } + +GLTFTextureSamplerIndex GLTFTexture::get_sampler() const { + return sampler; +} + +void GLTFTexture::set_sampler(GLTFTextureSamplerIndex val) { + sampler = val; +} diff --git a/modules/gltf/structures/gltf_texture.h b/modules/gltf/structures/gltf_texture.h index b1d12dddfa..b26c8a7b07 100644 --- a/modules/gltf/structures/gltf_texture.h +++ b/modules/gltf/structures/gltf_texture.h @@ -39,6 +39,7 @@ class GLTFTexture : public Resource { private: GLTFImageIndex src_image = 0; + GLTFTextureSamplerIndex sampler = -1; protected: static void _bind_methods(); @@ -46,6 +47,8 @@ protected: public: GLTFImageIndex get_src_image() const; void set_src_image(GLTFImageIndex val); + GLTFTextureSamplerIndex get_sampler() const; + void set_sampler(GLTFTextureSamplerIndex val); }; #endif // GLTF_TEXTURE_H diff --git a/modules/gltf/structures/gltf_texture_sampler.cpp b/modules/gltf/structures/gltf_texture_sampler.cpp new file mode 100644 index 0000000000..6cf615b6cc --- /dev/null +++ b/modules/gltf/structures/gltf_texture_sampler.cpp @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* gltf_texture_sampler.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gltf_texture_sampler.h" + +void GLTFTextureSampler::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_mag_filter"), &GLTFTextureSampler::get_mag_filter); + ClassDB::bind_method(D_METHOD("set_mag_filter", "filter_mode"), &GLTFTextureSampler::set_mag_filter); + ClassDB::bind_method(D_METHOD("get_min_filter"), &GLTFTextureSampler::get_min_filter); + ClassDB::bind_method(D_METHOD("set_min_filter", "filter_mode"), &GLTFTextureSampler::set_min_filter); + ClassDB::bind_method(D_METHOD("get_wrap_s"), &GLTFTextureSampler::get_wrap_s); + ClassDB::bind_method(D_METHOD("set_wrap_s", "wrap_mode"), &GLTFTextureSampler::set_wrap_s); + ClassDB::bind_method(D_METHOD("get_wrap_t"), &GLTFTextureSampler::get_wrap_t); + ClassDB::bind_method(D_METHOD("set_wrap_t", "wrap_mode"), &GLTFTextureSampler::set_wrap_t); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "mag_filter"), "set_mag_filter", "get_mag_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "min_filter"), "set_min_filter", "get_min_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_s"), "set_wrap_s", "get_wrap_s"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_t"), "set_wrap_t", "get_wrap_t"); +} diff --git a/modules/gltf/structures/gltf_texture_sampler.h b/modules/gltf/structures/gltf_texture_sampler.h new file mode 100644 index 0000000000..3fad31bbee --- /dev/null +++ b/modules/gltf/structures/gltf_texture_sampler.h @@ -0,0 +1,163 @@ +/*************************************************************************/ +/* gltf_texture_sampler.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GLTF_TEXTURE_SAMPLER_H +#define GLTF_TEXTURE_SAMPLER_H + +#include "core/io/resource.h" +#include "scene/resources/material.h" + +class GLTFTextureSampler : public Resource { + GDCLASS(GLTFTextureSampler, Resource); + +public: + enum FilterMode { + NEAREST = 9728, + LINEAR = 9729, + NEAREST_MIPMAP_NEAREST = 9984, + LINEAR_MIPMAP_NEAREST = 9985, + NEAREST_MIPMAP_LINEAR = 9986, + LINEAR_MIPMAP_LINEAR = 9987 + }; + + enum WrapMode { + CLAMP_TO_EDGE = 33071, + MIRRORED_REPEAT = 33648, + REPEAT = 10497, + DEFAULT = REPEAT + }; + + int get_mag_filter() const { + return mag_filter; + } + + void set_mag_filter(const int filter_mode) { + mag_filter = (FilterMode)filter_mode; + } + + int get_min_filter() const { + return min_filter; + } + + void set_min_filter(const int filter_mode) { + min_filter = (FilterMode)filter_mode; + } + + int get_wrap_s() const { + return wrap_s; + } + + void set_wrap_s(const int wrap_mode) { + wrap_s = (WrapMode)wrap_mode; + } + + int get_wrap_t() const { + return wrap_t; + } + + void set_wrap_t(const int wrap_mode) { + wrap_s = (WrapMode)wrap_mode; + } + + StandardMaterial3D::TextureFilter get_filter_mode() const { + using TextureFilter = StandardMaterial3D::TextureFilter; + + switch (min_filter) { + case NEAREST: + return TextureFilter::TEXTURE_FILTER_NEAREST; + case LINEAR: + return TextureFilter::TEXTURE_FILTER_LINEAR; + case NEAREST_MIPMAP_NEAREST: + case NEAREST_MIPMAP_LINEAR: + return TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; + case LINEAR_MIPMAP_NEAREST: + case LINEAR_MIPMAP_LINEAR: + default: + return TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; + } + } + + void set_filter_mode(StandardMaterial3D::TextureFilter mode) { + using TextureFilter = StandardMaterial3D::TextureFilter; + + switch (mode) { + case TextureFilter::TEXTURE_FILTER_NEAREST: + min_filter = FilterMode::NEAREST; + mag_filter = FilterMode::NEAREST; + break; + case TextureFilter::TEXTURE_FILTER_LINEAR: + min_filter = FilterMode::LINEAR; + mag_filter = FilterMode::LINEAR; + break; + case TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: + case TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: + min_filter = FilterMode::NEAREST_MIPMAP_LINEAR; + mag_filter = FilterMode::NEAREST; + break; + case TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: + case TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: + default: + min_filter = FilterMode::LINEAR_MIPMAP_LINEAR; + mag_filter = FilterMode::LINEAR; + break; + } + } + + bool get_wrap_mode() const { + // BaseMaterial3D presents wrapping as a boolean property. Either the texture is repeated + // in both dimensions, non-mirrored, or it isn't repeated at all. This will cause oddities + // when people import models having other wrapping mode combinations. + return (wrap_s == WrapMode::REPEAT) && (wrap_t == WrapMode::REPEAT); + } + + void set_wrap_mode(bool mat_repeats) { + if (mat_repeats) { + wrap_s = WrapMode::REPEAT; + wrap_t = WrapMode::REPEAT; + } else { + wrap_s = WrapMode::CLAMP_TO_EDGE; + wrap_t = WrapMode::CLAMP_TO_EDGE; + } + } + +protected: + static void _bind_methods(); + +private: + FilterMode mag_filter = FilterMode::LINEAR; + FilterMode min_filter = FilterMode::LINEAR_MIPMAP_LINEAR; + WrapMode wrap_s = WrapMode::REPEAT; + WrapMode wrap_t = WrapMode::REPEAT; +}; + +VARIANT_ENUM_CAST(GLTFTextureSampler::FilterMode); +VARIANT_ENUM_CAST(GLTFTextureSampler::WrapMode); + +#endif // GLTF_TEXTURE_SAMPLER_H diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index a64dc4a80b..6fd38d9445 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -241,7 +241,7 @@ protected: void _notification(int p_what); public: - virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); } + virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); } virtual String get_name() const override { return "GridMap"; } bool has_main_screen() const override { return false; } virtual void edit(Object *p_object) override; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index d469c28d4a..e5e53acb07 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -48,20 +48,10 @@ class CSharpScript; class CSharpInstance; class CSharpLanguage; -#ifdef NO_SAFE_CAST -template <typename TScriptInstance, typename TScriptLanguage> -TScriptInstance *cast_script_instance(ScriptInstance *p_inst) { - if (!p_inst) { - return nullptr; - } - return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : nullptr; -} -#else template <typename TScriptInstance, typename TScriptLanguage> TScriptInstance *cast_script_instance(ScriptInstance *p_inst) { return dynamic_cast<TScriptInstance *>(p_inst); } -#endif #define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst)) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 95a44d3b7e..d29e0d69ab 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -3326,11 +3326,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::PROJECTION: { - Projection transform = p_val.operator Projection(); - if (transform == Projection()) { + Projection projection = p_val.operator Projection(); + if (projection == Projection()) { r_iarg.default_argument = "Projection.Identity"; } else { - r_iarg.default_argument = "new Projection(new Vector4" + transform.matrix[0].operator String() + ", new Vector4" + transform.matrix[1].operator String() + ", new Vector4" + transform.matrix[2].operator String() + ", new Vector4" + transform.matrix[3].operator String() + ")"; + r_iarg.default_argument = "new Projection(new Vector4" + projection.columns[0].operator String() + ", new Vector4" + projection.columns[1].operator String() + ", new Vector4" + projection.columns[2].operator String() + ", new Vector4" + projection.columns[3].operator String() + ")"; } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index d4469b110b..5ac167ad98 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -92,6 +92,7 @@ if env["vulkan"]: env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_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_passthrough_extension_wrapper.cpp") diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp new file mode 100644 index 0000000000..0f6aaf8afb --- /dev/null +++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* openxr_composition_layer_depth_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_composition_layer_depth_extension.h" + +OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::singleton = nullptr; + +OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::get_singleton() { + return singleton; +} + +OpenXRCompositionLayerDepthExtension::OpenXRCompositionLayerDepthExtension(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + singleton = this; + + request_extensions[XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME] = &available; +} + +OpenXRCompositionLayerDepthExtension::~OpenXRCompositionLayerDepthExtension() { + singleton = nullptr; +} + +bool OpenXRCompositionLayerDepthExtension::is_available() { + return available; +} + +XrCompositionLayerBaseHeader *OpenXRCompositionLayerDepthExtension::get_composition_layer() { + // Seems this is all done in our base layer... Just in case this changes... + + return nullptr; +} diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.h b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h new file mode 100644 index 0000000000..9533783d83 --- /dev/null +++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h @@ -0,0 +1,53 @@ +/*************************************************************************/ +/* openxr_composition_layer_depth_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H +#define OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H + +#include "openxr_composition_layer_provider.h" +#include "openxr_extension_wrapper.h" + +class OpenXRCompositionLayerDepthExtension : public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider { +public: + static OpenXRCompositionLayerDepthExtension *get_singleton(); + + OpenXRCompositionLayerDepthExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRCompositionLayerDepthExtension() override; + + bool is_available(); + virtual XrCompositionLayerBaseHeader *get_composition_layer() override; + +private: + static OpenXRCompositionLayerDepthExtension *singleton; + + bool available = false; +}; + +#endif // OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_composition_layer_provider.h b/modules/openxr/extensions/openxr_composition_layer_provider.h index ba51389f7d..a4c4cbe0c6 100644 --- a/modules/openxr/extensions/openxr_composition_layer_provider.h +++ b/modules/openxr/extensions/openxr_composition_layer_provider.h @@ -31,6 +31,7 @@ #ifndef OPENXR_COMPOSITION_LAYER_PROVIDER_H #define OPENXR_COMPOSITION_LAYER_PROVIDER_H +#include "openxr_extension_wrapper.h" #include <openxr/openxr.h> // Interface for OpenXR extensions that provide a composition layer. diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 623c264e6e..c417c90d11 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -100,11 +100,12 @@ public: class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper { public: virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0; + virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) = 0; virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0; virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0; virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) = 0; - virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) = 0; + virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) = 0; OpenXRGraphicsExtensionWrapper(OpenXRAPI *p_openxr_api) : OpenXRExtensionWrapper(p_openxr_api){}; diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp index f9e771c934..ee5bda2881 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -228,6 +228,12 @@ void OpenXRVulkanExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usab p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_UINT); } +void OpenXRVulkanExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) { + p_usable_swap_chains.push_back(VK_FORMAT_R32_SFLOAT); + p_usable_swap_chains.push_back(VK_FORMAT_D24_UNORM_S8_UINT); + p_usable_swap_chains.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT); +} + bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) { XrSwapchainImageVulkanKHR *images = nullptr; @@ -271,7 +277,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1; - uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT; switch (p_swapchain_format) { case VK_FORMAT_R8G8B8A8_SRGB: @@ -283,16 +289,32 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in // will thus do an sRGB -> Linear conversion as expected. // format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; break; case VK_FORMAT_B8G8R8A8_SRGB: // format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB; format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; break; case VK_FORMAT_R8G8B8A8_UINT: format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; break; case VK_FORMAT_B8G8R8A8_UINT: format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + break; + case VK_FORMAT_R32_SFLOAT: + format = RenderingDevice::DATA_FORMAT_R32_SFLOAT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + break; + case VK_FORMAT_D24_UNORM_S8_UINT: + format = RenderingDevice::DATA_FORMAT_D24_UNORM_S8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + break; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + format = RenderingDevice::DATA_FORMAT_D32_SFLOAT_S8_UINT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; break; default: // continue with our default value @@ -328,8 +350,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in break; } - Vector<RID> image_rids; - Vector<RID> framebuffers; + Vector<RID> texture_rids; // create Godot texture objects for each entry in our swapchain for (uint64_t i = 0; i < swapchain_length; i++) { @@ -344,19 +365,10 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in 1, p_array_size); - image_rids.push_back(image_rid); - - { - Vector<RID> fb; - fb.push_back(image_rid); - - RID fb_rid = rendering_device->framebuffer_create(fb, RenderingDevice::INVALID_ID, p_array_size); - framebuffers.push_back(fb_rid); - } + texture_rids.push_back(image_rid); } - data->image_rids = image_rids; - data->framebuffers = framebuffers; + data->texture_rids = texture_rids; memfree(images); @@ -370,33 +382,19 @@ bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { - r_camera_matrix.matrix[j][i] = matrix.m[j * 4 + i]; + r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i]; } } return true; } -bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) { +RID OpenXRVulkanExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) { SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data; - ERR_FAIL_NULL_V(data, false); - ERR_FAIL_COND_V(p_from_render_target.is_null(), false); + ERR_FAIL_NULL_V(data, RID()); - RID source_image = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(p_from_render_target); - ERR_FAIL_COND_V(source_image.is_null(), false); - - RID depth_image; // TODO implement - - ERR_FAIL_INDEX_V(p_image_index, data->framebuffers.size(), false); - RID fb = data->framebuffers[p_image_index]; - ERR_FAIL_COND_V(fb.is_null(), false); - - // Our vulkan extension can only be used in conjunction with our vulkan renderer. - RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); - ERR_FAIL_NULL_V(copy_effects, false); - copy_effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview); - - return true; + ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID()); + return data->texture_rids[p_image_index]; } void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) { @@ -411,17 +409,11 @@ void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g RenderingDevice *rendering_device = rendering_server->get_rendering_device(); ERR_FAIL_NULL(rendering_device); - for (int i = 0; i < data->image_rids.size(); i++) { - // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain - rendering_device->free(data->image_rids[i]); - } - data->image_rids.clear(); - - for (int i = 0; i < data->framebuffers.size(); i++) { + for (int i = 0; i < data->texture_rids.size(); i++) { // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain - rendering_device->free(data->framebuffers[i]); + rendering_device->free(data->texture_rids[i]); } - data->framebuffers.clear(); + data->texture_rids.clear(); memdelete(data); *p_swapchain_graphics_data = nullptr; diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h index d6e9917900..71abe3b166 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.h +++ b/modules/openxr/extensions/openxr_vulkan_extension.h @@ -69,11 +69,12 @@ public: virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override; virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override; + virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override; virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override; virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override; virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override; virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override; - virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) override; + virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override; private: static OpenXRVulkanExtension *singleton; @@ -81,8 +82,7 @@ private: struct SwapchainGraphicsData { bool is_multiview; - Vector<RID> image_rids; - Vector<RID> framebuffers; + Vector<RID> texture_rids; }; bool check_graphics_api_support(XrVersion p_desired_version); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 16879ac4e5..8a69072793 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -49,6 +49,7 @@ #include "extensions/openxr_vulkan_extension.h" #endif +#include "extensions/openxr_composition_layer_depth_extension.h" #include "extensions/openxr_fb_passthrough_extension_wrapper.h" #include "extensions/openxr_hand_tracking_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" @@ -663,7 +664,7 @@ bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) { return false; } -bool OpenXRAPI::create_main_swapchain() { +bool OpenXRAPI::create_swapchains() { ERR_FAIL_NULL_V(graphics_extension, false); ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); @@ -681,34 +682,36 @@ bool OpenXRAPI::create_main_swapchain() { already rendering the next frame. Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create, - as we render 3D content into internal buffers that are copied into the swapchain, we don't get any of the performance gains - until such time as we implement VRS. + as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support */ - // Build a vector with swapchain formats we want to use, from best fit to worst - Vector<int64_t> usable_swapchain_formats; - int64_t swapchain_format_to_use = 0; + Size2 recommended_size = get_recommended_target_size(); - graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats); + // We start with our color swapchain... + { + // Build a vector with swapchain formats we want to use, from best fit to worst + Vector<int64_t> usable_swapchain_formats; + int64_t swapchain_format_to_use = 0; - // now find out which one is supported - for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { - if (is_swapchain_format_supported(usable_swapchain_formats[i])) { - swapchain_format_to_use = usable_swapchain_formats[i]; - } - } + graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats); - if (swapchain_format_to_use == 0) { - swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... - print_line("Couldn't find usable swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); - } else { - print_line("Using swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); - } + // now find out which one is supported + for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { + if (is_swapchain_format_supported(usable_swapchain_formats[i])) { + swapchain_format_to_use = usable_swapchain_formats[i]; + } + } - Size2 recommended_size = get_recommended_target_size(); + if (swapchain_format_to_use == 0) { + swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... + print_line("Couldn't find usable color swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); + } else { + print_line("Using color swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); + } - if (!create_swapchain(swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchain, &swapchain_graphics_data)) { - return false; + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) { + return false; + } } views = (XrView *)memalloc(sizeof(XrView) * view_count); @@ -717,18 +720,73 @@ bool OpenXRAPI::create_main_swapchain() { projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count); ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views"); + // We create our depth swapchain if: + // - we support our depth layer extension + // - we have our spacewarp extension (not yet implemented) + if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) { + // Build a vector with swapchain formats we want to use, from best fit to worst + Vector<int64_t> usable_swapchain_formats; + int64_t swapchain_format_to_use = 0; + + graphics_extension->get_usable_depth_formats(usable_swapchain_formats); + + // now find out which one is supported + for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { + if (is_swapchain_format_supported(usable_swapchain_formats[i])) { + swapchain_format_to_use = usable_swapchain_formats[i]; + } + } + + if (swapchain_format_to_use == 0) { + swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... + print_line("Couldn't find usable depth swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); + } else { + print_line("Using depth swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); + } + + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) { + return false; + } + + depth_views = (XrCompositionLayerDepthInfoKHR *)memalloc(sizeof(XrCompositionLayerDepthInfoKHR) * view_count); + ERR_FAIL_NULL_V_MSG(depth_views, false, "OpenXR Couldn't allocate memory for depth views"); + } + + // We create our velocity swapchain if: + // - we have our spacewarp extension (not yet implemented) + { + // TBD + } + for (uint32_t i = 0; i < view_count; i++) { views[i].type = XR_TYPE_VIEW; views[i].next = nullptr; projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; projection_views[i].next = nullptr; - projection_views[i].subImage.swapchain = swapchain; + projection_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain; projection_views[i].subImage.imageArrayIndex = i; projection_views[i].subImage.imageRect.offset.x = 0; projection_views[i].subImage.imageRect.offset.y = 0; projection_views[i].subImage.imageRect.extent.width = recommended_size.width; projection_views[i].subImage.imageRect.extent.height = recommended_size.height; + + if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) { + projection_views[i].next = &depth_views[i]; + + depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; + depth_views[i].next = nullptr; + depth_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain; + depth_views[i].subImage.imageArrayIndex = 0; + depth_views[i].subImage.imageRect.offset.x = 0; + depth_views[i].subImage.imageRect.offset.y = 0; + depth_views[i].subImage.imageRect.extent.width = recommended_size.width; + depth_views[i].subImage.imageRect.extent.height = recommended_size.height; + depth_views[i].minDepth = 0.0; + depth_views[i].maxDepth = 1.0; + depth_views[i].nearZ = 0.01; // Near and far Z will be set to the correct values in fill_projection_matrix + depth_views[i].farZ = 100.0; + } }; return true; @@ -740,7 +798,7 @@ void OpenXRAPI::destroy_session() { } if (graphics_extension) { - graphics_extension->cleanup_swapchain_graphics_data(&swapchain_graphics_data); + graphics_extension->cleanup_swapchain_graphics_data(&swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data); } if (views != nullptr) { @@ -753,9 +811,16 @@ void OpenXRAPI::destroy_session() { projection_views = nullptr; } - if (swapchain != XR_NULL_HANDLE) { - xrDestroySwapchain(swapchain); - swapchain = XR_NULL_HANDLE; + if (depth_views != nullptr) { + memfree(depth_views); + depth_views = nullptr; + } + + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + if (swapchains[i].swapchain != XR_NULL_HANDLE) { + xrDestroySwapchain(swapchains[i].swapchain); + swapchains[i].swapchain = XR_NULL_HANDLE; + } } if (supported_swapchain_formats != nullptr) { @@ -789,7 +854,7 @@ void OpenXRAPI::destroy_session() { } } -bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) { +bool OpenXRAPI::create_swapchain(XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) { ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); ERR_FAIL_NULL_V(graphics_extension, false); @@ -807,7 +872,7 @@ bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, u XR_TYPE_SWAPCHAIN_CREATE_INFO, // type next_pointer, // next 0, // createFlags - XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, // usageFlags + p_usage_flags, // usageFlags p_swapchain_format, // format p_sample_count, // sampleCount p_width, // width @@ -871,7 +936,7 @@ bool OpenXRAPI::on_state_ready() { // That will be very very ugly // The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module - if (!create_main_swapchain()) { + if (!create_swapchains()) { return false; } @@ -1304,6 +1369,15 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z return false; } + // if we're using depth views, make sure we update our near and far there... + if (depth_views != nullptr) { + for (uint32_t i = 0; i < view_count; i++) { + depth_views[i].nearZ = p_z_near; + depth_views[i].farZ = p_z_far; + } + } + + // now update our projection return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); } @@ -1442,15 +1516,15 @@ bool OpenXRAPI::process() { return true; } -bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) { - ERR_FAIL_COND_V(image_acquired, true); // this was not released when it should be, error out and re-use... +bool OpenXRAPI::acquire_image(OpenXRSwapChainInfo &p_swapchain) { + ERR_FAIL_COND_V(p_swapchain.image_acquired, true); // this was not released when it should be, error out and re-use... XrResult result; XrSwapchainImageAcquireInfo swapchain_image_acquire_info = { XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type nullptr // next }; - result = xrAcquireSwapchainImage(p_swapchain, &swapchain_image_acquire_info, &r_image_index); + result = xrAcquireSwapchainImage(p_swapchain.swapchain, &swapchain_image_acquire_info, &p_swapchain.image_index); if (XR_FAILED(result)) { print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]"); return false; @@ -1462,7 +1536,7 @@ bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) 17000000 // timeout in nanoseconds }; - result = xrWaitSwapchainImage(p_swapchain, &swapchain_image_wait_info); + result = xrWaitSwapchainImage(p_swapchain.swapchain, &swapchain_image_wait_info); if (XR_FAILED(result)) { print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]"); return false; @@ -1471,12 +1545,12 @@ bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) return true; } -bool OpenXRAPI::release_image(XrSwapchain p_swapchain) { +bool OpenXRAPI::release_image(OpenXRSwapChainInfo &p_swapchain) { XrSwapchainImageReleaseInfo swapchain_image_release_info = { XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type nullptr // next }; - XrResult result = xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info); + XrResult result = xrReleaseSwapchainImage(p_swapchain.swapchain, &swapchain_image_release_info); if (XR_FAILED(result)) { print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]"); return false; @@ -1590,28 +1664,41 @@ bool OpenXRAPI::pre_draw_viewport(RID p_render_target) { // TODO: at some point in time we may support multiple viewports in which case we need to handle that... + // Acquire our images + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + if (!swapchains[i].image_acquired && swapchains[i].swapchain != XR_NULL_HANDLE) { + if (!acquire_image(swapchains[i])) { + return false; + } + swapchains[i].image_acquired = true; + } + } + return true; } +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); + } else { + return RID(); + } +} + +RID OpenXRAPI::get_depth_texture() { + if (swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) { + return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_DEPTH].image_index); + } else { + return RID(); + } +} + void OpenXRAPI::post_draw_viewport(RID p_render_target) { if (!can_render()) { return; } - // TODO: at some point in time we may support multiple viewports in which case we need to handle that... - - // TODO: if we can get PR 51179 to work properly we can change away from this approach and move this into get_external_texture or something - if (!image_acquired) { - if (!acquire_image(swapchain, image_index)) { - return; - } - image_acquired = true; - - // print_line("OpenXR: acquired image " + itos(image_index) + ", copying..."); - - // Copy our buffer into our swap chain (remove once PR 51179 is done) - graphics_extension->copy_render_target_to_image(p_render_target, swapchain_graphics_data, image_index); - } + // Nothing to do here at this point in time... }; void OpenXRAPI::end_frame() { @@ -1623,7 +1710,7 @@ void OpenXRAPI::end_frame() { return; } - if (frame_state.shouldRender && view_pose_valid && !image_acquired) { + if (frame_state.shouldRender && view_pose_valid && !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) { print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!"); } @@ -1631,7 +1718,7 @@ void OpenXRAPI::end_frame() { // - shouldRender set to true // - a valid view pose for projection_views[eye].pose to submit layer // - an image to render - if (!frame_state.shouldRender || !view_pose_valid || !image_acquired) { + if (!frame_state.shouldRender || !view_pose_valid || !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) { // submit 0 layers when we shouldn't render XrFrameEndInfo frame_end_info = { XR_TYPE_FRAME_END_INFO, // type @@ -1652,10 +1739,12 @@ void OpenXRAPI::end_frame() { } // release our swapchain image if we acquired it - if (image_acquired) { - image_acquired = false; // whether we succeed or not, consider this released. + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + if (swapchains[i].image_acquired) { + swapchains[i].image_acquired = false; // whether we succeed or not, consider this released. - release_image(swapchain); + release_image(swapchains[i]); + } } for (uint32_t eye = 0; eye < view_count; eye++) { @@ -1763,6 +1852,7 @@ OpenXRAPI::OpenXRAPI() { // register our other extensions register_extension_wrapper(memnew(OpenXRPalmPoseExtension(this))); + register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension(this))); register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this))); register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this))); register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this))); diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 316886239e..bd69432dcb 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -120,15 +120,28 @@ private: OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr; XrSystemGraphicsProperties graphics_properties; - void *swapchain_graphics_data = nullptr; - uint32_t image_index = 0; - bool image_acquired = false; uint32_t view_count = 0; XrViewConfigurationView *view_configuration_views = nullptr; XrView *views = nullptr; XrCompositionLayerProjectionView *projection_views = nullptr; - XrSwapchain swapchain = XR_NULL_HANDLE; + XrCompositionLayerDepthInfoKHR *depth_views = nullptr; // Only used by Composition Layer Depth Extension if available + + enum OpenXRSwapChainTypes { + OPENXR_SWAPCHAIN_COLOR, + OPENXR_SWAPCHAIN_DEPTH, + // OPENXR_SWAPCHAIN_VELOCITY, + OPENXR_SWAPCHAIN_MAX + }; + + struct OpenXRSwapChainInfo { + XrSwapchain swapchain = XR_NULL_HANDLE; + void *swapchain_graphics_data = nullptr; + uint32_t image_index = 0; + bool image_acquired = false; + }; + + OpenXRSwapChainInfo swapchains[OPENXR_SWAPCHAIN_MAX]; XrSpace play_space = XR_NULL_HANDLE; XrSpace view_space = XR_NULL_HANDLE; @@ -212,13 +225,13 @@ private: bool setup_spaces(); bool load_supported_swapchain_formats(); bool is_swapchain_format_supported(int64_t p_swapchain_format); - bool create_main_swapchain(); + bool create_swapchains(); void destroy_session(); // swapchains - bool create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data); - bool acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index); - bool release_image(XrSwapchain p_swapchain); + bool create_swapchain(XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data); + bool acquire_image(OpenXRSwapChainInfo &p_swapchain); + bool release_image(OpenXRSwapChainInfo &p_swapchain); // action map struct Tracker { // Trackers represent tracked physical objects such as controllers, pucks, etc. @@ -318,6 +331,8 @@ public: void pre_render(); bool pre_draw_viewport(RID p_render_target); + RID get_color_texture(); + RID get_depth_texture(); void post_draw_viewport(RID p_render_target); void end_frame(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 01e148e00f..31dc2bbf43 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -648,6 +648,22 @@ Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_as return cm; } +RID OpenXRInterface::get_color_texture() { + if (openxr_api) { + return openxr_api->get_color_texture(); + } else { + return RID(); + } +} + +RID OpenXRInterface::get_depth_texture() { + if (openxr_api) { + return openxr_api->get_depth_texture(); + } else { + return RID(); + } +} + void OpenXRInterface::process() { if (openxr_api) { // do our normal process @@ -707,6 +723,7 @@ bool OpenXRInterface::pre_draw_viewport(RID p_render_target) { Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { Vector<BlitToScreen> blit_to_screen; +#ifndef ANDROID_ENABLED // If separate HMD we should output one eye to screen if (p_screen_rect != Rect2()) { BlitToScreen blit; @@ -732,6 +749,7 @@ Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, co blit.dst_rect = dst_rect; blit_to_screen.push_back(blit); } +#endif if (openxr_api) { openxr_api->post_draw_viewport(p_render_target); diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 3765f18637..72935b039c 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -126,6 +126,9 @@ public: virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override; + virtual RID get_color_texture() override; + virtual RID get_depth_texture() override; + virtual void process() override; virtual void pre_render() override; bool pre_draw_viewport(RID p_render_target) override; diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index d0c7484aa1..6b671c1660 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -388,15 +388,15 @@ Projection WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p_a int k = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - eye.matrix[i][j] = js_matrix[k++]; + eye.columns[i][j] = js_matrix[k++]; } } free(js_matrix); // Copied from godot_oculus_mobile's ovr_mobile_session.cpp - eye.matrix[2][2] = -(p_z_far + p_z_near) / (p_z_far - p_z_near); - eye.matrix[3][2] = -(2.0f * p_z_far * p_z_near) / (p_z_far - p_z_near); + eye.columns[2][2] = -(p_z_far + p_z_near) / (p_z_far - p_z_near); + eye.columns[3][2] = -(2.0f * p_z_far * p_z_near) / (p_z_far - p_z_near); return eye; } |