Merge pull request #68981 from aaronfranke/gltf-methods

Add three new methods to GLTFDocumentExtension and document all of its methods
This commit is contained in:
Rémi Verschelde 2022-11-22 08:30:30 +01:00
commit 3f2ca44534
No known key found for this signature in database
GPG Key ID: C3336907360768E1
4 changed files with 168 additions and 48 deletions

View File

@ -11,6 +11,16 @@
<tutorials>
</tutorials>
<methods>
<method name="_convert_scene_node" qualifiers="virtual">
<return type="void" />
<param index="0" name="state" type="GLTFState" />
<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_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>
</method>
<method name="_export_node" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
@ -18,23 +28,40 @@
<param index="2" name="json" type="Dictionary" />
<param index="3" name="node" type="Node" />
<description>
Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_post].
This method can be used to modify the final JSON of each node.
</description>
</method>
<method name="_export_post" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
<description>
Part of the export process. This method is run last, after all other parts of the export process.
This method can be used to modify the final JSON of the generated GLTF file.
</description>
</method>
<method name="_export_preflight" qualifiers="virtual">
<return type="int" />
<param index="0" name="root" type="Node" />
<description>
Part of the export process. This method is run first, before all other parts of the export process.
The return value is used to determine if this GLTFDocumentExtension class should be used for exporting a given GLTF file. If [constant OK], the export will use this GLTFDocumentExtension class. If not overridden, [constant OK] is returned.
</description>
</method>
<method name="_generate_scene_node" qualifiers="virtual">
<return type="Node3D" />
<param index="0" name="state" type="GLTFState" />
<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 _parse_node_extensions] and before [method _import_post_parse].
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.
</description>
</method>
<method name="_get_supported_extensions" qualifiers="virtual">
<return type="PackedStringArray" />
<description>
Part of the import process. This method is run after [method _import_preflight] and before [method _parse_node_extensions].
Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded.
</description>
</method>
@ -45,6 +72,8 @@
<param index="2" name="json" type="Dictionary" />
<param index="3" name="node" type="Node" />
<description>
Part of the import process. This method is run after [method _import_post_parse] and before [method _import_post].
This method can be used to make modifications to each of the generated Godot scene nodes.
</description>
</method>
<method name="_import_post" qualifiers="virtual">
@ -52,12 +81,16 @@
<param index="0" name="state" type="GLTFState" />
<param index="1" name="root" type="Node" />
<description>
Part of the import process. This method is run last, after all other parts of the import process.
This method can be used to modify the final Godot scene generated by the import process.
</description>
</method>
<method name="_import_post_parse" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
<description>
Part of the import process. This method is run after [method _generate_scene_node] and before [method _import_node].
This method can be used to modify any of the data imported so far, including any scene nodes, before running the final per-node import step.
</description>
</method>
<method name="_import_preflight" qualifiers="virtual">
@ -65,7 +98,18 @@
<param index="0" name="state" type="GLTFState" />
<param index="1" name="extensions" type="PackedStringArray" />
<description>
This callback is run first. It is used to determine if this GLTFDocumentExtension class should be used for importing a given GLTF file. If [constant OK], the import will use this GLTFDocumentExtension class.
Part of the import process. This method is run first, before all other parts of the import process.
The return value is used to determine if this GLTFDocumentExtension class should be used for importing a given GLTF file. If [constant OK], the import will use this GLTFDocumentExtension class. If not overridden, [constant OK] is returned.
</description>
</method>
<method name="_parse_node_extensions" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
<param index="1" name="gltf_node" type="GLTFNode" />
<param index="2" name="extensions" type="Dictionary" />
<description>
Part of the import process. This method is run after [method _get_supported_extensions] and before [method _generate_scene_node].
Runs when parsing the node extensions of a GLTFNode. This method can be used to process the extension JSON data into a format that can be used by [method _generate_scene_node].
</description>
</method>
</methods>

View File

@ -31,35 +31,50 @@
#include "gltf_document_extension.h"
void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_supported_extensions);
// Import process.
GDVIRTUAL_BIND(_import_preflight, "state", "extensions");
GDVIRTUAL_BIND(_get_supported_extensions);
GDVIRTUAL_BIND(_parse_node_extensions, "state", "gltf_node", "extensions");
GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent");
GDVIRTUAL_BIND(_import_post_parse, "state");
GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
GDVIRTUAL_BIND(_import_post, "state", "root");
// Export process.
GDVIRTUAL_BIND(_export_preflight, "root");
GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node");
GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node");
GDVIRTUAL_BIND(_export_post, "state");
}
// Import process.
Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_import_preflight, p_state, p_extensions, err);
return Error(err);
}
Vector<String> GLTFDocumentExtension::get_supported_extensions() {
Vector<String> ret;
GDVIRTUAL_CALL(_get_supported_extensions, ret);
return ret;
}
Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
Error GLTFDocumentExtension::parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_import_post, p_state, p_root, err);
GDVIRTUAL_CALL(_parse_node_extensions, p_state, p_gltf_node, p_extensions, err);
return Error(err);
}
Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_import_preflight, p_state, p_extensions, err);
return Error(err);
Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
ERR_FAIL_NULL_V(p_state, nullptr);
ERR_FAIL_NULL_V(p_gltf_node, nullptr);
ERR_FAIL_NULL_V(p_scene_parent, nullptr);
Node3D *ret_node = nullptr;
GDVIRTUAL_CALL(_generate_scene_node, p_state, p_gltf_node, p_scene_parent, ret_node);
return ret_node;
}
Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) {
@ -69,19 +84,6 @@ Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) {
return Error(err);
}
Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_export_post, p_state, err);
return Error(err);
}
Error GLTFDocumentExtension::export_preflight(Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_export_preflight, p_root, err);
return Error(err);
}
Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
@ -91,6 +93,29 @@ Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p
return Error(err);
}
Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_import_post, p_state, p_root, err);
return Error(err);
}
// Export process.
Error GLTFDocumentExtension::export_preflight(Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_export_preflight, p_root, err);
return Error(err);
}
void GLTFDocumentExtension::convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) {
ERR_FAIL_NULL(p_state);
ERR_FAIL_NULL(p_gltf_node);
ERR_FAIL_NULL(p_scene_node);
GDVIRTUAL_CALL(_convert_scene_node, p_state, p_gltf_node, p_scene_node);
}
Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
@ -99,3 +124,10 @@ Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p
GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err);
return Error(err);
}
Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
GDVIRTUAL_CALL(_export_post, p_state, err);
return Error(err);
}

