diff options
-rw-r--r-- | doc/classes/@GlobalScope.xml | 4 | ||||
-rw-r--r-- | editor/editor_node.cpp | 17 | ||||
-rw-r--r-- | editor/editor_node.h | 1 | ||||
-rw-r--r-- | modules/fbx/data/fbx_mesh_data.cpp | 28 | ||||
-rw-r--r-- | modules/fbx/data/import_state.h | 1 | ||||
-rw-r--r-- | modules/fbx/editor_scene_importer_fbx.cpp | 10 | ||||
-rw-r--r-- | modules/fbx/editor_scene_importer_fbx.h | 4 | ||||
-rw-r--r-- | modules/gltf/gltf_document.cpp | 31 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 3 |
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); |