Merge pull request #96465 from aaronfranke/gltf-pre-gen-post-conv

GLTF: Add `import_pre_generate` and `export_post_convert` extension steps
This commit is contained in:
Rémi Verschelde 2024-09-17 21:01:54 +02:00
commit a181d00af4
No known key found for this signature in database
GPG key ID: C3336907360768E1
4 changed files with 64 additions and 14 deletions

View file

@ -18,7 +18,7 @@
<param index="1" name="gltf_node" type="GLTFNode" /> <param index="1" name="gltf_node" type="GLTFNode" />
<param index="2" name="scene_node" type="Node" /> <param index="2" name="scene_node" type="Node" />
<description> <description>
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]. 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].
</description> </description>
</method> </method>
@ -41,6 +41,15 @@
This method can be used to modify the final JSON of the generated glTF file. This method can be used to modify the final JSON of the generated glTF file.
</description> </description>
</method> </method>
<method name="_export_post_convert" qualifiers="virtual">
<return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" />
<param index="1" name="root" type="Node" />
<description>
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.
</description>
</method>
<method name="_export_preflight" qualifiers="virtual"> <method name="_export_preflight" qualifiers="virtual">
<return type="int" enum="Error" /> <return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" /> <param index="0" name="state" type="GLTFState" />
@ -54,7 +63,7 @@
<return type="int" enum="Error" /> <return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" /> <param index="0" name="state" type="GLTFState" />
<description> <description>
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]. 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].
</description> </description>
</method> </method>
@ -64,7 +73,7 @@
<param index="1" name="gltf_node" type="GLTFNode" /> <param index="1" name="gltf_node" type="GLTFNode" />
<param index="2" name="scene_parent" type="Node" /> <param index="2" name="scene_parent" type="Node" />
<description> <description>
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. 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. [b]Note:[/b] The [param scene_parent] parameter may be null if this is the single root node.
</description> </description>
@ -113,8 +122,16 @@
<return type="int" enum="Error" /> <return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" /> <param index="0" name="state" type="GLTFState" />
<description> <description>
Part of the import process. This method is run after [method _parse_node_extensions] and before [method _generate_scene_node]. 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, before generating the nodes and then running the final per-node import step. 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.
</description>
</method>
<method name="_import_pre_generate" qualifiers="virtual">
<return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" />
<description>
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.
</description> </description>
</method> </method>
<method name="_import_preflight" qualifiers="virtual"> <method name="_import_preflight" qualifiers="virtual">

View file

