summaryrefslogtreecommitdiff
path: root/modules/gltf
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gltf')
-rw-r--r--modules/gltf/SCsub2
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml3
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml8
-rw-r--r--modules/gltf/extensions/SCsub9
-rw-r--r--modules/gltf/gltf_defines.h2
-rw-r--r--modules/gltf/gltf_document.cpp95
-rw-r--r--modules/gltf/gltf_document.h4
-rw-r--r--modules/gltf/gltf_document_extension.cpp7
-rw-r--r--modules/gltf/gltf_document_extension.h2
-rw-r--r--modules/gltf/gltf_state.cpp12
-rw-r--r--modules/gltf/gltf_state.h4
12 files changed, 116 insertions, 40 deletions
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub
index 71f3ba58d9..5f111165fd 100644
--- a/modules/gltf/SCsub
+++ b/modules/gltf/SCsub
@@ -7,7 +7,7 @@ env_gltf = env_modules.Clone()
# Godot source files
env_gltf.add_source_files(env.modules_sources, "*.cpp")
-env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp")
env_gltf.add_source_files(env.modules_sources, "structures/*.cpp")
+SConscript("extensions/SCsub")
if env["tools"]:
env_gltf.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index d2a9022445..936794976d 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFDocumentExtension" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ [GLTFDocument] extension class.
</brief_description>
<description>
+ Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export.
</description>
<tutorials>
</tutorials>
@@ -28,6 +30,12 @@
<description>
</description>
</method>
+ <method name="_get_supported_extensions" qualifiers="virtual">
+ <return type="PackedStringArray" />
+ <description>
+ 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>
<method name="_import_node" qualifiers="virtual">
<return type="int" />
<param index="0" name="state" type="GLTFState" />
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index e933e6046a..4d1aa89ac9 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ GLTF node class.
</brief_description>
<description>
+ Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes).
</description>
<tutorials>
+ <link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 1dbd89aed8..6c2f488c1c 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -7,6 +7,14 @@
<tutorials>
</tutorials>
<methods>
+ <method name="add_used_extension">
+ <return type="void" />
+ <param index="0" name="extension_name" type="String" />
+ <param index="1" name="required" type="bool" />
+ <description>
+ Appends an extension to the list of extensions used by this GLTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically.
+ </description>
+ </method>
<method name="get_accessors">
<return type="GLTFAccessor[]" />
<description>
diff --git a/modules/gltf/extensions/SCsub b/modules/gltf/extensions/SCsub
new file mode 100644
index 0000000000..ad214bb79c
--- /dev/null
+++ b/modules/gltf/extensions/SCsub
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_gltf = env_modules.Clone()
+
+# Godot source files
+env_gltf.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h
index c20c87f798..9ee2397968 100644
--- a/modules/gltf/gltf_defines.h
+++ b/modules/gltf/gltf_defines.h
@@ -66,9 +66,9 @@ using GLTFBufferIndex = int;
using GLTFBufferViewIndex = int;
using GLTFCameraIndex = int;
using GLTFImageIndex = int;
+using GLTFLightIndex = int;
using GLTFMaterialIndex = int;
using GLTFMeshIndex = int;
-using GLTFLightIndex = int;
using GLTFNodeIndex = int;
using GLTFSkeletonIndex = int;
using GLTFSkinIndex = int;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index f5730e7137..8d2e37be3a 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -191,14 +191,14 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return Error::FAILED;
}
- /* STEP SERIALIZE SCENE */
+ /* STEP SERIALIZE LIGHTS */
err = _serialize_lights(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE EXTENSIONS */
- err = _serialize_extensions(state);
+ err = _serialize_gltf_extensions(state);
if (err != OK) {
return Error::FAILED;
}
@@ -219,9 +219,9 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return OK;
}
-Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
- Array extensions_used;
- Array extensions_required;
+Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> state) const {
+ Vector<String> extensions_used = state->extensions_used;
+ Vector<String> extensions_required = state->extensions_required;
if (!state->lights.is_empty()) {
extensions_used.push_back("KHR_lights_punctual");
}
@@ -230,9 +230,11 @@ Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const {
extensions_required.push_back("KHR_texture_transform");
}
if (!extensions_used.is_empty()) {
+ extensions_used.sort();
state->json["extensionsUsed"] = extensions_used;
}
if (!extensions_required.is_empty()) {
+ extensions_required.sort();
state->json["extensionsRequired"] = extensions_required;
}
return OK;
@@ -401,47 +403,47 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
Array nodes;
for (int i = 0; i < state->nodes.size(); i++) {
Dictionary node;
- Ref<GLTFNode> n = state->nodes[i];
+ Ref<GLTFNode> gltf_node = state->nodes[i];
Dictionary extensions;
node["extensions"] = extensions;
- if (!n->get_name().is_empty()) {
- node["name"] = n->get_name();
+ if (!gltf_node->get_name().is_empty()) {
+ node["name"] = gltf_node->get_name();
}
- if (n->camera != -1) {
- node["camera"] = n->camera;
+ if (gltf_node->camera != -1) {
+ node["camera"] = gltf_node->camera;
}
- if (n->light != -1) {
+ if (gltf_node->light != -1) {
Dictionary lights_punctual;
extensions["KHR_lights_punctual"] = lights_punctual;
- lights_punctual["light"] = n->light;
+ lights_punctual["light"] = gltf_node->light;
}
- if (n->mesh != -1) {
- node["mesh"] = n->mesh;
+ if (gltf_node->mesh != -1) {
+ node["mesh"] = gltf_node->mesh;
}
- if (n->skin != -1) {
- node["skin"] = n->skin;
+ if (gltf_node->skin != -1) {
+ node["skin"] = gltf_node->skin;
}
- if (n->skeleton != -1 && n->skin < 0) {
+ if (gltf_node->skeleton != -1 && gltf_node->skin < 0) {
}
- if (n->xform != Transform3D()) {
- node["matrix"] = _xform_to_array(n->xform);
+ if (gltf_node->xform != Transform3D()) {
+ node["matrix"] = _xform_to_array(gltf_node->xform);
}
- if (!n->rotation.is_equal_approx(Quaternion())) {
- node["rotation"] = _quaternion_to_array(n->rotation);
+ if (!gltf_node->rotation.is_equal_approx(Quaternion())) {
+ node["rotation"] = _quaternion_to_array(gltf_node->rotation);
}
- if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
- node["scale"] = _vec3_to_arr(n->scale);
+ if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
+ node["scale"] = _vec3_to_arr(gltf_node->scale);
}
- if (!n->position.is_zero_approx()) {
- node["translation"] = _vec3_to_arr(n->position);
+ if (!gltf_node->position.is_zero_approx()) {
+ node["translation"] = _vec3_to_arr(gltf_node->position);
}
- if (n->children.size()) {
+ if (gltf_node->children.size()) {
Array children;
- for (int j = 0; j < n->children.size(); j++) {
- children.push_back(n->children[j]);
+ for (int j = 0; j < gltf_node->children.size(); j++) {
+ children.push_back(gltf_node->children[j]);
}
node["children"] = children;
}
@@ -450,7 +452,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
ERR_CONTINUE(ext.is_null());
ERR_CONTINUE(!state->scene_nodes.find(i));
- Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]);
+ Error err = ext->export_node(state, gltf_node, node, state->scene_nodes[i]);
ERR_CONTINUE(err != OK);
}
@@ -5046,7 +5048,7 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta
return mi;
}
-Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
+Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr);
@@ -5102,6 +5104,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeInde
return spatial;
}
+
void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
bool retflag = true;
_check_visibility(p_current, retflag);
@@ -6916,12 +6919,32 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR);
- if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) {
- Array extensions_required = state->json["extensionsRequired"];
- if (extensions_required.find("KHR_draco_mesh_compression") != -1) {
- ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported.");
- return ERR_UNAVAILABLE;
+ if (state->json.has("extensionsUsed")) {
+ Vector<String> ext_array = state->json["extensionsUsed"];
+ state->extensions_used = ext_array;
+ }
+ if (state->json.has("extensionsRequired")) {
+ Vector<String> ext_array = state->json["extensionsRequired"];
+ state->extensions_required = ext_array;
+ }
+ HashSet<String> supported_extensions;
+ supported_extensions.insert("KHR_lights_punctual");
+ supported_extensions.insert("KHR_materials_pbrSpecularGlossiness");
+ supported_extensions.insert("KHR_texture_transform");
+ for (int ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Vector<String> ext_supported_extensions = ext->get_supported_extensions();
+ for (int i = 0; i < ext_supported_extensions.size(); ++i) {
+ supported_extensions.insert(ext_supported_extensions[i]);
}
}
- return OK;
+ Error ret = Error::OK;
+ for (int i = 0; i < state->extensions_required.size(); i++) {
+ if (!supported_extensions.has(state->extensions_required[i])) {
+ ERR_PRINT("GLTF: Can't import file '" + state->filename + "', required extension '" + String(state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?");
+ ret = ERR_UNAVAILABLE;
+ }
+ }
+ return ret;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 36a2f94a4e..750d3d403e 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -188,7 +188,7 @@ private:
const GLTFNodeIndex bone_index);
ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index);
Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
+ Light3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index);
void _assign_scene_names(Ref<GLTFState> state);
template <class T>
@@ -265,7 +265,7 @@ private:
Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material);
Error _serialize_version(Ref<GLTFState> state);
Error _serialize_file(Ref<GLTFState> state, const String p_path);
- Error _serialize_extensions(Ref<GLTFState> state) const;
+ Error _serialize_gltf_extensions(Ref<GLTFState> state) const;
public:
// https://www.itu.int/rec/R-REC-BT.601
diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp
index d0bd7651e0..3b952f8246 100644
--- a/modules/gltf/gltf_document_extension.cpp
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -31,6 +31,7 @@
#include "gltf_document_extension.h"
void GLTFDocumentExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_supported_extensions);
GDVIRTUAL_BIND(_import_preflight, "state");
GDVIRTUAL_BIND(_import_post_parse, "state");
GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
@@ -40,6 +41,12 @@ void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_export_post, "state");
}
+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);
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h
index 0ef9109584..d4bb3993dc 100644
--- a/modules/gltf/gltf_document_extension.h
+++ b/modules/gltf/gltf_document_extension.h
@@ -41,6 +41,7 @@ protected:
static void _bind_methods();
public:
+ virtual Vector<String> get_supported_extensions();
virtual Error import_preflight(Ref<GLTFState> p_state);
virtual Error import_post_parse(Ref<GLTFState> p_state);
virtual Error export_post(Ref<GLTFState> p_state);
@@ -48,6 +49,7 @@ public:
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 export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
+ GDVIRTUAL0R(Vector<String>, _get_supported_extensions);
GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>);
GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>);
GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 85bac446cc..a23fb39503 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -31,6 +31,7 @@
#include "gltf_state.h"
void GLTFState::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension);
ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json);
ClassDB::bind_method(D_METHOD("get_major_version"), &GLTFState::get_major_version);
@@ -112,6 +113,17 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
}
+void GLTFState::add_used_extension(const String &p_extension_name, bool p_required) {
+ if (!extensions_used.has(p_extension_name)) {
+ extensions_used.push_back(p_extension_name);
+ }
+ if (p_required) {
+ if (!extensions_required.has(p_extension_name)) {
+ extensions_required.push_back(p_extension_name);
+ }
+ }
+}
+
Dictionary GLTFState::get_json() {
return json;
}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 6b2d1ca228..791431f376 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -78,6 +78,8 @@ class GLTFState : public Resource {
Vector<int> root_nodes;
Vector<Ref<GLTFTexture>> textures;
Vector<Ref<Texture2D>> images;
+ Vector<String> extensions_used;
+ Vector<String> extensions_required;
Vector<Ref<GLTFSkin>> skins;
Vector<Ref<GLTFCamera>> cameras;
@@ -97,6 +99,8 @@ protected:
static void _bind_methods();
public:
+ void add_used_extension(const String &p_extension, bool p_required = false);
+
Dictionary get_json();
void set_json(Dictionary p_json);