summaryrefslogtreecommitdiff
path: root/editor/editor_resource_preview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/editor_resource_preview.cpp')
-rw-r--r--editor/editor_resource_preview.cpp277
1 files changed, 153 insertions, 124 deletions
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 77288be614..2bc92427e5 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,31 +31,35 @@
#include "editor_resource_preview.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/message_queue.h"
-#include "core/os/file_access.h"
-#include "editor_node.h"
-#include "editor_scale.h"
-#include "editor_settings.h"
+#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
bool EditorResourcePreviewGenerator::handles(const String &p_type) const {
- if (get_script_instance() && get_script_instance()->has_method("handles")) {
- return get_script_instance()->call("handles", p_type);
+ bool success;
+ if (GDVIRTUAL_CALL(_handles, p_type, success)) {
+ return success;
}
- ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::handles needs to be overridden.");
+ ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::_handles needs to be overridden.");
}
Ref<Texture2D> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 &p_size) const {
- if (get_script_instance() && get_script_instance()->has_method("generate")) {
- return get_script_instance()->call("generate", p_from, p_size);
+ Ref<Texture2D> preview;
+ if (GDVIRTUAL_CALL(_generate, p_from, p_size, preview)) {
+ return preview;
}
- ERR_FAIL_V_MSG(Ref<Texture2D>(), "EditorResourcePreviewGenerator::generate needs to be overridden.");
+ ERR_FAIL_V_MSG(Ref<Texture2D>(), "EditorResourcePreviewGenerator::_generate needs to be overridden.");
}
Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 &p_size) const {
- if (get_script_instance() && get_script_instance()->has_method("generate_from_path")) {
- return get_script_instance()->call("generate_from_path", p_path, p_size);
+ Ref<Texture2D> preview;
+ if (GDVIRTUAL_CALL(_generate_from_path, p_path, p_size, preview)) {
+ return preview;
}
RES res = ResourceLoader::load(p_path);
@@ -66,27 +70,29 @@ Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String &
}
bool EditorResourcePreviewGenerator::generate_small_preview_automatically() const {
- if (get_script_instance() && get_script_instance()->has_method("generate_small_preview_automatically")) {
- return get_script_instance()->call("generate_small_preview_automatically");
+ bool success;
+ if (GDVIRTUAL_CALL(_generate_small_preview_automatically, success)) {
+ return success;
}
return false;
}
bool EditorResourcePreviewGenerator::can_generate_small_preview() const {
- if (get_script_instance() && get_script_instance()->has_method("can_generate_small_preview")) {
- return get_script_instance()->call("can_generate_small_preview");
+ bool success;
+ if (GDVIRTUAL_CALL(_can_generate_small_preview, success)) {
+ return success;
}
return false;
}
void EditorResourcePreviewGenerator::_bind_methods() {
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::STRING, "type")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture2D), "generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture2D), "generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "generate_small_preview_automatically"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "can_generate_small_preview"));
+ GDVIRTUAL_BIND(_handles, "type");
+ GDVIRTUAL_BIND(_generate, "resource", "size");
+ GDVIRTUAL_BIND(_generate_from_path, "path", "size");
+ GDVIRTUAL_BIND(_generate_small_preview_automatically);
+ GDVIRTUAL_BIND(_can_generate_small_preview);
}
EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
@@ -136,7 +142,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
type = ResourceLoader::get_resource_type(p_item.path);
}
- if (type == "") {
+ if (type.is_empty()) {
r_texture = Ref<ImageTexture>();
r_small_texture = Ref<ImageTexture>();
return; //could not guess type
@@ -161,7 +167,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
r_texture = generated;
- int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_theme_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size
+ int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_theme_icon(SNAME("Object"), SNAME("EditorIcons"))->get_width(); // Kind of a workaround to retrieve the default icon size
if (preview_generators[i]->can_generate_small_preview()) {
Ref<Texture2D> generated_small;
@@ -174,10 +180,10 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
if (!r_small_texture.is_valid() && r_texture.is_valid() && preview_generators[i]->generate_small_preview_automatically()) {
- Ref<Image> small_image = r_texture->get_data();
+ Ref<Image> small_image = r_texture->get_image();
small_image = small_image->duplicate();
small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC);
- r_small_texture.instance();
+ r_small_texture.instantiate();
r_small_texture->create_from_image(small_image);
}
@@ -205,126 +211,130 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
}
-void EditorResourcePreview::_thread() {
- exited.clear();
- while (!exit.is_set()) {
- preview_sem.wait();
- preview_mutex.lock();
-
- if (queue.size()) {
- QueueItem item = queue.front()->get();
- queue.pop_front();
-
- if (cache.has(item.path)) {
- //already has it because someone loaded it, just let it know it's ready
- String path = item.path;
- if (item.resource.is_valid()) {
- path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
- }
+void EditorResourcePreview::_iterate() {
+ preview_mutex.lock();
- _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
+ if (queue.size()) {
+ QueueItem item = queue.front()->get();
+ queue.pop_front();
- preview_mutex.unlock();
- } else {
- preview_mutex.unlock();
+ if (cache.has(item.path)) {
+ //already has it because someone loaded it, just let it know it's ready
+ String path = item.path;
+ if (item.resource.is_valid()) {
+ path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
+ }
- Ref<ImageTexture> texture;
- Ref<ImageTexture> small_texture;
+ _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
+ preview_mutex.unlock();
+ } else {
+ preview_mutex.unlock();
- if (item.resource.is_valid()) {
- _generate_preview(texture, small_texture, item, String());
+ Ref<ImageTexture> texture;
+ Ref<ImageTexture> small_texture;
- //adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
- _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
- } else {
- String temp_path = EditorSettings::get_singleton()->get_cache_dir();
- String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ if (item.resource.is_valid()) {
+ _generate_preview(texture, small_texture, item, String());
- //does not have it, try to load a cached thumbnail
+ //adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
+ _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
- String file = cache_base + ".txt";
- FileAccess *f = FileAccess::open(file, FileAccess::READ);
- if (!f) {
- // No cache found, generate
- _generate_preview(texture, small_texture, item, cache_base);
- } else {
- uint64_t modtime = FileAccess::get_modified_time(item.path);
- int tsize = f->get_line().to_int();
- bool has_small_texture = f->get_line().to_int();
- uint64_t last_modtime = f->get_line().to_int();
+ } else {
+ String temp_path = EditorPaths::get_singleton()->get_cache_dir();
+ String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
+ cache_base = temp_path.plus_file("resthumb-" + cache_base);
- bool cache_valid = true;
+ //does not have it, try to load a cached thumbnail
- if (tsize != thumbnail_size) {
+ String file = cache_base + ".txt";
+ FileAccess *f = FileAccess::open(file, FileAccess::READ);
+ if (!f) {
+ // No cache found, generate
+ _generate_preview(texture, small_texture, item, cache_base);
+ } else {
+ uint64_t modtime = FileAccess::get_modified_time(item.path);
+ int tsize = f->get_line().to_int();
+ bool has_small_texture = f->get_line().to_int();
+ uint64_t last_modtime = f->get_line().to_int();
+
+ bool cache_valid = true;
+
+ if (tsize != thumbnail_size) {
+ cache_valid = false;
+ memdelete(f);
+ } else if (last_modtime != modtime) {
+ String last_md5 = f->get_line();
+ String md5 = FileAccess::get_md5(item.path);
+ memdelete(f);
+
+ if (last_md5 != md5) {
cache_valid = false;
- memdelete(f);
- } else if (last_modtime != modtime) {
- String last_md5 = f->get_line();
- String md5 = FileAccess::get_md5(item.path);
- memdelete(f);
- if (last_md5 != md5) {
- cache_valid = false;
+ } else {
+ //update modified time
+ f = FileAccess::open(file, FileAccess::WRITE);
+ if (!f) {
+ // Not returning as this would leave the thread hanging and would require
+ // some proper cleanup/disabling of resource preview generation.
+ ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
} else {
- //update modified time
-
- f = FileAccess::open(file, FileAccess::WRITE);
- if (!f) {
- // Not returning as this would leave the thread hanging and would require
- // some proper cleanup/disabling of resource preview generation.
- ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
- } else {
- f->store_line(itos(thumbnail_size));
- f->store_line(itos(has_small_texture));
- f->store_line(itos(modtime));
- f->store_line(md5);
- memdelete(f);
- }
+ f->store_line(itos(thumbnail_size));
+ f->store_line(itos(has_small_texture));
+ f->store_line(itos(modtime));
+ f->store_line(md5);
+ memdelete(f);
}
- } else {
- memdelete(f);
}
+ } else {
+ memdelete(f);
+ }
- if (cache_valid) {
- Ref<Image> img;
- img.instance();
- Ref<Image> small_img;
- small_img.instance();
+ if (cache_valid) {
+ Ref<Image> img;
+ img.instantiate();
+ Ref<Image> small_img;
+ small_img.instantiate();
- if (img->load(cache_base + ".png") != OK) {
- cache_valid = false;
- } else {
- texture.instance();
- texture->create_from_image(img);
-
- if (has_small_texture) {
- if (small_img->load(cache_base + "_small.png") != OK) {
- cache_valid = false;
- } else {
- small_texture.instance();
- small_texture->create_from_image(small_img);
- }
+ if (img->load(cache_base + ".png") != OK) {
+ cache_valid = false;
+ } else {
+ texture.instantiate();
+ texture->create_from_image(img);
+
+ if (has_small_texture) {
+ if (small_img->load(cache_base + "_small.png") != OK) {
+ cache_valid = false;
+ } else {
+ small_texture.instantiate();
+ small_texture->create_from_image(small_img);
}
}
}
+ }
- if (!cache_valid) {
- _generate_preview(texture, small_texture, item, cache_base);
- }
+ if (!cache_valid) {
+ _generate_preview(texture, small_texture, item, cache_base);
}
- _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
+ _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
-
- } else {
- preview_mutex.unlock();
}
+
+ } else {
+ preview_mutex.unlock();
+ }
+}
+
+void EditorResourcePreview::_thread() {
+ exited.clear();
+ while (!exit.is_set()) {
+ preview_sem.wait();
+ _iterate();
}
exited.set();
}
@@ -419,13 +429,17 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
}
if (call_invalidated) { //do outside mutex
- call_deferred("emit_signal", "preview_invalidated", p_path);
+ call_deferred(SNAME("emit_signal"), "preview_invalidated", p_path);
}
}
void EditorResourcePreview::start() {
- ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
- thread.start(_thread_func, this);
+ if (OS::get_singleton()->get_render_main_thread_mode() == OS::RENDER_ANY_THREAD) {
+ ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
+ thread.start(_thread_func, this);
+ } else {
+ _mainthread_only = true;
+ }
}
void EditorResourcePreview::stop() {
@@ -434,7 +448,7 @@ void EditorResourcePreview::stop() {
preview_sem.post();
while (!exited.is_set()) {
OS::get_singleton()->delay_usec(10000);
- RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
+ RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on rendering server
}
thread.wait_to_finish();
}
@@ -448,3 +462,18 @@ EditorResourcePreview::EditorResourcePreview() {
EditorResourcePreview::~EditorResourcePreview() {
stop();
}
+
+void EditorResourcePreview::update() {
+ if (!_mainthread_only) {
+ return;
+ }
+
+ if (!exit.is_set()) {
+ // no need to even lock the mutex if the size is zero
+ // there is no problem if queue.size() is wrong, even if
+ // there was a race condition.
+ if (queue.size()) {
+ _iterate();
+ }
+ }
+}