Skip to content

Commit 7a800a9

Browse files
committed
Implement EditorTextureImportPlugin to extends texture importer
1 parent 215acd5 commit 7a800a9

File tree

7 files changed

+311
-3
lines changed

7 files changed

+311
-3
lines changed

doc/classes/EditorPlugin.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,15 @@
544544
If [param first_priority] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
545545
</description>
546546
</method>
547+
<method name="add_texture_import_plugin">
548+
<return type="void" />
549+
<param index="0" name="importer" type="EditorTextureImportPlugin" />
550+
<param index="1" name="first_priority" type="bool" default="false" />
551+
<description>
552+
Add a [EditorTextureImportPlugin]. These plugins allow customizing the import process of [CompressedTexture2D].
553+
If [param first_priority] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
554+
</description>
555+
</method>
547556
<method name="add_tool_menu_item">
548557
<return type="void" />
549558
<param index="0" name="name" type="String" />
@@ -732,6 +741,13 @@
732741
Remove the [EditorScenePostImportPlugin], added with [method add_scene_post_import_plugin].
733742
</description>
734743
</method>
744+
<method name="remove_texture_import_plugin">
745+
<return type="void" />
746+
<param index="0" name="importer" type="EditorTextureImportPlugin" />
747+
<description>
748+
Remove the [EditorTextureImportPlugin], added with [method add_texture_import_plugin].
749+
</description>
750+
</method>
735751
<method name="remove_tool_menu_item">
736752
<return type="void" />
737753
<param index="0" name="name" type="String" />
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="EditorTextureImportPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
3+
<brief_description>
4+
Plugin to control and modify the process of importing a [CompressedTexture2D].
5+
</brief_description>
6+
<description>
7+
This plugin type exists to extend [ResourceImporterTexture] and modify the process of importing [CompressedTexture2D], allowing to load custom file format, add import options, and change the image when processing.
8+
</description>
9+
<tutorials>
10+
</tutorials>
11+
<methods>
12+
<method name="_get_import_options" qualifiers="virtual const">
13+
<return type="void" />
14+
<param index="0" name="path" type="String" />
15+
<param index="1" name="preset_index" type="int" />
16+
<description>
17+
Override to add import options. These will appear in the Texture2D import dock on the editor. Add options via [method add_import_option] and [method add_import_option_advanced].
18+
</description>
19+
</method>
20+
<method name="_get_option_visibility" qualifiers="virtual const">
21+
<return type="Variant" />
22+
<param index="0" name="path" type="String" />
23+
<param index="1" name="option" type="String" />
24+
<description>
25+
Override to change the visibility of import option. Should return [code]true[/code] to show the given option, [code]false[/code] to hide the given option, or [code]null[/code] to ignore.
26+
</description>
27+
</method>
28+
<method name="_get_recognized_extensions" qualifiers="virtual const">
29+
<return type="PackedStringArray" />
30+
<description>
31+
Gets the file extensions that will be added to the recognized extensions list of texture importer.
32+
</description>
33+
</method>
34+
<method name="_load_image" qualifiers="virtual const">
35+
<return type="int" enum="Error" />
36+
<param index="0" name="image" type="Image" />
37+
<description>
38+
Override to add import options. These will appear in the Texture2D import dock on the editor. Add options via [method add_import_option] and [method add_import_option_advanced].
39+
</description>
40+
</method>
41+
<method name="_post_process" qualifiers="virtual const">
42+
<return type="Image" />
43+
<param index="0" name="image" type="Image" />
44+
<description>
45+
Post process the image. This function is called after the image has been processed, such as fix alpha border, apply size limit. See also [ResourceImporterTexture].
46+
</description>
47+
</method>
48+
<method name="_pre_process" qualifiers="virtual const">
49+
<return type="Image" />
50+
<param index="0" name="image" type="Image" />
51+
<description>
52+
Pre Process the image. This function is called right after the image loader loaded the image and no changes have been made.
53+
</description>
54+
</method>
55+
<method name="add_import_option">
56+
<return type="void" />
57+
<param index="0" name="name" type="String" />
58+
<param index="1" name="value" type="Variant" />
59+
<description>
60+
Add a specific import option (name and default value only). This function can only be called from [method _get_import_options].
61+
</description>
62+
</method>
63+
<method name="add_import_option_advanced">
64+
<return type="void" />
65+
<param index="0" name="type" type="int" enum="Variant.Type" />
66+
<param index="1" name="name" type="String" />
67+
<param index="2" name="default_value" type="Variant" />
68+
<param index="3" name="hint" type="int" enum="PropertyHint" default="0" />
69+
<param index="4" name="hint_string" type="String" default="&quot;&quot;" />
70+
<param index="5" name="usage_flags" type="int" default="6" />
71+
<description>
72+
Add a specific import option. This function can only be called from [method _get_import_options].
73+
</description>
74+
</method>
75+
<method name="get_option_value" qualifiers="const">
76+
<return type="Variant" />
77+
<param index="0" name="name" type="StringName" />
78+
<description>
79+
Query the value of an option. This function can only be called from [method _get_option_visibility], [method _load_image], [method _pre_process] and [method _post_process].
80+
</description>
81+
</method>
82+
</methods>
83+
<constants>
84+
<constant name="PRESET_DETECT" value="0" enum="Preset">
85+
The 2D/3D (Auto-Detect) preset of texture importer. Can be accessed in [method _get_import_options].
86+
</constant>
87+
<constant name="PRESET_2D" value="1" enum="Preset">
88+
The 2D preset of texture importer. Can be accessed in [method _get_import_options].
89+
</constant>
90+
<constant name="PRESET_3D" value="2" enum="Preset">
91+
The 3D preset of texture importer. Can be accessed in [method _get_import_options].
92+
</constant>
93+
</constants>
94+
</class>

