Browse Source

GLTF: Add import_pre_generate and export_post_convert extension steps

Aaron Franke 1 năm trước cách đây
mục cha
commit
5972907612

+ 22 - 5
modules/gltf/doc_classes/GLTFDocumentExtension.xml

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

+ 25 - 8
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<GLTFState> p_state, const Di
 	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) {
 	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<GLTFState> p_state, Ref<G
 	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) {
 	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<GLTFState> p_state, Ref<GLTFN
 	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) {
 	ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
 	Error err = OK;

+ 5 - 1
modules/gltf/extensions/gltf_document_extension.h

@@ -50,12 +50,14 @@ public:
 	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 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 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);
 	// Export process.
 	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 Error export_post_convert(Ref<GLTFState> p_state, Node *p_root);
 	virtual Error export_preserialize(Ref<GLTFState> p_state);
 	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);
@@ -71,13 +73,15 @@ public:
 	GDVIRTUAL4R(Error, _parse_image_data, Ref<GLTFState>, PackedByteArray, String, Ref<Image>);
 	GDVIRTUAL0R(String, _get_image_file_extension);
 	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_pre_generate, Ref<GLTFState>);
+	GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
 	GDVIRTUAL4R(Error, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
 	GDVIRTUAL2R(Error, _import_post, Ref<GLTFState>, Node *);
 	// Export process.
 	GDVIRTUAL2R(Error, _export_preflight, Ref<GLTFState>, Node *);
 	GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
+	GDVIRTUAL2R(Error, _export_post_convert, Ref<GLTFState>, Node *);
 	GDVIRTUAL1R(Error, _export_preserialize, Ref<GLTFState>);
 	GDVIRTUAL0R(Vector<String>, _get_saveable_image_formats);
 	GDVIRTUAL5R(PackedByteArray, _serialize_image_to_bytes, Ref<GLTFState>, Ref<Image>, Dictionary, String, float);

+ 12 - 0
modules/gltf/gltf_document.cpp

@@ -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 = _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<GLTFDocumentExtension> 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<GLTFState> 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<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;
 }