summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--editor/editor_node.cpp17
-rw-r--r--editor/editor_node.h1
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp28
-rw-r--r--modules/fbx/data/import_state.h1
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp10
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h4
-rw-r--r--modules/gltf/gltf_document.cpp31
-rw-r--r--scene/gui/text_edit.cpp3
9 files changed, 45 insertions, 54 deletions
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index b40ae65a61..bf81362e79 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -668,7 +668,7 @@
</method>
<method name="print" qualifiers="vararg">
<description>
- Converts one or more arguments to strings in the best way possible and prints them to the console.
+ Converts one or more arguments of any type to string in the best way possible and prints them to the console.
[codeblock]
a = [1, 2, 3]
print("a", "b", a) # Prints ab[1, 2, 3]
@@ -994,7 +994,7 @@
<return type="String">
</return>
<description>
- Converts one or more arguments to string in the best way possible.
+ Converts one or more arguments of any type to string in the best way possible.
</description>
</method>
<method name="str2var">
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 72d9aacef3..ce579febfe 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2123,7 +2123,10 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (scene->get_filename() == "") {
current_option = -1;
- _menu_option_confirm(FILE_SAVE_BEFORE_RUN, false);
+ _menu_option(FILE_SAVE_AS_SCENE);
+ // Set the option to save and run so when the dialog is accepted, the scene runs.
+ current_option = FILE_SAVE_AND_RUN;
+ file->set_title(TTR("Save scene before running..."));
return;
}
@@ -2382,18 +2385,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_SAVE_ALL_SCENES: {
_save_all_scenes();
} break;
- case FILE_SAVE_BEFORE_RUN: {
- if (!p_confirmed) {
- confirmation->get_cancel_button()->set_text(TTR("No"));
- confirmation->get_ok_button()->set_text(TTR("Yes"));
- confirmation->set_text(TTR("This scene has never been saved. Save before running?"));
- confirmation->popup_centered();
- break;
- }
-
- _menu_option(FILE_SAVE_AS_SCENE);
- _menu_option_confirm(FILE_SAVE_AND_RUN, false);
- } break;
case FILE_EXPORT_PROJECT: {
project_export->popup_export();
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 0ef2e8cbfc..12aa2a2f5d 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -125,7 +125,6 @@ private:
FILE_SAVE_SCENE,
FILE_SAVE_AS_SCENE,
FILE_SAVE_ALL_SCENES,
- FILE_SAVE_BEFORE_RUN,
FILE_SAVE_AND_RUN,
FILE_SHOW_IN_FILESYSTEM,
FILE_IMPORT_SUBSCENE,
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index d84a7ab17c..963a815896 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -135,26 +135,6 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
&collect_all,
HashMap<int, Vector3>());
- // List<int> keys;
- // normals.get_key_list(&keys);
- //
- // const std::vector<Assimp::FBX::MeshGeometry::Edge>& edges = mesh_geometry->get_edge_map();
- // for (int index = 0; index < keys.size(); index++) {
- // const int key = keys[index];
- // const int v1 = edges[key].vertex_0;
- // const int v2 = edges[key].vertex_1;
- // const Vector3& n1 = normals.get(v1);
- // const Vector3& n2 = normals.get(v2);
- // print_verbose("[" + itos(v1) + "] n1: " + n1 + "\n[" + itos(v2) + "] n2: " + n2);
- // //print_verbose("[" + itos(key) + "] n1: " + n1 + ", n2: " + n2) ;
- // //print_verbose("vindex: " + itos(edges[key].vertex_0) + ", vindex2: " + itos(edges[key].vertex_1));
- // //Vector3 ver1 = vertices[edges[key].vertex_0];
- // //Vector3 ver2 = vertices[edges[key].vertex_1];
- // /*real_t angle1 = Math::rad2deg(n1.angle_to(n2));
- // real_t angle2 = Math::rad2deg(n2.angle_to(n1));
- // print_verbose("angle of normals: " + rtos(angle1) + " angle 2" + rtos(angle2));*/
- // }
-
HashMap<int, Vector2> uvs_0;
HashMap<int, HashMap<int, Vector2>> uvs_0_raw = extract_per_vertex_data(
vertices.size(),
@@ -371,6 +351,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
normals_ptr[vertex]);
}
+ if (state.is_blender_fbx) {
+ morph_st->generate_normals();
+ }
morph_st->generate_tangents();
surface->morphs.push_back(morph_st->commit_to_arrays());
}
@@ -393,6 +376,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
SurfaceData *surface = surfaces.getptr(*surface_id);
+ if (state.is_blender_fbx) {
+ surface->surface_tool->generate_normals();
+ }
// you can't generate them without a valid uv map.
if (uvs_0_raw.size() > 0) {
surface->surface_tool->generate_tangents();
@@ -785,7 +771,7 @@ void FBXMeshData::add_vertex(
const Vector3 &p_morph_normal) {
ERR_FAIL_INDEX_MSG(p_vertex, (Vertex)p_vertices_position.size(), "FBX file is corrupted, the position of the vertex can't be retrieved.");
- if (p_normals.has(p_vertex)) {
+ if (p_normals.has(p_vertex) && !state.is_blender_fbx) {
p_surface_tool->set_normal(p_normals[p_vertex] + p_morph_normal);
}
diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h
index 1d664a5212..83bc43faff 100644
--- a/modules/fbx/data/import_state.h
+++ b/modules/fbx/data/import_state.h
@@ -64,6 +64,7 @@ struct FBXSkeleton;
struct ImportState {
bool enable_material_import = true;
bool enable_animation_import = true;
+ bool is_blender_fbx = false;
Map<StringName, Ref<Texture>> cached_image_searches;
Map<uint64_t, Ref<Material>> cached_materials;
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index 5918f4dbed..6576147b2b 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -180,10 +180,12 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
}
if (is_blender_fbx) {
- WARN_PRINT("Blender FBX files will not work properly with keyframes or skeletons until we make fixes. Please stand by.");
+ WARN_PRINT("We don't officially support Blender FBX animations yet, due to issues with upstream Blender,\n"
+ "so please wait for us to work around remaining issues. We will continue to import the file but it may be broken.\n"
+ "For minimal breakage, please export FBX from Blender with -Z forward, and Y up.");
}
- Node3D *spatial = _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8);
+ Node3D *spatial = _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8, is_blender_fbx);
// todo: move to document shutdown (will need to be validated after moving; this code has been validated already)
for (FBXDocParser::TokenPtr token : tokens) {
if (token) {
@@ -327,8 +329,10 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
const FBXDocParser::Document *p_document,
const uint32_t p_flags,
int p_bake_fps,
- const int32_t p_max_bone_weights) {
+ const int32_t p_max_bone_weights,
+ bool p_is_blender_fbx) {
ImportState state;
+ state.is_blender_fbx = p_is_blender_fbx;
state.path = p_path;
state.animation_player = NULL;
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
index 25c7c1a907..39f8648b0f 100644
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -114,7 +114,9 @@ private:
Node3D *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document,
const uint32_t p_flags,
- int p_bake_fps, const int32_t p_max_bone_weights);
+ int p_bake_fps,
+ const int32_t p_max_bone_weights,
+ bool p_is_blender_fbx);
template <class T>
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 2b6211095a..580bc006f5 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -2918,21 +2918,30 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
}
} else { // Relative path to an external image file.
uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
- // The spec says that if mimeType is defined, we should enforce it.
- // So we should only rely on ResourceLoader::load if mimeType is not defined,
- // otherwise we should use the same logic as for buffers.
- if (mimetype == "image/png" || mimetype == "image/jpeg") {
- // Load data buffer and rely on PNG and JPEG-specific logic below to load the image.
- // This makes it possible to load a file with a wrong extension but correct MIME type,
- // e.g. "foo.jpg" containing PNG data and with MIME type "image/png". ResourceLoader would fail.
+ // ResourceLoader will rely on the file extension to use the relevant loader.
+ // The spec says that if mimeType is defined, it should take precedence (e.g.
+ // there could be a `.png` image which is actually JPEG), but there's no easy
+ // API for that in Godot, so we'd have to load as a buffer (i.e. embedded in
+ // the material), so we do this only as fallback.
+ Ref<Texture2D> texture = ResourceLoader::load(uri);
+ if (texture.is_valid()) {
+ state->images.push_back(texture);
+ continue;
+ } else if (mimetype == "image/png" || mimetype == "image/jpeg") {
+ // Fallback to loading as byte array.
+ // This enables us to support the spec's requirement that we honor mimetype
+ // regardless of file URI.
data = FileAccess::get_file_as_array(uri);
- ERR_FAIL_COND_V_MSG(data.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load image file as an array: " + uri);
+ if (data.size() == 0) {
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s. Skipping it.", i, mimetype, uri));
+ state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ continue;
+ }
data_ptr = data.ptr();
data_size = data.size();
} else {
- // Good old ResourceLoader will rely on file extension.
- Ref<Texture2D> texture = ResourceLoader::load(uri);
- state->images.push_back(texture);
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded from URI: %s. Skipping it.", i, uri));
+ state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
continue;
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 75b875ff0b..7557d36298 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1285,8 +1285,7 @@ void TextEdit::_notification(int p_what) {
if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) {
int yofs = (text_height - cache.tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), current_color);
- }
- if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
+ } else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
int yofs = (text_height - cache.space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
int xofs = (glyphs[j].advance * glyphs[j].repeat - cache.space_icon->get_width()) / 2;
cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x + xofs, ofs_y + yofs), current_color);