editor/import/resource_importer_texture.cpp

Lines changed: 139 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,90 @@
4141
#include "editor/themes/editor_theme_manager.h"
4242
#include "scene/resources/compressed_texture.h"
4343

44+
Variant EditorTextureImportPlugin::get_option_value(const StringName &p_name) const {
45+
ERR_FAIL_COND_V_MSG(current_options == nullptr, Variant(), "get_option_value() called from a function where option values are not available.");
46+
ERR_FAIL_COND_V_MSG(!current_options->has(p_name), Variant(), "get_option_value() called with unexisting option argument: " + String(p_name));
47+
return (*current_options)[p_name];
48+
}
49+
50+
void EditorTextureImportPlugin::add_import_option(const String &p_name, const Variant &p_default_value) {
51+
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option() can only be called from get_import_options().");
52+
add_import_option_advanced(p_default_value.get_type(), p_name, p_default_value);
53+
}
54+
55+
void EditorTextureImportPlugin::add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) {
56+
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option_advanced() can only be called from get_import_options().");
57+
current_option_list->push_back(ResourceImporter::ImportOption(PropertyInfo(p_type, p_name, p_hint, p_hint_string, p_usage_flags), p_default_value));
58+
}
59+
60+
void EditorTextureImportPlugin::get_recognized_extensions(List<String> *p_extensions) const {
61+
Vector<String> extensions;
62+
GDVIRTUAL_CALL(_get_recognized_extensions, extensions);
63+
for (int i = 0; i < extensions.size(); i++) {
64+
p_extensions->push_back(extensions[i]);
65+
}
66+
}
67+
68+
void EditorTextureImportPlugin::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options, Preset p_preset) const {
69+
current_option_list = r_options;
70+
GDVIRTUAL_CALL(_get_import_options, p_path, p_preset);
71+
current_option_list = nullptr;
72+
}
73+
74+
Variant EditorTextureImportPlugin::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
75+
current_options = &p_options;
76+
Variant ret;
77+
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_option, ret);
78+
current_options = nullptr;
79+
return ret;
80+
}
81+
82+
Error EditorTextureImportPlugin::load_image(Ref<Image> p_image, bool *r_use_custom_loader, const HashMap<StringName, Variant> &p_options) const {
83+
Error err = OK;
84+
current_options = &p_options;
85+
bool custom_loader = GDVIRTUAL_CALL(_load_image, p_image, err);
86+
current_options = nullptr;
87+
if (r_use_custom_loader) {
88+
*r_use_custom_loader = custom_loader;
89+
}
90+
return err;
91+
}
92+
93+
Ref<Image> EditorTextureImportPlugin::pre_process(Ref<Image> p_image, const HashMap<StringName, Variant> &p_options) const {
94+
Ref<Image> image = p_image;
95+
current_options = &p_options;
96+
GDVIRTUAL_CALL(_pre_process, p_image, image);
97+
current_options = nullptr;
98+
return image;
99+
}
100+
101+
Ref<Image> EditorTextureImportPlugin::post_process(Ref<Image> p_image, const HashMap<StringName, Variant> &p_options) const {
102+
Ref<Image> image = p_image;
103+
current_options = &p_options;
104+
GDVIRTUAL_CALL(_post_process, p_image, image);
105+
current_options = nullptr;
106+
return image;
107+
}
108+
109+
void EditorTextureImportPlugin::_bind_methods() {
110+
ClassDB::bind_method(D_METHOD("get_option_value", "name"), &EditorTextureImportPlugin::get_option_value);
111+
ClassDB::bind_method(D_METHOD("add_import_option", "name", "value"), &EditorTextureImportPlugin::add_import_option);
112+
ClassDB::bind_method(D_METHOD("add_import_option_advanced", "type", "name", "default_value", "hint", "hint_string", "usage_flags"), &EditorTextureImportPlugin::add_import_option_advanced, DEFVAL(PROPERTY_HINT_NONE), DEFVAL(""), DEFVAL(PROPERTY_USAGE_DEFAULT));
113+
114+
BIND_ENUM_CONSTANT(PRESET_DETECT);
115+
BIND_ENUM_CONSTANT(PRESET_2D);
116+
BIND_ENUM_CONSTANT(PRESET_3D);
117+
118+
GDVIRTUAL_BIND(_get_recognized_extensions);
119+
GDVIRTUAL_BIND(_get_import_options, "path", "preset_index");
120+
GDVIRTUAL_BIND(_get_option_visibility, "path", "option");
121+
GDVIRTUAL_BIND(_load_image, "image");
122+
GDVIRTUAL_BIND(_pre_process, "image");
123+
GDVIRTUAL_BIND(_post_process, "image");
124+
}
125+
126+
///////////////////////////////////////////////////////
127+
44128
void ResourceImporterTexture::_texture_reimport_roughness(const Ref<CompressedTexture2D> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) {
45129
ERR_FAIL_COND(p_tex.is_null());
46130

@@ -170,6 +254,9 @@ String ResourceImporterTexture::get_visible_name() const {
170254

171255
void ResourceImporterTexture::get_recognized_extensions(List<String> *p_extensions) const {
172256
ImageLoader::get_recognized_extensions(p_extensions);
257+
for (const Ref<EditorTextureImportPlugin> &plugin : texture_import_plugins) {
258+
plugin->get_recognized_extensions(p_extensions);
259+
}
173260
}
174261

175262
String ResourceImporterTexture::get_save_extension() const {
@@ -209,6 +296,13 @@ bool ResourceImporterTexture::get_option_visibility(const String &p_path, const
209296
return p_options["mipmaps/generate"];
210297
}
211298

299+
for (const Ref<EditorTextureImportPlugin> &plugin : texture_import_plugins) {
300+
Variant ret = plugin->get_option_visibility(p_path, p_option, p_options);
301+
if (ret.get_type() == Variant::BOOL && !ret) {
302+
return false;
303+
}
304+
}
305+
212306
return true;
213307
}
214308

@@ -256,6 +350,10 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo
256350
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "editor/scale_with_editor_scale"), false));
257351
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "editor/convert_colors_with_editor_theme"), false));
258352
}
353+
354+
for (const Ref<EditorTextureImportPlugin> &plugin : texture_import_plugins) {
355+
plugin->get_import_options(p_path, r_options);
356+
}
259357
}
260358