View File

@ -40,20 +40,31 @@ protected:
static void _bind_methods();
public:
virtual Vector<String> get_supported_extensions();
// Import process.
virtual Error import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions);
virtual Vector<String> get_supported_extensions();
virtual Error parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions);
virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
virtual Error import_post_parse(Ref<GLTFState> p_state);
virtual Error export_post(Ref<GLTFState> p_state);
virtual Error import_post(Ref<GLTFState> p_state, Node *p_node);
virtual Error export_preflight(Node *p_state);
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(Node *p_state);
virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node);
virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
GDVIRTUAL0R(Vector<String>, _get_supported_extensions);
virtual Error export_post(Ref<GLTFState> p_state);
// Import process.
GDVIRTUAL2R(int, _import_preflight, Ref<GLTFState>, Vector<String>);
GDVIRTUAL0R(Vector<String>, _get_supported_extensions);
GDVIRTUAL3R(int, _parse_node_extensions, Ref<GLTFState>, Ref<GLTFNode>, Dictionary);
GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>);
GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
GDVIRTUAL2R(int, _import_post, Ref<GLTFState>, Node *);
// Export process.
GDVIRTUAL1R(int, _export_preflight, Node *);
GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL4R(int, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
GDVIRTUAL1R(int, _export_post, Ref<GLTFState>);
};

View File

@ -625,6 +625,11 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
node->light = light;
}
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
Error err = ext->parse_node_extensions(state, node, extensions);
ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing node extensions for node " + node->get_name() + " in file " + state->filename + ". Continuing.");
}
}
if (n.has("children")) {
@ -5266,6 +5271,10 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co
AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current);
_convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current);
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
ext->convert_scene_node(state, gltf_node, p_current);
}
GLTFNodeIndex current_node_i = state->nodes.size();
GLTFNodeIndex gltf_root = p_gltf_root;
if (gltf_root == -1) {
@ -5589,21 +5598,32 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
// and attach it to the bone_attachment
scene_parent = bone_attachment;
}
// Check if any GLTFDocumentExtension classes want to generate a node for us.
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
current_node = ext->generate_scene_node(state, gltf_node, scene_parent);
if (current_node) {
break;
}
}
// If none of our GLTFDocumentExtension classes generated us a node, we generate one.
if (!current_node) {
if (gltf_node->mesh >= 0) {
current_node = _generate_mesh_instance(state, node_index);
} else if (gltf_node->camera >= 0) {
current_node = _generate_camera(state, node_index);
} else if (gltf_node->light >= 0) {
current_node = _generate_light(state, node_index);
}
// We still have not managed to make a node.
if (!current_node) {
} else {
current_node = _generate_spatial(state, node_index);
}
}
// Add the node we generated and set the owner to the scene root.
scene_parent->add_child(current_node, true);
if (current_node != scene_root) {
current_node->set_owner(scene_root);
Array args;
args.append(scene_root);
current_node->propagate_call(StringName("set_owner"), args);
}
current_node->set_transform(gltf_node->xform);
current_node->set_name(gltf_node->get_name());
@ -5669,19 +5689,32 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen
// and attach it to the bone_attachment
scene_parent = bone_attachment;
}
// We still have not managed to make a node
// Check if any GLTFDocumentExtension classes want to generate a node for us.
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
current_node = ext->generate_scene_node(state, gltf_node, scene_parent);
if (current_node) {
break;
}
}
// If none of our GLTFDocumentExtension classes generated us a node, we generate one.
if (!current_node) {
if (gltf_node->mesh >= 0) {
current_node = _generate_mesh_instance(state, node_index);
} else if (gltf_node->camera >= 0) {
current_node = _generate_camera(state, node_index);
} else if (gltf_node->light >= 0) {
current_node = _generate_light(state, node_index);
} else {
current_node = _generate_spatial(state, node_index);
}
}
// Add the node we generated and set the owner to the scene root.
scene_parent->add_child(current_node, true);
if (current_node != scene_root) {
current_node->set_owner(scene_root);
Array args;
args.append(scene_root);
current_node->propagate_call(StringName("set_owner"), args);
}
// Do not set transform here. Transform is already applied to our bone.
current_node->set_name(gltf_node->get_name());