mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Allow images to be imported "for editor use" and respect editor settings
This commit is contained in:
parent
6b92dbfce2
commit
817d4db21f
@ -52,6 +52,7 @@ public:
|
||||
enum LoaderFlags {
|
||||
FLAG_NONE = 0,
|
||||
FLAG_FORCE_LINEAR = 1,
|
||||
FLAG_CONVERT_COLORS = 2,
|
||||
};
|
||||
|
||||
virtual ~ImageFormatLoader() {}
|
||||
|
@ -108,6 +108,15 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (r_path_and_type.metadata && !r_path_and_type.path.is_empty()) {
|
||||
Dictionary metadata = r_path_and_type.metadata;
|
||||
if (metadata.has("has_editor_variant")) {
|
||||
r_path_and_type.path = r_path_and_type.path.get_basename() + ".editor." + r_path_and_type.path.get_extension();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (r_path_and_type.path.is_empty() || r_path_and_type.type.is_empty()) {
|
||||
return ERR_FILE_CORRUPT;
|
||||
}
|
||||
|
@ -3364,6 +3364,8 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
|
||||
Ref<Texture2D> icon = p_editor->get_icon();
|
||||
if (icon.is_valid()) {
|
||||
tb->set_icon(icon);
|
||||
// Make sure the control is updated if the icon is reimported.
|
||||
icon->connect("changed", callable_mp((Control *)tb, &Control::update_minimum_size));
|
||||
} else if (singleton->gui_base->has_theme_icon(p_editor->get_name(), SNAME("EditorIcons"))) {
|
||||
tb->set_icon(singleton->gui_base->get_theme_icon(p_editor->get_name(), SNAME("EditorIcons")));
|
||||
}
|
||||
|
@ -447,6 +447,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
// Colors
|
||||
bool dark_theme = EditorSettings::get_singleton()->is_dark_theme();
|
||||
|
||||
#ifdef MODULE_SVG_ENABLED
|
||||
if (dark_theme) {
|
||||
ImageLoaderSVG::set_forced_color_map(HashMap<Color, Color>());
|
||||
} else {
|
||||
ImageLoaderSVG::set_forced_color_map(EditorColorMap::get());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ensure base colors are in the 0..1 luminance range to avoid 8-bit integer overflow or text rendering issues.
|
||||
// Some places in the editor use 8-bit integer colors.
|
||||
const Color dark_color_1 = base_color.lerp(Color(0, 0, 0, 1), contrast).clamp();
|
||||
|
@ -36,6 +36,8 @@
|
||||
#include "core/version.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_scale.h"
|
||||
#include "editor/editor_settings.h"
|
||||
|
||||
void ResourceImporterTexture::_texture_reimport_roughness(const Ref<CompressedTexture2D> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) {
|
||||
ERR_FAIL_COND(p_tex.is_null());
|
||||
@ -233,6 +235,10 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo
|
||||
|
||||
if (p_path.get_extension() == "svg") {
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0));
|
||||
|
||||
// Editor use only, applies to SVG.
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "editor/scale_with_editor_scale"), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "editor/convert_colors_with_editor_theme"), false));
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,6 +453,14 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
scale = p_options["svg/scale"];
|
||||
}
|
||||
|
||||
// Editor-specific options.
|
||||
bool use_editor_scale = p_options.has("editor/scale_with_editor_scale") && p_options["editor/scale_with_editor_scale"];
|
||||
bool convert_editor_colors = p_options.has("editor/convert_colors_with_editor_theme") && p_options["editor/convert_colors_with_editor_theme"];
|
||||
|
||||
// Start importing images.
|
||||
List<Ref<Image>> images_imported;
|
||||
|
||||
// Load the normal image.
|
||||
Ref<Image> normal_image;
|
||||
Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R;
|
||||
if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) {
|
||||
@ -456,88 +470,117 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
}
|
||||
}
|
||||
|
||||
// Load the main image.
|
||||
Ref<Image> image;
|
||||
image.instantiate();
|
||||
Error err = ImageLoader::load_image(p_source_file, image, nullptr, loader_flags, scale);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
images_imported.push_back(image);
|
||||
|
||||
Array formats_imported;
|
||||
// Load the editor-only image.
|
||||
Ref<Image> editor_image;
|
||||
bool import_editor_image = use_editor_scale || convert_editor_colors;
|
||||
if (import_editor_image) {
|
||||
float editor_scale = scale;
|
||||
if (use_editor_scale) {
|
||||
editor_scale = scale * EDSCALE;
|
||||
}
|
||||
|
||||
if (size_limit > 0 && (image->get_width() > size_limit || image->get_height() > size_limit)) {
|
||||
//limit size
|
||||
if (image->get_width() >= image->get_height()) {
|
||||
int new_width = size_limit;
|
||||
int new_height = image->get_height() * new_width / image->get_width();
|
||||
int32_t editor_loader_flags = loader_flags;
|
||||
if (convert_editor_colors) {
|
||||
editor_loader_flags |= ImageFormatLoader::FLAG_CONVERT_COLORS;
|
||||
}
|
||||
|
||||
image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
|
||||
editor_image.instantiate();
|
||||
err = ImageLoader::load_image(p_source_file, editor_image, nullptr, editor_loader_flags, editor_scale);
|
||||
if (err != OK) {
|
||||
WARN_PRINT("Failed to import an image resource for editor use from '" + p_source_file + "'");
|
||||
} else {
|
||||
int new_height = size_limit;
|
||||
int new_width = image->get_width() * new_height / image->get_height();
|
||||
|
||||
image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
|
||||
}
|
||||
|
||||
if (normal == 1) {
|
||||
image->normalize();
|
||||
images_imported.push_back(editor_image);
|
||||
}
|
||||
}
|
||||
|
||||
if (fix_alpha_border) {
|
||||
image->fix_alpha_edges();
|
||||
}
|
||||
for (Ref<Image> &target_image : images_imported) {
|
||||
// Apply the size limit.
|
||||
if (size_limit > 0 && (target_image->get_width() > size_limit || target_image->get_height() > size_limit)) {
|
||||
if (target_image->get_width() >= target_image->get_height()) {
|
||||
int new_width = size_limit;
|
||||
int new_height = target_image->get_height() * new_width / target_image->get_width();
|
||||
|
||||
if (premult_alpha) {
|
||||
image->premultiply_alpha();
|
||||
}
|
||||
target_image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
|
||||
} else {
|
||||
int new_height = size_limit;
|
||||
int new_width = target_image->get_width() * new_height / target_image->get_height();
|
||||
|
||||
if (normal_map_invert_y) {
|
||||
// Inverting the green channel can be used to flip a normal map's direction.
|
||||
// There's no standard when it comes to normal map Y direction, so this is
|
||||
// sometimes needed when using a normal map exported from another program.
|
||||
// See <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates>.
|
||||
const int height = image->get_height();
|
||||
const int width = image->get_width();
|
||||
target_image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
|
||||
}
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
const Color color = image->get_pixel(i, j);
|
||||
image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b));
|
||||
if (normal == 1) {
|
||||
target_image->normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr_clamp_exposure) {
|
||||
// Clamp HDR exposure following Filament's tonemapping formula.
|
||||
// This can be used to reduce fireflies in environment maps or reduce the influence
|
||||
// of the sun from an HDRI panorama on environment lighting (when a DirectionalLight3D is used instead).
|
||||
const int height = image->get_height();
|
||||
const int width = image->get_width();
|
||||
// Fix alpha border.
|
||||
if (fix_alpha_border) {
|
||||
target_image->fix_alpha_edges();
|
||||
}
|
||||
|
||||
// These values are chosen arbitrarily and seem to produce good results with 4,096 samples.
|
||||
const float linear = 4096.0;
|
||||
const float compressed = 16384.0;
|
||||
// Premultiply the alpha.
|
||||
if (premult_alpha) {
|
||||
target_image->premultiply_alpha();
|
||||
}
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
const Color color = image->get_pixel(i, j);
|
||||
const float luma = color.get_luminance();
|
||||
// Invert the green channel of the image to flip the normal map it contains.
|
||||
if (normal_map_invert_y) {
|
||||
// Inverting the green channel can be used to flip a normal map's direction.
|
||||
// There's no standard when it comes to normal map Y direction, so this is
|
||||
// sometimes needed when using a normal map exported from another program.
|
||||
// See <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates>.
|
||||
const int height = target_image->get_height();
|
||||
const int width = target_image->get_width();
|
||||
|
||||
Color clamped_color;
|
||||
if (luma <= linear) {
|
||||
clamped_color = color;
|
||||
} else {
|
||||
clamped_color = (color / luma) * ((linear * linear - compressed * luma) / (2 * linear - compressed - luma));
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
const Color color = target_image->get_pixel(i, j);
|
||||
target_image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
image->set_pixel(i, j, clamped_color);
|
||||
// Clamp HDR exposure.
|
||||
if (hdr_clamp_exposure) {
|
||||
// Clamp HDR exposure following Filament's tonemapping formula.
|
||||
// This can be used to reduce fireflies in environment maps or reduce the influence
|
||||
// of the sun from an HDRI panorama on environment lighting (when a DirectionalLight3D is used instead).
|
||||
const int height = target_image->get_height();
|
||||
const int width = target_image->get_width();
|
||||
|
||||
// These values are chosen arbitrarily and seem to produce good results with 4,096 samples.
|
||||
const float linear = 4096.0;
|
||||
const float compressed = 16384.0;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
const Color color = target_image->get_pixel(i, j);
|
||||
const float luma = color.get_luminance();
|
||||
|
||||
Color clamped_color;
|
||||
if (luma <= linear) {
|
||||
clamped_color = color;
|
||||
} else {
|
||||
clamped_color = (color / luma) * ((linear * linear - compressed * luma) / (2 * linear - compressed - luma));
|
||||
}
|
||||
|
||||
target_image->set_pixel(i, j, clamped_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
|
||||
//basis universal does not support float formats, fall back
|
||||
// Basis universal does not support float formats, fallback.
|
||||
compress_mode = COMPRESS_VRAM_COMPRESSED;
|
||||
}
|
||||
|
||||
@ -547,9 +590,11 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
bool force_normal = normal == 1;
|
||||
bool srgb_friendly_pack = pack_channels == 0;
|
||||
|
||||
Array formats_imported;
|
||||
|
||||
if (compress_mode == COMPRESS_VRAM_COMPRESSED) {
|
||||
//must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
|
||||
//Android, GLES 2.x
|
||||
// Must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
|
||||
// Android, GLES 2.x
|
||||
|
||||
const bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
|
||||
bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565);
|
||||
@ -557,7 +602,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
const bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc");
|
||||
|
||||
if (can_bptc) {
|
||||
//add to the list anyway
|
||||
// Add to the list anyway.
|
||||
formats_imported.push_back("bptc");
|
||||
}
|
||||
|
||||
@ -566,9 +611,9 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
|
||||
if (is_hdr && can_compress_hdr) {
|
||||
if (has_alpha) {
|
||||
//can compress hdr, but hdr with alpha is not compressible
|
||||
// Can compress HDR, but HDR with alpha is not compressible.
|
||||
if (hdr_compression == 2) {
|
||||
//but user selected to compress hdr anyway, so force an alpha-less format.
|
||||
// But user selected to compress HDR anyway, so force an alpha-less format.
|
||||
if (image->get_format() == Image::FORMAT_RGBAF) {
|
||||
image->convert(Image::FORMAT_RGBF);
|
||||
} else if (image->get_format() == Image::FORMAT_RGBAH) {
|
||||
@ -580,7 +625,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
}
|
||||
|
||||
if (!can_compress_hdr) {
|
||||
//fallback to RGBE99995
|
||||
// Fallback to RGBE99995.
|
||||
if (image->get_format() != Image::FORMAT_RGBE9995) {
|
||||
image->convert(Image::FORMAT_RGBE9995);
|
||||
}
|
||||
@ -615,16 +660,31 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
EditorNode::add_io_error(vformat(TTR("%s: No suitable desktop VRAM compression algorithm enabled in Project Settings (S3TC or BPTC). This texture may not display correctly on desktop platforms."), p_source_file));
|
||||
}
|
||||
} else {
|
||||
//import normally
|
||||
// Import normally.
|
||||
_save_ctex(image, p_save_path + ".ctex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel);
|
||||
}
|
||||
|
||||
if (editor_image.is_valid()) {
|
||||
_save_ctex(editor_image, p_save_path + ".editor.ctex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel);
|
||||
}
|
||||
|
||||
if (r_metadata) {
|
||||
Dictionary metadata;
|
||||
metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
|
||||
if (formats_imported.size()) {
|
||||
metadata["imported_formats"] = formats_imported;
|
||||
}
|
||||
|
||||
if (editor_image.is_valid()) {
|
||||
metadata["has_editor_variant"] = true;
|
||||
if (use_editor_scale) {
|
||||
metadata["editor_scale"] = EDSCALE;
|
||||
}
|
||||
if (convert_editor_colors) {
|
||||
metadata["editor_dark_theme"] = EditorSettings::get_singleton()->is_dark_theme();
|
||||
}
|
||||
}
|
||||
|
||||
*r_metadata = metadata;
|
||||
}
|
||||
return OK;
|
||||
@ -657,13 +717,22 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co
|
||||
//will become invalid if formats are missing to import
|
||||
Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
|
||||
|
||||
if (metadata.has("has_editor_variant")) {
|
||||
if (metadata.has("editor_scale") && (float)metadata["editor_scale"] != EDSCALE) {
|
||||
return false;
|
||||
}
|
||||
if (metadata.has("editor_dark_theme") && (bool)metadata["editor_dark_theme"] != EditorSettings::get_singleton()->is_dark_theme()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata.has("vram_texture")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vram = metadata["vram_texture"];
|
||||
if (!vram) {
|
||||
return true; //do not care about non vram
|
||||
return true; // Do not care about non-VRAM.
|
||||
}
|
||||
|
||||
Vector<String> formats_imported;
|
||||
|
@ -35,6 +35,12 @@
|
||||
|
||||
#include <thorvg.h>
|
||||
|
||||
HashMap<Color, Color> ImageLoaderSVG::forced_color_map = HashMap<Color, Color>();
|
||||
|
||||
void ImageLoaderSVG::set_forced_color_map(const HashMap<Color, Color> &p_color_map) {
|
||||
forced_color_map = p_color_map;
|
||||
}
|
||||
|
||||
void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string) {
|
||||
// Replace colors in the SVG based on what is passed in `p_color_map`.
|
||||
// Used to change the colors of editor icons based on the used theme.
|
||||
@ -138,7 +144,13 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const
|
||||
|
||||
Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) {
|
||||
String svg = p_fileaccess->get_as_utf8_string();
|
||||
create_image_from_string(p_image, svg, p_scale, false, HashMap<Color, Color>());
|
||||
|
||||
if (p_flags & FLAG_CONVERT_COLORS) {
|
||||
create_image_from_string(p_image, svg, p_scale, false, forced_color_map);
|
||||
} else {
|
||||
create_image_from_string(p_image, svg, p_scale, false, HashMap<Color, Color>());
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(p_image->is_empty(), FAILED);
|
||||
if (p_flags & FLAG_FORCE_LINEAR) {
|
||||
p_image->srgb_to_linear();
|
||||
|
@ -34,9 +34,13 @@
|
||||
#include "core/io/image_loader.h"
|
||||
|
||||
class ImageLoaderSVG : public ImageFormatLoader {
|
||||
static HashMap<Color, Color> forced_color_map;
|
||||
|
||||
void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string);
|
||||
|
||||
public:
|
||||
static void set_forced_color_map(const HashMap<Color, Color> &p_color_map);
|
||||
|
||||
void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
|
||||
|
||||
virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) override;
|
||||
|
Loading…
Reference in New Issue
Block a user