261359
void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) {
@@ -338,6 +436,23 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I
338436
}
339437
}
340438

439+
void ResourceImporterTexture::add_texture_import_plugin(Ref<EditorTextureImportPlugin> p_plugin, bool p_first_priority) {
440+
ERR_FAIL_COND(p_plugin.is_null());
441+
if (p_first_priority) {
442+
texture_import_plugins.insert(0, p_plugin);
443+
} else {
444+
texture_import_plugins.push_back(p_plugin);
445+
}
446+
}
447+
448+
void ResourceImporterTexture::remove_texture_import_plugin(Ref<EditorTextureImportPlugin> p_importer) {
449+
texture_import_plugins.erase(p_importer);
450+
}
451+
452+
void ResourceImporterTexture::clean_up_importer_plugins() {
453+
texture_import_plugins.clear();
454+
}
455+
341456
void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) {
342457
Ref<FileAccess> f = FileAccess::open(p_to_path, FileAccess::WRITE);
343458
ERR_FAIL_COND(f.is_null());
@@ -559,10 +674,25 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
559674
// Load the main image.
560675
Ref<Image> image;
561676
image.instantiate();
562-
Error err = ImageLoader::load_image(p_source_file, image, nullptr, loader_flags, scale);
563-
if (err != OK) {
564-
return err;
677+
Error err = OK;
678+
bool use_custom_loader = false;
679+
680+
for (const Ref<EditorTextureImportPlugin> &plugin : texture_import_plugins) {
681+
err = plugin->load_image(image, &use_custom_loader, p_options);
682+
}
683+
ERR_FAIL_COND_V_MSG(image.is_null(), ERR_INVALID_DATA, "The returned image of _load_image() is null.");
684+
ERR_FAIL_COND_V(use_custom_loader && err != OK, err);
685+
686+
if (!use_custom_loader) {
687+
err = ImageLoader::load_image(p_source_file, image, nullptr, loader_flags, scale);
688+
ERR_FAIL_COND_V(err != OK, err);
565689
}
690+
691+
for (const Ref<EditorTextureImportPlugin> &plugin : texture_import_plugins) {
692+
image = plugin->pre_process(image, p_options);
693+
}
694+
ERR_FAIL_COND_V_MSG(image.is_null(), ERR_INVALID_DATA, "The returned image of _pre_process() is null.");
695+
566696
images_imported.push_back(image);
567697

568698
// Load the editor-only image.
@@ -636,6 +766,11 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
636766
}
637767
}
638768

