diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index ae04b63cfeb..eca0423a355 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -200,7 +200,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) #else if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { - RS::_fix_surface_compatibility(new_surface); + RS::get_singleton()->fix_surface_compatibility(new_surface); surface_version = new_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION), "Surface version provided (" + diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8e749f4def4..ffad8d7a43e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -153,6 +153,7 @@ #include "editor/project_settings_editor.h" #include "editor/register_exporters.h" #include "editor/scene_tree_dock.h" +#include "editor/surface_upgrade_tool.h" #include "editor/window_wrapper.h" #include @@ -5501,11 +5502,16 @@ bool EditorNode::ensure_main_scene(bool p_from_native) { void EditorNode::_immediate_dialog_confirmed() { immediate_dialog_confirmed = true; } -bool EditorNode::immediate_confirmation_dialog(const String &p_text, const String &p_ok_text, const String &p_cancel_text) { +bool EditorNode::immediate_confirmation_dialog(const String &p_text, const String &p_ok_text, const String &p_cancel_text, uint32_t p_wrap_width) { ConfirmationDialog *cd = memnew(ConfirmationDialog); cd->set_text(p_text); cd->set_ok_button_text(p_ok_text); cd->set_cancel_button_text(p_cancel_text); + if (p_wrap_width > 0) { + cd->set_autowrap(true); + cd->get_label()->set_custom_minimum_size(Size2(p_wrap_width, 0) * EDSCALE); + } + cd->connect("confirmed", callable_mp(singleton, &EditorNode::_immediate_dialog_confirmed)); singleton->gui_base->add_child(cd); @@ -8023,6 +8029,8 @@ EditorNode::EditorNode() { String exec = OS::get_singleton()->get_executable_path(); // Save editor executable path for third-party tools. EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); + + surface_upgrade_tool = memnew(SurfaceUpgradeTool); } EditorNode::~EditorNode() { @@ -8037,6 +8045,7 @@ EditorNode::~EditorNode() { memdelete(editor_plugins_force_over); memdelete(editor_plugins_force_input_forwarding); memdelete(progress_hb); + memdelete(surface_upgrade_tool); EditorSettings::destroy(); EditorColorMap::finish(); diff --git a/editor/editor_node.h b/editor/editor_node.h index 4e36c19e96a..7d85055ac27 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -113,6 +113,7 @@ class ProjectSettingsEditor; class RunSettingsDialog; class SceneImportSettings; class ScriptCreateDialog; +class SurfaceUpgradeTool; class WindowWrapper; class EditorNode : public Node { @@ -493,6 +494,8 @@ private: HashMap> icon_type_cache; + SurfaceUpgradeTool *surface_upgrade_tool = nullptr; + static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS]; static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS]; static int build_callback_count; @@ -738,7 +741,7 @@ public: static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); } static void add_build_callback(EditorBuildCallback p_callback); - static bool immediate_confirmation_dialog(const String &p_text, const String &p_ok_text = TTR("Ok"), const String &p_cancel_text = TTR("Cancel")); + static bool immediate_confirmation_dialog(const String &p_text, const String &p_ok_text = TTR("Ok"), const String &p_cancel_text = TTR("Cancel"), uint32_t p_wrap_width = 0); static void cleanup(); diff --git a/editor/surface_upgrade_tool.cpp b/editor/surface_upgrade_tool.cpp new file mode 100644 index 00000000000..26ff6e55a03 --- /dev/null +++ b/editor/surface_upgrade_tool.cpp @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* surface_upgrade_tool.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "surface_upgrade_tool.h" + +#include "editor/editor_file_system.h" +#include "editor/editor_node.h" +#include "servers/rendering_server.h" + +void SurfaceUpgradeTool::_add_files(EditorFileSystemDirectory *p_dir, HashSet &r_paths, PackedStringArray &r_files) { + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + _add_files(p_dir->get_subdir(i), r_paths, r_files); + } + + for (int i = 0; i < p_dir->get_file_count(); i++) { + if (p_dir->get_file_type(i) == "Mesh" || + p_dir->get_file_type(i) == "ArrayMesh" || + p_dir->get_file_type(i) == "PackedScene") { + if (FileAccess::exists(p_dir->get_file_path(i) + ".import")) { + r_files.push_back(p_dir->get_file_path(i)); + } else { + r_paths.insert(p_dir->get_file_path(i)); + } + } + } +} + +void SurfaceUpgradeTool::upgrade_all_meshes() { + // Update all meshes here. + HashSet paths; + PackedStringArray files_to_import; + _add_files(EditorFileSystem::get_singleton()->get_filesystem(), paths, files_to_import); + + EditorProgress ep("Re-saving all scenes and meshes", TTR("Upgrading All Meshes in Project"), paths.size()); + + ep.step(TTR("Re-importing meshes"), 0); + EditorFileSystem::get_singleton()->reimport_files(files_to_import); + + uint32_t step = 1; + for (const String &file : paths) { + Ref res = ResourceLoader::load(file); + ep.step(TTR("Attempting to re-save ") + file, step++); + if (res.is_valid()) { + // Ignore things that fail to load. + ResourceSaver::save(res); + } + } +} + +void SurfaceUpgradeTool::_show_popup() { + RS::get_singleton()->set_surface_upgrade_callback(nullptr); + bool accepted = EditorNode::immediate_confirmation_dialog(TTR("This project uses meshes with an outdated mesh format from previous Godot versions. The engine needs to update the format in order to use those meshes.\n\nPress 'Upgrade & Re-save' to have the engine scan the project folder and automatically update and re-save all meshes and scenes. This update may take a few minutes. Upgrading will make the meshes incompatible with previous versions of Godot.\n\nPress 'Upgrade Only' to continue opening the scene as normal. The engine will update each mesh in memory, but the update will not be saved. Choosing this option will lead to slower load times every time this project is loaded."), TTR("Upgrade & Re-save"), TTR("Upgrade Only"), 500); + if (accepted) { + RS::get_singleton()->set_warn_on_surface_upgrade(false); + upgrade_all_meshes(); + } +} + +SurfaceUpgradeTool::SurfaceUpgradeTool() { + RS::get_singleton()->set_surface_upgrade_callback(_show_popup); +} + +SurfaceUpgradeTool::~SurfaceUpgradeTool() {} diff --git a/editor/surface_upgrade_tool.h b/editor/surface_upgrade_tool.h new file mode 100644 index 00000000000..fa052200d8c --- /dev/null +++ b/editor/surface_upgrade_tool.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* surface_upgrade_tool.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SURFACE_UPGRADE_TOOL_H +#define SURFACE_UPGRADE_TOOL_H + +#include "scene/main/node.h" + +class EditorFileSystemDirectory; + +class SurfaceUpgradeTool { + static void upgrade_all_meshes(); + + static void _show_popup(); + static void _add_files(EditorFileSystemDirectory *p_dir, HashSet &r_paths, PackedStringArray &r_files); + +public: + SurfaceUpgradeTool(); + ~SurfaceUpgradeTool(); +}; + +#endif // SURFACE_UPGRADE_TOOL_H diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 3aeec7ea87a..2aabf142038 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1638,7 +1638,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { #ifndef DISABLE_DEPRECATED uint64_t surface_version = surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); if (surface_version != ARRAY_FLAG_FORMAT_CURRENT_VERSION) { - RS::_fix_surface_compatibility(surface); + RS::get_singleton()->fix_surface_compatibility(surface, get_path()); } #endif diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 14605b308ee..36ce1e38c69 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -356,7 +356,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) #else if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { - RS::_fix_surface_compatibility(new_surface); + RS::get_singleton()->fix_surface_compatibility(new_surface); surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Surface version provided (" + diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 2b4fe6e01b0..952d4796516 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2036,15 +2036,39 @@ Vector _convert_surface_version_1_to_surface_version_2(uint64_t p_forma return new_vertex_data; } +#ifdef TOOLS_ENABLED +void RenderingServer::set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback) { + surface_upgrade_callback = p_callback; +} + +void RenderingServer::set_warn_on_surface_upgrade(bool p_warn) { + warn_on_surface_upgrade = p_warn; +} +#endif + #ifndef DISABLE_DEPRECATED -void RenderingServer::_fix_surface_compatibility(SurfaceData &p_surface) { +void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const String &p_path) { uint64_t surface_version = p_surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version > ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Cannot convert surface with version provided (" + itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ") to current version (" + itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ")"); +#ifdef TOOLS_ENABLED + // Editor callback to ask user about re-saving all meshes. + if (surface_upgrade_callback && warn_on_surface_upgrade) { + surface_upgrade_callback(); + } + + if (warn_on_surface_upgrade) { + if (p_path.is_empty()) { + WARN_PRINT("A surface uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + } else { + WARN_PRINT("A surface of " + p_path + " uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + } + } +#endif + if (surface_version == ARRAY_FLAG_FORMAT_VERSION_1) { // The only difference for now is that Version 1 uses interleaved vertex positions while version 2 does not. // I.e. PNTPNTPNT -> PPPNTNTNT. - WARN_PRINT_ED("Upgrading mesh from older surface format. Once saved again (or re-imported), this mesh will be incompatible with earlier versions of Godot."); int vertex_size = 0; int normal_size = 0; diff --git a/servers/rendering_server.h b/servers/rendering_server.h index ba8cc3ba80e..5b8c16e7feb 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1630,8 +1630,14 @@ public: RenderingServer(); virtual ~RenderingServer(); +#ifdef TOOLS_ENABLED + typedef void (*SurfaceUpgradeCallback)(); + void set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback); + void set_warn_on_surface_upgrade(bool p_warn); +#endif + #ifndef DISABLE_DEPRECATED - static void _fix_surface_compatibility(SurfaceData &p_surface); + void fix_surface_compatibility(SurfaceData &p_surface, const String &p_path = ""); #endif private: @@ -1647,6 +1653,10 @@ private: TypedArray _instance_geometry_get_shader_parameter_list(RID p_instance) const; TypedArray _bake_render_uv2(RID p_base, const TypedArray &p_material_overrides, const Size2i &p_image_size); void _particles_set_trail_bind_poses(RID p_particles, const TypedArray &p_bind_poses); +#ifdef TOOLS_ENABLED + SurfaceUpgradeCallback surface_upgrade_callback = nullptr; + bool warn_on_surface_upgrade = true; +#endif }; // Make variant understand the enums.