Implementation of tool to automatically upgrade and re-save meshes

This commit is contained in:
clayjohn 2023-10-19 13:31:26 +02:00
parent 7f884b4e00
commit 318ef8461f
9 changed files with 193 additions and 8 deletions

View file

@ -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 (" +

View file

@ -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 <stdio.h>
@ -5507,11 +5508,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);
@ -8022,6 +8028,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() {
@ -8036,6 +8044,7 @@ EditorNode::~EditorNode() {
memdelete(editor_plugins_force_over);
memdelete(editor_plugins_force_input_forwarding);
memdelete(progress_hb);
memdelete(surface_upgrade_tool);
EditorSettings::destroy();

View file

@ -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<String, Ref<Texture2D>> 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();

View file

@ -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<String> &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<String> 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<Resource> 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() {}

View file

@ -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<String> &r_paths, PackedStringArray &r_files);
public:
SurfaceUpgradeTool();
~SurfaceUpgradeTool();
};
#endif // SURFACE_UPGRADE_TOOL_H

View file

@ -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

View file

@ -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 (" +

View file

@ -2036,15 +2036,39 @@ Vector<uint8_t> _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;

View file

@ -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<Dictionary> _instance_geometry_get_shader_parameter_list(RID p_instance) const;
TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size);
void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses);
#ifdef TOOLS_ENABLED
SurfaceUpgradeCallback surface_upgrade_callback = nullptr;
bool warn_on_surface_upgrade = true;
#endif
};
// Make variant understand the enums.