769+
for (const Ref<EditorTextureImportPlugin> &plugin : texture_import_plugins) {
770+
image = plugin->post_process(image, p_options);
771+
}
772+
ERR_FAIL_COND_V_MSG(image.is_null(), ERR_INVALID_DATA, "The returned image of _post_process() is null.");
773+
639774
bool detect_3d = int(p_options["detect_3d/compress_to"]) > 0;
640775
bool detect_roughness = roughness == 0;
641776
bool detect_normal = normal == 0;
@@ -837,6 +972,7 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path, co
837972
}
838973

839974
ResourceImporterTexture *ResourceImporterTexture::singleton = nullptr;
975+
Vector<Ref<EditorTextureImportPlugin>> ResourceImporterTexture::texture_import_plugins;
840976

841977
ResourceImporterTexture::ResourceImporterTexture(bool p_singleton) {
842978
// This should only be set through the EditorNode.

editor/import/resource_importer_texture.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,50 @@
3737

3838
class CompressedTexture2D;
3939

40+
class EditorTextureImportPlugin : public RefCounted {
41+
GDCLASS(EditorTextureImportPlugin, RefCounted);
42+
43+
public:
44+
enum Preset {
45+
PRESET_DETECT,
46+
PRESET_2D,
47+
PRESET_3D,
48+
};
49+
50+
private:
51+
mutable const HashMap<StringName, Variant> *current_options = nullptr;
52+
mutable List<ResourceImporter::ImportOption> *current_option_list = nullptr;
53+
54+
protected:
55+
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
56+
GDVIRTUAL2C(_get_import_options, String, int)
57+
GDVIRTUAL2RC(Variant, _get_option_visibility, String, String)
58+
GDVIRTUAL1RC(Error, _load_image, Ref<Image>)
59+
GDVIRTUAL1RC(Ref<Image>, _pre_process, Ref<Image>)
60+
GDVIRTUAL1RC(Ref<Image>, _post_process, Ref<Image>)
61+
62+
static void _bind_methods();
63+
64+
public:
65+
Variant get_option_value(const StringName &p_name) const;
66+
void add_import_option(const String &p_name, const Variant &p_default_value);
67+
void add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT);
68+
69+
virtual void get_recognized_extensions(List<String> *p_extensions) const;
70+
virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options, Preset p_preset = PRESET_DETECT) const;
71+
virtual Variant get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const;
72+
73+
virtual Error load_image(Ref<Image> p_image, bool *r_use_custom_loader, const HashMap<StringName, Variant> &p_options) const;
74+
virtual Ref<Image> pre_process(Ref<Image> p_image, const HashMap<StringName, Variant> &p_options) const;
75+
virtual Ref<Image> post_process(Ref<Image> p_image, const HashMap<StringName, Variant> &p_options) const;
76+
};
77+
VARIANT_ENUM_CAST(EditorTextureImportPlugin::Preset);
78+
4079
class ResourceImporterTexture : public ResourceImporter {
4180
GDCLASS(ResourceImporterTexture, ResourceImporter);
4281

82+
static Vector<Ref<EditorTextureImportPlugin>> texture_import_plugins;
83+
4384
public:
4485
enum CompressMode {
4586
COMPRESS_LOSSLESS,
@@ -83,6 +124,11 @@ class ResourceImporterTexture : public ResourceImporter {
83124
static void save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality);
84125

85126
static ResourceImporterTexture *get_singleton() { return singleton; }
127+
128+
static void add_texture_import_plugin(Ref<EditorTextureImportPlugin> p_plugin, bool p_first_priority = false);
129+
static void remove_texture_import_plugin(Ref<EditorTextureImportPlugin> p_plugin);
130+
static void clean_up_importer_plugins();
131+
86132
virtual String get_importer_name() const override;
87133
virtual String get_visible_name() const override;
88134
virtual void get_recognized_extensions(List<String> *p_extensions) const override;

0 commit comments

Comments
 (0)