From 597290761231b7f1f1827f86f55635622926d34d Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Mon, 2 Sep 2024 03:27:06 -0700 Subject: [PATCH] GLTF: Add import_pre_generate and export_post_convert extension steps --- .../doc_classes/GLTFDocumentExtension.xml | 27 ++++++++++++--- .../extensions/gltf_document_extension.cpp | 33 ++++++++++++++----- .../gltf/extensions/gltf_document_extension.h | 6 +++- modules/gltf/gltf_document.cpp | 12 +++++++ 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index 5c548c472f6..b33e296e1ca 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -18,7 +18,7 @@ - Part of the export process. This method is run after [method _export_preflight] and before [method _export_preserialize]. + Part of the export process. This method is run after [method _export_preflight] and before [method _export_post_convert]. Runs when converting the data from a Godot scene node. This method can be used to process the Godot scene node data into a format that can be used by [method _export_node]. @@ -41,6 +41,15 @@ This method can be used to modify the final JSON of the generated glTF file. + + + + + + Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_preserialize]. + This method can be used to modify the converted node data structures before serialization with any additional data from the scene tree. + + @@ -54,7 +63,7 @@ - Part of the export process. This method is run after [method _convert_scene_node] and before [method _get_saveable_image_formats]. + Part of the export process. This method is run after [method _export_post_convert] and before [method _get_saveable_image_formats]. This method can be used to alter the state before performing serialization. It runs every time when generating a buffer with [method GLTFDocument.generate_buffer] or writing to the file system with [method GLTFDocument.write_to_filesystem]. @@ -64,7 +73,7 @@ - Part of the import process. This method is run after [method _import_post_parse] and before [method _import_node]. + Part of the import process. This method is run after [method _import_pre_generate] and before [method _import_node]. Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node. [b]Note:[/b] The [param scene_parent] parameter may be null if this is the single root node. @@ -113,8 +122,16 @@ - Part of the import process. This method is run after [method _parse_node_extensions] and before [method _generate_scene_node]. - This method can be used to modify any of the data imported so far after parsing, before generating the nodes and then running the final per-node import step. + Part of the import process. This method is run after [method _parse_node_extensions] and before [method _import_pre_generate]. + This method can be used to modify any of the data imported so far after parsing each node, but before generating the scene or any of its nodes. + + + + + + + Part of the import process. This method is run after [method _import_post_parse] and before [method _generate_scene_node]. + This method can be used to modify or read from any of the processed data structures, before generating the nodes and then running the final per-node import step. diff --git a/modules/gltf/extensions/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp index c6540ebb22f..6e611762b69 100644 --- a/modules/gltf/extensions/gltf_document_extension.cpp +++ b/modules/gltf/extensions/gltf_document_extension.cpp @@ -38,13 +38,15 @@ void GLTFDocumentExtension::_bind_methods() { GDVIRTUAL_BIND(_parse_image_data, "state", "image_data", "mime_type", "ret_image"); GDVIRTUAL_BIND(_get_image_file_extension); GDVIRTUAL_BIND(_parse_texture_json, "state", "texture_json", "ret_gltf_texture"); - GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent"); GDVIRTUAL_BIND(_import_post_parse, "state"); + GDVIRTUAL_BIND(_import_pre_generate, "state"); + GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent"); GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node"); GDVIRTUAL_BIND(_import_post, "state", "root"); // Export process. GDVIRTUAL_BIND(_export_preflight, "state", "root"); GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node"); + GDVIRTUAL_BIND(_export_post_convert, "state", "root"); GDVIRTUAL_BIND(_export_preserialize, "state"); GDVIRTUAL_BIND(_get_saveable_image_formats); GDVIRTUAL_BIND(_serialize_image_to_bytes, "state", "image", "image_dict", "image_format", "lossy_quality"); @@ -98,6 +100,20 @@ Error GLTFDocumentExtension::parse_texture_json(Ref p_state, const Di return err; } +Error GLTFDocumentExtension::import_post_parse(Ref p_state) { + ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); + Error err = OK; + GDVIRTUAL_CALL(_import_post_parse, p_state, err); + return err; +} + +Error GLTFDocumentExtension::import_pre_generate(Ref p_state) { + ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); + Error err = OK; + GDVIRTUAL_CALL(_import_pre_generate, p_state, err); + return err; +} + Node3D *GLTFDocumentExtension::generate_scene_node(Ref p_state, Ref p_gltf_node, Node *p_scene_parent) { ERR_FAIL_COND_V(p_state.is_null(), nullptr); ERR_FAIL_COND_V(p_gltf_node.is_null(), nullptr); @@ -106,13 +122,6 @@ Node3D *GLTFDocumentExtension::generate_scene_node(Ref p_state, Ref p_state) { - ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); - Error err = OK; - GDVIRTUAL_CALL(_import_post_parse, p_state, err); - return err; -} - Error GLTFDocumentExtension::import_node(Ref p_state, Ref p_gltf_node, Dictionary &r_dict, Node *p_node) { ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_gltf_node.is_null(), ERR_INVALID_PARAMETER); @@ -145,6 +154,14 @@ void GLTFDocumentExtension::convert_scene_node(Ref p_state, Ref p_state, Node *p_root) { + ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); + Error err = OK; + GDVIRTUAL_CALL(_export_post_convert, p_state, p_root, err); + return err; +} + Error GLTFDocumentExtension::export_preserialize(Ref p_state) { ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); Error err = OK; diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h index 761dff725c2..b70710e0150 100644 --- a/modules/gltf/extensions/gltf_document_extension.h +++ b/modules/gltf/extensions/gltf_document_extension.h @@ -50,12 +50,14 @@ public: virtual String get_image_file_extension(); virtual Error parse_texture_json(Ref p_state, const Dictionary &p_texture_json, Ref r_gltf_texture); virtual Error import_post_parse(Ref p_state); + virtual Error import_pre_generate(Ref p_state); virtual Node3D *generate_scene_node(Ref p_state, Ref p_gltf_node, Node *p_scene_parent); virtual Error import_node(Ref p_state, Ref p_gltf_node, Dictionary &r_json, Node *p_node); virtual Error import_post(Ref p_state, Node *p_node); // Export process. virtual Error export_preflight(Ref p_state, Node *p_root); virtual void convert_scene_node(Ref p_state, Ref p_gltf_node, Node *p_scene_node); + virtual Error export_post_convert(Ref p_state, Node *p_root); virtual Error export_preserialize(Ref p_state); virtual Vector get_saveable_image_formats(); virtual PackedByteArray serialize_image_to_bytes(Ref p_state, Ref p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality); @@ -71,13 +73,15 @@ public: GDVIRTUAL4R(Error, _parse_image_data, Ref, PackedByteArray, String, Ref); GDVIRTUAL0R(String, _get_image_file_extension); GDVIRTUAL3R(Error, _parse_texture_json, Ref, Dictionary, Ref); - GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref, Ref, Node *); GDVIRTUAL1R(Error, _import_post_parse, Ref); + GDVIRTUAL1R(Error, _import_pre_generate, Ref); + GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref, Ref, Node *); GDVIRTUAL4R(Error, _import_node, Ref, Ref, Dictionary, Node *); GDVIRTUAL2R(Error, _import_post, Ref, Node *); // Export process. GDVIRTUAL2R(Error, _export_preflight, Ref, Node *); GDVIRTUAL3(_convert_scene_node, Ref, Ref, Node *); + GDVIRTUAL2R(Error, _export_post_convert, Ref, Node *); GDVIRTUAL1R(Error, _export_preserialize, Ref); GDVIRTUAL0R(Vector, _get_saveable_image_formats); GDVIRTUAL5R(PackedByteArray, _serialize_image_to_bytes, Ref, Ref, Dictionary, String, float); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index bd034cbdc5d..992075e980e 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -7205,6 +7205,12 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref p_state) { ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skeletons."); err = _create_skins(p_state); ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skins."); + // Run pre-generate for each extension, in case an extension needs to do something before generating the scene. + for (Ref ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + err = ext->import_pre_generate(p_state); + ERR_CONTINUE(err != OK); + } // Generate the node tree. Node *single_root; if (p_state->extensions_used.has("GODOT_single_root")) { @@ -7439,6 +7445,12 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref p_state, uint state->extensions_used.append("GODOT_single_root"); } _convert_scene_node(state, p_node, -1, -1); + // Run post-convert for each extension, in case an extension needs to do something after converting the scene. + for (Ref ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + Error err = ext->export_post_convert(p_state, p_node); + ERR_CONTINUE(err != OK); + } return OK; }