From af83d11dc636b46734c4d370e1268bd062deb7aa Mon Sep 17 00:00:00 2001 From: heppocogne <83043568+heppocogne@users.noreply.github.com> Date: Wed, 11 Jan 2023 14:32:57 +0900 Subject: [PATCH] Support compress svg file option (Internal update) SVGSprite no longer loads the same svg file multiple times --- addons/svg_sprite/plugin.cfg | 4 +-- addons/svg_sprite/plugin.gd | 46 +++++++++++++++++++++++++++-- cpp/src/gdlibrary.cpp | 3 ++ cpp/src/rawsvg_loader.cpp | 57 ++++++++++++++++++++++++++++++++++++ cpp/src/rawsvg_loader.h | 28 ++++++++++++++++++ cpp/src/svgsprite.cpp | 44 ++++++++++------------------ cpp/src/svgsprite.h | 3 +- project.godot | 4 +++ 8 files changed, 154 insertions(+), 35 deletions(-) create mode 100644 cpp/src/rawsvg_loader.cpp create mode 100644 cpp/src/rawsvg_loader.h diff --git a/addons/svg_sprite/plugin.cfg b/addons/svg_sprite/plugin.cfg index ec0338f..ed4b4e6 100644 --- a/addons/svg_sprite/plugin.cfg +++ b/addons/svg_sprite/plugin.cfg @@ -1,7 +1,7 @@ [plugin] name="SVGSprite" -description="" +description="Rasterize svg dynamically" author="heppocogne" -version="1.3.1" +version="1.3.2" script="plugin.gd" diff --git a/addons/svg_sprite/plugin.gd b/addons/svg_sprite/plugin.gd index 30ca16f..8458cb9 100644 --- a/addons/svg_sprite/plugin.gd +++ b/addons/svg_sprite/plugin.gd @@ -2,8 +2,10 @@ tool extends EditorPlugin const _rawsvg_root:="res://_rawsvg" +const compress_setting:="svgsprite/compress" var res_file_sys:EditorFileSystem var file_sys:FileSystemDock +var _compress_setting_cache:bool func _enter_tree(): @@ -13,13 +15,22 @@ func _enter_tree(): file_sys=get_editor_interface().get_file_system_dock() file_sys.connect("file_removed",self,"_on_file_removed") file_sys.connect("files_moved",self,"_on_files_moved") + ProjectSettings.connect("project_settings_changed",self,"_on_project_settings_changed") var dir:=Directory.new() if !dir.dir_exists(_rawsvg_root): dir.make_dir(_rawsvg_root) pick_svg_files("res://") - add_custom_type("SVGSprite","Node2D",preload("res://addons/svg_sprite/svgsprite_library.gdns"),preload("res://addons/svg_sprite/icon_svgsprite.svg")) + add_custom_type("SVGSprite", + "Node2D", + preload("res://addons/svg_sprite/svgsprite_library.gdns"), + preload("res://addons/svg_sprite/icon_svgsprite.svg")) + + if !ProjectSettings.has_setting(compress_setting): + ProjectSettings.set_setting(compress_setting,false) + + _compress_setting_cache=ProjectSettings.get_setting(compress_setting) func _exit_tree(): @@ -56,11 +67,25 @@ func get_rawsvg_path(path:String)->String: return _rawsvg_root.plus_file(path.get_file()+"-"+path.get_basename().sha256_text()+".rawsvg") +func get_rawsvgz_path(path:String)->String: + return _rawsvg_root.plus_file(path.get_file()+"-"+path.get_basename().sha256_text()+".rawsvgz") + + func _on_resources_reimported(paths:PoolStringArray): for path in paths: if path.ends_with(".svg"): - var d:=Directory.new() - d.copy(path,get_rawsvg_path(path)) + if ProjectSettings.get_setting(compress_setting): + var f:=File.new() + var svg:String + if f.open(path,File.READ)==OK: + svg=f.get_as_text() + f.close() + if f.open_compressed(get_rawsvgz_path(path),File.WRITE,File.COMPRESSION_DEFLATE)==OK: + f.store_string(svg) + f.close() + else: + var d:=Directory.new() + d.copy(path,get_rawsvg_path(path)) func _on_file_removed(path:String): @@ -73,3 +98,18 @@ func _on_files_moved(old_path:String,new_path:String): if old_path.ends_with(".svg"): var d:=Directory.new() d.rename(get_rawsvg_path(old_path),get_rawsvg_path(new_path)) + + +func _on_project_settings_changed(): + if _compress_setting_cache!=ProjectSettings.get_setting(compress_setting): + var dir:=Directory.new() + dir.change_dir(_rawsvg_root) + dir.list_dir_begin(true,true) + var item_name:=dir.get_next() + while item_name!="": + dir.remove(item_name) + item_name=dir.get_next() + dir.list_dir_end() + + pick_svg_files("res://") + _compress_setting_cache=ProjectSettings.get_setting(compress_setting) diff --git a/cpp/src/gdlibrary.cpp b/cpp/src/gdlibrary.cpp index adf748e..8e4785e 100644 --- a/cpp/src/gdlibrary.cpp +++ b/cpp/src/gdlibrary.cpp @@ -1,12 +1,15 @@ #include "svgsprite.h" +#include "rawsvg_loader.h" extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { godot::Godot::gdnative_init(o); + godot::RawSvgLoader::on_library_init(); } extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { + godot::RawSvgLoader::on_library_terminate(); godot::Godot::gdnative_terminate(o); } diff --git a/cpp/src/rawsvg_loader.cpp b/cpp/src/rawsvg_loader.cpp new file mode 100644 index 0000000..526a3c5 --- /dev/null +++ b/cpp/src/rawsvg_loader.cpp @@ -0,0 +1,57 @@ +#include "rawsvg_loader.h" +#include + +using namespace godot; + +RawSvgLoader *RawSvgLoader::singleton = nullptr; + +void RawSvgLoader::on_library_init() +{ + if (singleton != nullptr) + delete singleton; + singleton = new RawSvgLoader(); +} + +void RawSvgLoader::on_library_terminate() +{ + delete singleton; + singleton = nullptr; +} + +RawSvgLoader *RawSvgLoader::get_singleton() +{ + return singleton; +} + +RawSvgLoader::~RawSvgLoader() +{ + for (auto &pair : docs_cache) + docs_cache[pair.first] = nullptr; +} + +std::unique_ptr &RawSvgLoader::load(const String &path) +{ + if (docs_cache.count(path) == 0) + { + Ref ref_f = File::_new(); + Error err; + if (path.ends_with(".rawsvg")) + err = ref_f->open(path, File::READ); + else if (path.ends_with(".rawsvgz")) + err = ref_f->open_compressed(path, File::READ, File::COMPRESSION_DEFLATE); + + if (err == godot::Error::OK) + { + char *buf = ref_f->get_as_text().alloc_c_string(); + docs_cache[path] = lunasvg::Document::loadFromData(const_cast(buf)); + godot::api->godot_free(buf); + if (!docs_cache[path]) + { + Godot::print_error("invalid svg file:" + path, __func__, __FILE__, __LINE__); + docs_cache[path] = nullptr; + } + } + } + + return docs_cache[path]; +} \ No newline at end of file diff --git a/cpp/src/rawsvg_loader.h b/cpp/src/rawsvg_loader.h new file mode 100644 index 0000000..2aa7d3a --- /dev/null +++ b/cpp/src/rawsvg_loader.h @@ -0,0 +1,28 @@ +#ifndef RAWSVG_LOADER_H +#define RAWSVG_LOADER_H + +#include + +#include +#include +#include + +namespace godot +{ + class RawSvgLoader + { + static RawSvgLoader *singleton; + RawSvgLoader() {} + std::map> docs_cache; + + public: + static void on_library_init(); + static void on_library_terminate(); + static RawSvgLoader *get_singleton(); + ~RawSvgLoader(); + + std::unique_ptr &load(const String &path); + }; +}; + +#endif \ No newline at end of file diff --git a/cpp/src/svgsprite.cpp b/cpp/src/svgsprite.cpp index 60d1ae8..e9ab82b 100644 --- a/cpp/src/svgsprite.cpp +++ b/cpp/src/svgsprite.cpp @@ -4,7 +4,7 @@ #include #include #include -// #include +#include #include #ifndef EDITOR_FEATURE_DISABLED #include @@ -13,6 +13,7 @@ #include #include +#include "rawsvg_loader.h" using namespace godot; @@ -46,11 +47,10 @@ void SVGSprite::_register_methods() } SVGSprite::SVGSprite() : _cache_dirty(true), -#ifndef EDITOR_FEATURE_DISABLED + _svg_doc(nullptr), _ref_texture(ImageTexture::_new()), +#ifndef EDITOR_FEATURE_DISABLED _ref_prerasterized(nullptr) -#else - _ref_texture(ImageTexture::_new()) #endif { } @@ -181,36 +181,17 @@ void SVGSprite::_notification(int what) void SVGSprite::set_svg_file(String p_svg_file) { svg_file = p_svg_file; - - if (svg_file == "") - { #ifndef EDITOR_FEATURE_DISABLED + if (svg_file == "") _ref_prerasterized = nullptr; -#endif - _svg_doc = nullptr; - } else - { -#ifndef EDITOR_FEATURE_DISABLED _ref_prerasterized = ResourceLoader::get_singleton()->load(svg_file); -#endif - Ref ref_f = File::_new(); - const String rawsvg_file = get_rawsvg_path(svg_file); - if (ref_f->open(rawsvg_file, File::READ) == godot::Error::OK) - { - char *buf = ref_f->get_as_text().alloc_c_string(); - _svg_doc = lunasvg::Document::loadFromData(const_cast(buf)); - godot::api->godot_free(buf); - if (!_svg_doc) - Godot::print_error("invalid svg file:" + rawsvg_file, __func__, __FILE__, __LINE__); - } - else - { - _svg_doc = nullptr; - Godot::print_error(String("cannot open file (error code=") + Variant((int)ref_f->get_error()) + String("):") + rawsvg_file, __func__, __FILE__, __LINE__); - } - } + if ((bool)ProjectSettings::get_singleton()->get_setting("svgsprite/compress") == false) + _svg_doc = RawSvgLoader::get_singleton()->load(get_rawsvg_path(p_svg_file)).get(); + else + _svg_doc = RawSvgLoader::get_singleton()->load(get_rawsvgz_path(p_svg_file)).get(); _cache_dirty = true; +#endif update(); } @@ -257,3 +238,8 @@ String SVGSprite::get_rawsvg_path(String path) { return String(_rawsvg_root).plus_file(path.get_file() + "-" + path.get_basename().sha256_text() + ".rawsvg"); } + +String SVGSprite::get_rawsvgz_path(String path) +{ + return String(_rawsvg_root).plus_file(path.get_file() + "-" + path.get_basename().sha256_text() + ".rawsvgz"); +} diff --git a/cpp/src/svgsprite.h b/cpp/src/svgsprite.h index 237a2ab..e30ffd0 100644 --- a/cpp/src/svgsprite.h +++ b/cpp/src/svgsprite.h @@ -15,7 +15,7 @@ namespace godot { GODOT_CLASS(SVGSprite, Node2D) - std::unique_ptr _svg_doc; + lunasvg::Document *_svg_doc; // rotation and scaling Transform2D _transform; PoolByteArray _bitmap_byte_array; @@ -36,6 +36,7 @@ namespace godot static void _register_methods(); static String get_rawsvg_path(String path); + static String get_rawsvgz_path(String path); SVGSprite(); ~SVGSprite(); diff --git a/project.godot b/project.godot index 3f9e421..77fa6e3 100644 --- a/project.godot +++ b/project.godot @@ -39,3 +39,7 @@ common/enable_pause_aware_picking=true [rendering] environment/default_environment="res://default_env.tres" + +[svgsprite] + +compress=true