Skip to content

Commit 4553358

Browse files
committed
Revert "Rework scene preview thumbnails"
This reverts commit 0834318. While the feature is great, a number of issues have been found with the implementation, and we need more time to resolve them. So we roll this back for 4.5, to rework the feature for a later Godot release.
1 parent 6af4ef0 commit 4553358

11 files changed

+307
-849
lines changed

doc/classes/EditorInterface.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,6 @@
428428
<param index="1" name="with_preview" type="bool" default="true" />
429429
<description>
430430
Saves the currently active scene as a file at [param path].
431-
[b]Note:[/b] The [param with_preview] parameter has no effect.
432431
</description>
433432
</method>
434433
<method name="select_file">

editor/editor_interface.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
#include "editor/property_selector.h"
5353
#include "editor/themes/editor_scale.h"
5454
#include "main/main.h"
55+
#include "plugins/editor_preview_plugins.h"
56+
#include "scene/3d/light_3d.h"
57+
#include "scene/3d/mesh_instance_3d.h"
5558
#include "scene/gui/box_container.h"
5659
#include "scene/gui/control.h"
5760
#include "scene/main/window.h"
@@ -100,6 +103,27 @@ EditorUndoRedoManager *EditorInterface::get_editor_undo_redo() const {
100103
return EditorUndoRedoManager::get_singleton();
101104
}
102105

106+
AABB EditorInterface::_calculate_aabb_for_scene(Node *p_node, AABB &p_scene_aabb) {
107+
MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
108+
if (mesh_node && mesh_node->get_mesh().is_valid()) {
109+
Transform3D accum_xform;
110+
Node3D *base = mesh_node;
111+
while (base) {
112+
accum_xform = base->get_transform() * accum_xform;
113+
base = Object::cast_to<Node3D>(base->get_parent());
114+
}
115+
116+
AABB aabb = accum_xform.xform(mesh_node->get_mesh()->get_aabb());
117+
p_scene_aabb.merge_with(aabb);
118+
}
119+
120+
for (int i = 0; i < p_node->get_child_count(); i++) {
121+
p_scene_aabb = _calculate_aabb_for_scene(p_node->get_child(i), p_scene_aabb);
122+
}
123+
124+
return p_scene_aabb;
125+
}
126+
103127
TypedArray<Texture2D> EditorInterface::_make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size) {
104128
Vector<Ref<Mesh>> meshes;
105129

@@ -205,6 +229,137 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh
205229
return textures;
206230
}
207231