@ -38,13 +38,15 @@ void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_parse_image_data, "state", "image_data", "mime_type", "ret_image"); GDVIRTUAL_BIND(_parse_image_data, "state", "image_data", "mime_type", "ret_image");
GDVIRTUAL_BIND(_get_image_file_extension); GDVIRTUAL_BIND(_get_image_file_extension);
GDVIRTUAL_BIND(_parse_texture_json, "state", "texture_json", "ret_gltf_texture"); 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_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_node, "state", "gltf_node", "json", "node");
GDVIRTUAL_BIND(_import_post, "state", "root"); GDVIRTUAL_BIND(_import_post, "state", "root");
// Export process. // Export process.
GDVIRTUAL_BIND(_export_preflight, "state", "root"); GDVIRTUAL_BIND(_export_preflight, "state", "root");
GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node"); GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node");
GDVIRTUAL_BIND(_export_post_convert, "state", "root");
GDVIRTUAL_BIND(_export_preserialize, "state"); GDVIRTUAL_BIND(_export_preserialize, "state");
GDVIRTUAL_BIND(_get_saveable_image_formats); GDVIRTUAL_BIND(_get_saveable_image_formats);
GDVIRTUAL_BIND(_serialize_image_to_bytes, "state", "image", "image_dict", "image_format", "lossy_quality"); GDVIRTUAL_BIND(_serialize_image_to_bytes, "state", "image", "image_dict", "image_format", "lossy_quality");
@ -98,6 +100,20 @@ Error GLTFDocumentExtension::parse_texture_json(Ref<GLTFState> p_state, const Di
return err; return err;
} }
Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> 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<GLTFState> 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<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
ERR_FAIL_COND_V(p_state.is_null(), nullptr); ERR_FAIL_COND_V(p_state.is_null(), nullptr);
ERR_FAIL_COND_V(p_gltf_node.is_null(), nullptr); ERR_FAIL_COND_V(p_gltf_node.is_null(), nullptr);
@ -106,13 +122,6 @@ Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<G
return ret_node; return ret_node;
} }
Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> 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<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> 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_state.is_null(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_gltf_node.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<GLTFState> p_state, Ref<GLTFN
GDVIRTUAL_CALL(_convert_scene_node, p_state, p_gltf_node, p_scene_node); GDVIRTUAL_CALL(_convert_scene_node, p_state, p_gltf_node, p_scene_node);
} }
Error GLTFDocumentExtension::export_post_convert(Ref<GLTFState> 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<GLTFState> p_state) { Error GLTFDocumentExtension::export_preserialize(Ref<GLTFState> p_state) {
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
Error err = OK; Error err = OK;

View file

@ -50,12 +50,14 @@ public:
virtual String get_image_file_extension(); virtual String get_image_file_extension();
virtual Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture); virtual Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture);
virtual Error import_post_parse(Ref<GLTFState> p_state); virtual Error import_post_parse(Ref<GLTFState> p_state);
virtual Error import_pre_generate(Ref<GLTFState> p_state);
virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent); virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error import_post(Ref<GLTFState> p_state, Node *p_node); virtual Error import_post(Ref<GLTFState> p_state, Node *p_node);
// Export process. // Export process.
virtual Error export_preflight(Ref<GLTFState> p_state, Node *p_root); virtual Error export_preflight(Ref<GLTFState> p_state, Node *p_root);
virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node); virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node);
virtual Error export_post_convert(Ref<GLTFState> p_state, Node *p_root);
virtual Error export_preserialize(Ref<GLTFState> p_state); virtual Error export_preserialize(Ref<GLTFState> p_state);
virtual Vector<String> get_saveable_image_formats(); virtual Vector<String> get_saveable_image_formats();
virtual PackedByteArray serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality); virtual PackedByteArray serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> 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<GLTFState>, PackedByteArray, String, Ref<Image>); GDVIRTUAL4R(Error, _parse_image_data, Ref<GLTFState>, PackedByteArray, String, Ref<Image>);
GDVIRTUAL0R(String, _get_image_file_extension); GDVIRTUAL0R(String, _get_image_file_extension);
GDVIRTUAL3R(Error, _parse_texture_json, Ref<GLTFState>, Dictionary, Ref<GLTFTexture>); GDVIRTUAL3R(Error, _parse_texture_json, Ref<GLTFState>, Dictionary, Ref<GLTFTexture>);
GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL1R(Error, _import_post_parse, Ref<GLTFState>); GDVIRTUAL1R(Error, _import_post_parse, Ref<GLTFState>);
GDVIRTUAL1R(Error, _import_pre_generate, Ref<GLTFState>);
GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL4R(Error, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); GDVIRTUAL4R(Error, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
GDVIRTUAL2R(Error, _import_post, Ref<GLTFState>, Node *); GDVIRTUAL2R(Error, _import_post, Ref<GLTFState>, Node *);
// Export process. // Export process.
GDVIRTUAL2R(Error, _export_preflight, Ref<GLTFState>, Node *); GDVIRTUAL2R(Error, _export_preflight, Ref<GLTFState>, Node *);
GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *); GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL2R(Error, _export_post_convert, Ref<GLTFState>, Node *);
GDVIRTUAL1R(Error, _export_preserialize, Ref<GLTFState>); GDVIRTUAL1R(Error, _export_preserialize, Ref<GLTFState>);
GDVIRTUAL0R(Vector<String>, _get_saveable_image_formats); GDVIRTUAL0R(Vector<String>, _get_saveable_image_formats);
GDVIRTUAL5R(PackedByteArray, _serialize_image_to_bytes, Ref<GLTFState>, Ref<Image>, Dictionary, String, float); GDVIRTUAL5R(PackedByteArray, _serialize_image_to_bytes, Ref<GLTFState>, Ref<Image>, Dictionary, String, float);

View file

@ -7205,6 +7205,12 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skeletons."); ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skeletons.");
err = _create_skins(p_state); err = _create_skins(p_state);
ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skins."); 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<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
err = ext->import_pre_generate(p_state);
ERR_CONTINUE(err != OK);
}
// Generate the node tree. // Generate the node tree.
Node *single_root; Node *single_root;
if (p_state->extensions_used.has("GODOT_single_root")) { if (p_state->extensions_used.has("GODOT_single_root")) {
@ -7439,6 +7445,12 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint
state->extensions_used.append("GODOT_single_root"); state->extensions_used.append("GODOT_single_root");
} }
_convert_scene_node(state, p_node, -1, -1); _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<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
Error err = ext->export_post_convert(p_state, p_node);
ERR_CONTINUE(err != OK);
}
return OK; return OK;
} }