232+
void EditorInterface::make_scene_preview(const String &p_path, Node *p_scene, int p_preview_size) {
233+
ERR_FAIL_NULL_MSG(p_scene, "The provided scene is null.");
234+
ERR_FAIL_COND_MSG(p_scene->is_inside_tree(), "The scene must not be inside the tree.");
235+
ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be called from the editor.");
236+
ERR_FAIL_NULL_MSG(EditorNode::get_singleton(), "EditorNode doesn't exist.");
237+
238+
SubViewport *sub_viewport_node = memnew(SubViewport);
239+
AABB scene_aabb;
240+
scene_aabb = _calculate_aabb_for_scene(p_scene, scene_aabb);
241+
242+
sub_viewport_node->set_update_mode(SubViewport::UPDATE_ALWAYS);
243+
sub_viewport_node->set_size(Vector2i(p_preview_size, p_preview_size));
244+
sub_viewport_node->set_transparent_background(false);
245+
Ref<World3D> world;
246+
world.instantiate();
247+
sub_viewport_node->set_world_3d(world);
248+
249+
EditorNode::get_singleton()->add_child(sub_viewport_node);
250+
Ref<Environment> env;
251+
env.instantiate();
252+
env->set_background(Environment::BG_CLEAR_COLOR);
253+
254+
Ref<CameraAttributesPractical> camera_attributes;
255+
camera_attributes.instantiate();
256+
257+
Node3D *root = memnew(Node3D);
258+
root->set_name("Root");
259+
sub_viewport_node->add_child(root);
260+
261+
Camera3D *camera = memnew(Camera3D);
262+
camera->set_environment(env);
263+
camera->set_attributes(camera_attributes);
264+
camera->set_name("Camera3D");
265+
root->add_child(camera);
266+
camera->set_current(true);
267+
268+
camera->set_position(Vector3(0.0, 0.0, 3.0));
269+
270+
DirectionalLight3D *light = memnew(DirectionalLight3D);
271+
light->set_name("Light");
272+
DirectionalLight3D *light2 = memnew(DirectionalLight3D);
273+
light2->set_name("Light2");
274+
light2->set_color(Color(0.7, 0.7, 0.7, 1.0));
275+
276+
root->add_child(light);
277+
root->add_child(light2);
278+
279+
sub_viewport_node->add_child(p_scene);
280+
281+
// Calculate the camera and lighting position based on the size of the scene.
282+
Vector3 center = scene_aabb.get_center();
283+
float camera_size = scene_aabb.get_longest_axis_size();
284+
285+
const float cam_rot_x = -Math::PI / 4;
286+
const float cam_rot_y = -Math::PI / 4;
287+
288+
camera->set_orthogonal(camera_size * 2.0, 0.0001, camera_size * 2.0);
289+
290+
Transform3D xf;
291+
xf.basis = Basis(Vector3(0, 1, 0), cam_rot_y) * Basis(Vector3(1, 0, 0), cam_rot_x);
292+
xf.origin = center;
293+
xf.translate_local(0, 0, camera_size);
294+
295+
camera->set_transform(xf);
296+
297+
Transform3D xform;
298+
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math::PI / 6);
299+
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math::PI / 6) * xform.basis;
300+
301+
light->set_transform(xform * Transform3D().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0)));
302+
light2->set_transform(xform * Transform3D().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0)));
303+
304+
// Update the renderer to get the screenshot.
305+
DisplayServer::get_singleton()->process_events();
306+
Main::iteration();
307+
Main::iteration();
308+
309+
// Get the texture.
310+
Ref<Texture2D> texture = sub_viewport_node->get_texture();
311+
ERR_FAIL_COND_MSG(texture.is_null(), "Failed to get texture from sub_viewport_node.");
312+
313+
// Remove the initial scene node.
314+
sub_viewport_node->remove_child(p_scene);
315+
316+
// Cleanup the viewport.
317+
if (sub_viewport_node) {
318+
if (sub_viewport_node->get_parent()) {
319+
sub_viewport_node->get_parent()->remove_child(sub_viewport_node);
320+
}
321+
sub_viewport_node->queue_free();
322+
sub_viewport_node = nullptr;
323+
}
324+
325+
// Now generate the cache image.
326+
Ref<Image> img = texture->get_image();
327+
if (img.is_valid() && img->get_width() > 0 && img->get_height() > 0) {
328+
img = img->duplicate();
329+
330+
int preview_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
331+
preview_size *= EDSCALE;
332+
333+
int vp_size = MIN(img->get_width(), img->get_height());
334+
int x = (img->get_width() - vp_size) / 2;
335+
int y = (img->get_height() - vp_size) / 2;
336+
337+
if (vp_size < preview_size) {
338+
img->crop_from_point(x, y, vp_size, vp_size);
339+
} else {
340+
int ratio = vp_size / preview_size;
341+
int size = preview_size * MAX(1, ratio / 2);
342+
343+
x = (img->get_width() - size) / 2;
344+
y = (img->get_height() - size) / 2;
345+
346+
img->crop_from_point(x, y, size, size);
347+
img->resize(preview_size, preview_size, Image::INTERPOLATE_LANCZOS);
348+
}
349+
img->convert(Image::FORMAT_RGB8);
350+
351+
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
352+
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
353+
cache_base = temp_path.path_join("resthumb-" + cache_base);
354+
355+
post_process_preview(img);
356+
img->save_png(cache_base + ".png");
357+
}
358+
359+
EditorResourcePreview::get_singleton()->check_for_invalidation(p_path);
360+
EditorFileSystem::get_singleton()->emit_signal(SNAME("filesystem_changed"));
361+
}
362+
208363
void EditorInterface::set_plugin_enabled(const String &p_plugin, bool p_enabled) {
209364
EditorNode::get_singleton()->set_addon_plugin_enabled(p_plugin, p_enabled, true);
210365
}

editor/editor_interface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ class EditorInterface : public Object {
7979
void _call_dialog_callback(const Callable &p_callback, const Variant &p_selected, const String &p_context);
8080

8181
// Editor tools.
82+
8283
TypedArray<Texture2D> _make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size);
84+
AABB _calculate_aabb_for_scene(Node *p_node, AABB &p_scene_aabb);
8385

8486
protected:
8587
static void _bind_methods();
@@ -108,6 +110,7 @@ class EditorInterface : public Object {
108110
EditorUndoRedoManager *get_editor_undo_redo() const;
109111

110112
Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size);
113+
void make_scene_preview(const String &p_path, Node *p_scene, int p_preview_size);
111114

112115
void set_plugin_enabled(const String &p_plugin, bool p_enabled);
113116
bool is_plugin_enabled(const String &p_plugin) const;

0 commit comments

Comments
 (0)