summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/config_file.cpp8
-rw-r--r--core/io/config_file.h1
-rw-r--r--core/math/rect2.h4
-rw-r--r--doc/tools/doc_status.py3
-rw-r--r--editor/editor_export.cpp7
-rw-r--r--editor/editor_export.h1
-rw-r--r--editor/plugins/sprite_editor_plugin.cpp77
-rw-r--r--editor/plugins/sprite_editor_plugin.h3
-rw-r--r--editor/project_manager.cpp6
-rw-r--r--editor/project_settings_editor.cpp19
-rw-r--r--platform/osx/export/export.cpp23
-rw-r--r--platform/windows/export/export.cpp185
-rw-r--r--scene/gui/grid_container.cpp2
-rw-r--r--scene/gui/item_list.cpp2
-rw-r--r--scene/main/viewport.cpp11
-rw-r--r--scene/resources/bit_map.cpp56
-rw-r--r--scene/resources/bit_map.h1
-rw-r--r--servers/visual/visual_server_canvas.cpp11
18 files changed, 346 insertions, 74 deletions
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 271e5c5a0b..5684c82d1c 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -123,6 +123,13 @@ void ConfigFile::erase_section(const String &p_section) {
values.erase(p_section);
}
+void ConfigFile::erase_section_key(const String &p_section, const String &p_key) {
+
+ ERR_FAIL_COND_MSG(!values.has(p_section), "Cannot erase key from nonexistent section '" + p_section + "'.");
+
+ values[p_section].erase(p_key);
+}
+
Error ConfigFile::save(const String &p_path) {
Error err;
@@ -293,6 +300,7 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_section_keys", "section"), &ConfigFile::_get_section_keys);
ClassDB::bind_method(D_METHOD("erase_section", "section"), &ConfigFile::erase_section);
+ ClassDB::bind_method(D_METHOD("erase_section_key", "section", "key"), &ConfigFile::erase_section_key);
ClassDB::bind_method(D_METHOD("load", "path"), &ConfigFile::load);
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 3ab6fef868..d927779f9c 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -60,6 +60,7 @@ public:
void get_section_keys(const String &p_section, List<String> *r_keys) const;
void erase_section(const String &p_section);
+ void erase_section_key(const String &p_section, const String &p_key);
Error save(const String &p_path);
Error load(const String &p_path);
diff --git a/core/math/rect2.h b/core/math/rect2.h
index d636aa223f..f58756ee40 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -99,8 +99,8 @@ struct Rect2 {
inline bool encloses(const Rect2 &p_rect) const {
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
- ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) &&
- ((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
+ ((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) &&
+ ((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
}
_FORCE_INLINE_ bool has_no_area() const {
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py
index 974ac2d05c..6e34cffc05 100644
--- a/doc/tools/doc_status.py
+++ b/doc/tools/doc_status.py
@@ -259,7 +259,8 @@ class ClassStatus:
status.progresses[tag.tag].increment(len(descr.text.strip()) > 0)
elif tag.tag in ['constants', 'members']:
for sub_tag in list(tag):
- status.progresses[tag.tag].increment(len(sub_tag.text.strip()) > 0)
+ if not sub_tag.text is None:
+ status.progresses[tag.tag].increment(len(sub_tag.text.strip()) > 0)
elif tag.tag in ['tutorials']:
pass # Ignore those tags for now
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 90f54df485..9510092a86 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1606,6 +1606,9 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr
da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < so_files.size() && err == OK; i++) {
err = da->copy(so_files[i].path, p_path.get_base_dir().plus_file(so_files[i].path.get_file()));
+ if (err == OK) {
+ err = sign_shared_object(p_preset, p_debug, p_path.get_base_dir().plus_file(so_files[i].path.get_file()));
+ }
}
memdelete(da);
}
@@ -1614,6 +1617,10 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr
return err;
}
+Error EditorExportPlatformPC::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
+ return OK;
+}
+
void EditorExportPlatformPC::set_extension(const String &p_extension, const String &p_feature_key) {
extensions[p_feature_key] = p_extension;
}
diff --git a/editor/editor_export.h b/editor/editor_export.h
index 3152e249bd..11dc464b5a 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -423,6 +423,7 @@ public:
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
+ virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
void set_extension(const String &p_extension, const String &p_feature_key = "default");
void set_name(const String &p_name);
diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp
index 69fd592652..40734cffc4 100644
--- a/editor/plugins/sprite_editor_plugin.cpp
+++ b/editor/plugins/sprite_editor_plugin.cpp
@@ -178,6 +178,7 @@ void SpriteEditor::_update_mesh_data() {
err_dialog->popup_centered_minsize();
return;
}
+
Ref<Image> image = texture->get_data();
ERR_FAIL_COND(image.is_null());
Rect2 rect;
@@ -190,7 +191,12 @@ void SpriteEditor::_update_mesh_data() {
bm.instance();
bm->create_from_image_alpha(image);
- int grow = island_merging->get_value();
+ int shrink = shrink_pixels->get_value();
+ if (shrink > 0) {
+ bm->shrink_mask(shrink, rect);
+ }
+
+ int grow = grow_pixels->get_value();
if (grow > 0) {
bm->grow_mask(grow, rect);
}
@@ -338,6 +344,13 @@ void SpriteEditor::_convert_to_mesh_2d_node() {
}
void SpriteEditor::_convert_to_polygon_2d_node() {
+
+ if (computed_outline_lines.empty()) {
+ err_dialog->set_text(TTR("Invalid geometry, can't create polygon."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
Polygon2D *polygon_2d_instance = memnew(Polygon2D);
int total_point_count = 0;
@@ -362,12 +375,6 @@ void SpriteEditor::_convert_to_polygon_2d_node() {
Vector<Vector2> outline = computed_outline_lines[i];
Vector<Vector2> uv_outline = outline_lines[i];
- if (outline.size() < 3) {
- err_dialog->set_text(TTR("Invalid geometry, can't create polygon."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
PoolIntArray pia;
pia.resize(outline.size());
PoolIntArray::Write pia_write = pia.write();
@@ -396,16 +403,17 @@ void SpriteEditor::_convert_to_polygon_2d_node() {
}
void SpriteEditor::_create_collision_polygon_2d_node() {
+
+ if (computed_outline_lines.empty()) {
+ err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
for (int i = 0; i < computed_outline_lines.size(); i++) {
Vector<Vector2> outline = computed_outline_lines[i];
- if (outline.size() < 3) {
- err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon."));
- err_dialog->popup_centered_minsize();
- continue;
- }
-
CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
collision_polygon_2d_instance->set_polygon(outline);
@@ -419,16 +427,17 @@ void SpriteEditor::_create_collision_polygon_2d_node() {
}
void SpriteEditor::_create_light_occluder_2d_node() {
+
+ if (computed_outline_lines.empty()) {
+ err_dialog->set_text(TTR("Invalid geometry, can't create light occluder."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
for (int i = 0; i < computed_outline_lines.size(); i++) {
Vector<Vector2> outline = computed_outline_lines[i];
- if (outline.size() < 3) {
- err_dialog->set_text(TTR("Invalid geometry, can't create light occluder."));
- err_dialog->popup_centered_minsize();
- continue;
- }
-
Ref<OccluderPolygon2D> polygon;
polygon.instance();
@@ -531,10 +540,14 @@ void SpriteEditor::_debug_uv_draw() {
Ref<Texture> tex = node->get_texture();
ERR_FAIL_COND(!tex.is_valid());
+
+ Point2 draw_pos_offset = Point2(1.0, 1.0);
+ Size2 draw_size_offset = Size2(2.0, 2.0);
+
debug_uv->set_clip_contents(true);
- debug_uv->draw_texture(tex, Point2());
- debug_uv->set_custom_minimum_size(tex->get_size());
- //debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
+ debug_uv->draw_texture(tex, draw_pos_offset);
+ debug_uv->set_custom_minimum_size(tex->get_size() + draw_size_offset);
+ debug_uv->draw_set_transform(draw_pos_offset, 0, Size2(1.0, 1.0));
Color color = Color(1.0, 0.8, 0.7);
@@ -604,13 +617,21 @@ SpriteEditor::SpriteEditor() {
simplification->set_value(2);
hb->add_child(simplification);
hb->add_spacer();
+ hb->add_child(memnew(Label(TTR("Shrink (Pixels): "))));
+ shrink_pixels = memnew(SpinBox);
+ shrink_pixels->set_min(0);
+ shrink_pixels->set_max(10);
+ shrink_pixels->set_step(1);
+ shrink_pixels->set_value(0);
+ hb->add_child(shrink_pixels);
+ hb->add_spacer();
hb->add_child(memnew(Label(TTR("Grow (Pixels): "))));
- island_merging = memnew(SpinBox);
- island_merging->set_min(0);
- island_merging->set_max(10);
- island_merging->set_step(1);
- island_merging->set_value(2);
- hb->add_child(island_merging);
+ grow_pixels = memnew(SpinBox);
+ grow_pixels->set_min(0);
+ grow_pixels->set_max(10);
+ grow_pixels->set_step(1);
+ grow_pixels->set_value(2);
+ hb->add_child(grow_pixels);
hb->add_spacer();
update_preview = memnew(Button);
update_preview->set_text(TTR("Update Preview"));
diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h
index 81be4a19e9..4ca7bca1a8 100644
--- a/editor/plugins/sprite_editor_plugin.h
+++ b/editor/plugins/sprite_editor_plugin.h
@@ -67,7 +67,8 @@ class SpriteEditor : public Control {
Vector<int> computed_indices;
SpinBox *simplification;
- SpinBox *island_merging;
+ SpinBox *grow_pixels;
+ SpinBox *shrink_pixels;
Button *update_preview;
void _menu_option(int p_option);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index f70dcab931..d903e153a7 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1753,6 +1753,12 @@ void ProjectManager::_notification(int p_what) {
Engine::get_singleton()->set_editor_hint(false);
} break;
+ case NOTIFICATION_RESIZED: {
+
+ if (open_templates->is_visible()) {
+ open_templates->popup_centered_minsize();
+ }
+ } break;
case NOTIFICATION_READY: {
if (_project_list->get_project_count() == 0 && StreamPeerSSL::is_available())
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index f177e634a6..35187214a6 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -845,13 +845,9 @@ void ProjectSettingsEditor::_item_adds(String) {
void ProjectSettingsEditor::_item_add() {
- Variant value;
- switch (type->get_selected()) {
- case 0: value = false; break;
- case 1: value = 0; break;
- case 2: value = 0.0; break;
- case 3: value = ""; break;
- }
+ // Initialize the property with the default value for the given type
+ Variant::CallError ce;
+ const Variant value = Variant::construct(Variant::Type(type->get_selected()), NULL, 0, ce);
String catname = category->get_text().strip_edges();
String propname = property->get_text().strip_edges();
@@ -1834,10 +1830,11 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
type = memnew(OptionButton);
type->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_prop_bar->add_child(type);
- type->add_item("bool");
- type->add_item("int");
- type->add_item("float");
- type->add_item("string");
+
+ // Start at 1 to avoid adding "Nil" as an option
+ for (int i = 1; i < Variant::VARIANT_MAX; i++) {
+ type->add_item(Variant::get_type_name(Variant::Type(i)), i);
+ }
Button *add = memnew(Button);
add_prop_bar->add_child(add);
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index c8ecbd5a2d..9226aea369 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -132,10 +132,12 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
#ifdef OSX_ENABLED
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "codesign/custom_options"), PoolStringArray()));
#endif
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
@@ -375,16 +377,27 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
args.push_back("--entitlements");
args.push_back(p_preset->get("codesign/entitlements"));
}
+
+ PoolStringArray user_args = p_preset->get("codesign/custom_options");
+ for (int i = 0; i < user_args.size(); i++) {
+ String user_arg = user_args[i].strip_edges();
+ if (!user_arg.empty()) {
+ args.push_back(user_arg);
+ }
+ }
+
args.push_back("-s");
args.push_back(p_preset->get("codesign/identity"));
+
args.push_back("-v"); /* provide some more feedback */
+
args.push_back(p_path);
String str;
Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true);
ERR_FAIL_COND_V(err != OK, err);
- print_line("codesign: " + str);
+ print_line("codesign (" + p_path + "): " + str);
if (str.find("no identity found") != -1) {
EditorNode::add_io_error("codesign: no identity found");
return FAILED;
@@ -663,20 +676,20 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = save_pack(p_preset, pack_path, &shared_objects);
// see if we can code sign our new package
- String identity = p_preset->get("codesign/identity");
+ bool sign_enabled = p_preset->get("codesign/enable");
if (err == OK) {
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file());
- if (err == OK && identity != "") {
+ if (err == OK && sign_enabled) {
err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file());
}
}
memdelete(da);
}
- if (err == OK && identity != "") {
+ if (err == OK && sign_enabled) {
if (ep.step("Code signing bundle", 2)) {
return ERR_SKIP;
}
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 827daa2d58..3abb05b494 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -31,6 +31,7 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "editor/editor_export.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "platform/windows/logo.gen.h"
@@ -38,11 +39,22 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,
class EditorExportPlatformWindows : public EditorExportPlatformPC {
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+
public:
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
+ virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
virtual void get_export_options(List<ExportOption> *r_options);
};
+Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
+ if (p_preset->get("codesign/enable")) {
+ return _code_sign(p_preset, p_path);
+ } else {
+ return OK;
+ }
+}
+
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags);
@@ -133,12 +145,28 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
OS::get_singleton()->execute(wine_path, args, true);
#endif
- return OK;
+ if (p_preset->get("codesign/enable") && err == OK) {
+ err = _code_sign(p_preset, p_path);
+ }
+
+ return err;
}
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
+#ifdef WINDOWS_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
+#endif
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "codesign/custom_options"), PoolStringArray()));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
@@ -149,11 +177,164 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
}
+Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ List<String> args;
+
+#ifdef WINDOWS_ENABLED
+ String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
+ if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
+ ERR_PRINTS("Could not find signtool executable at " + signtool_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+ if (signtool_path == String()) {
+ signtool_path = "signtool"; // try to run signtool from PATH
+ }
+#else
+ String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
+ if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
+ ERR_PRINTS("Could not find osslsigncode executable at " + signtool_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+ if (signtool_path == String()) {
+ signtool_path = "osslsigncode"; // try to run signtool from PATH
+ }
+#endif
+
+ args.push_back("sign");
+
+ //identity
+#ifdef WINDOWS_ENABLED
+ int id_type = p_preset->get("codesign/identity_type");
+ if (id_type == 0) { //auto select
+ args.push_back("/a");
+ } else if (id_type == 1) { //pkcs12
+ if (p_preset->get("codesign/identity") != "") {
+ args.push_back("/f");
+ args.push_back(p_preset->get("codesign/identity"));
+ } else {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+ } else if (id_type == 2) { //Windows certificate store
+ if (p_preset->get("codesign/identity") != "") {
+ args.push_back("/sha1");
+ args.push_back(p_preset->get("codesign/identity"));
+ } else {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+ } else {
+ EditorNode::add_io_error("codesign: invalid identity type");
+ return FAILED;
+ }
+#else
+ if (p_preset->get("codesign/identity") != "") {
+ args.push_back("-pkcs12");
+ args.push_back(p_preset->get("codesign/identity"));
+ } else {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+#endif
+
+ //password
+ if (p_preset->get("codesign/password") != "") {
+#ifdef WINDOWS_ENABLED
+ args.push_back("/p");
+#else
+ args.push_back("-pass");
+#endif
+ args.push_back(p_preset->get("codesign/password"));
+ }
+
+ //timestamp
+ if (p_preset->get("codesign/timestamp")) {
+ if (p_preset->get("codesign/timestamp_server") != "") {
+#ifdef WINDOWS_ENABLED
+ args.push_back("/tr");
+ args.push_back(p_preset->get("codesign/timestamp_server_url"));
+ args.push_back("/td");
+ if ((int)p_preset->get("codesign/digest_algorithm") == 0) {
+ args.push_back("sha1");
+ } else {
+ args.push_back("sha256");
+ }
+#else
+ args.push_back("-ts");
+ args.push_back(p_preset->get("codesign/timestamp_server_url"));
+#endif
+ } else {
+ EditorNode::add_io_error("codesign: invalid timestamp server");
+ return FAILED;
+ }
+ }
+
+ //digest
+#ifdef WINDOWS_ENABLED
+ args.push_back("/fd");
+#else
+ args.push_back("-h");
+#endif
+ if ((int)p_preset->get("codesign/digest_algorithm") == 0) {
+ args.push_back("sha1");
+ } else {
+ args.push_back("sha256");
+ }
+
+ //description
+ if (p_preset->get("codesign/description") != "") {
+#ifdef WINDOWS_ENABLED
+ args.push_back("/d");
+#else
+ args.push_back("-n");
+#endif
+ args.push_back(p_preset->get("codesign/description"));
+ }
+
+ //user options
+ PoolStringArray user_args = p_preset->get("codesign/custom_options");
+ for (int i = 0; i < user_args.size(); i++) {
+ String user_arg = user_args[i].strip_edges();
+ if (!user_arg.empty()) {
+ args.push_back(user_arg);
+ }
+ }
+
+#ifndef WINDOWS_ENABLED
+ args.push_back("-in");
+#endif
+ args.push_back(p_path);
+#ifndef WINDOWS_ENABLED
+ args.push_back("-out");
+ args.push_back(p_path);
+#endif
+
+ String str;
+ Error err = OS::get_singleton()->execute(signtool_path, args, true, NULL, &str, NULL, true);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ print_line("codesign (" + p_path + "): " + str);
+#ifndef WINDOWS_ENABLED
+ if (str.find("SignTool Error") != -1) {
+#else
+ if (str.find("Failed") != -1) {
+#endif
+ return FAILED;
+ }
+
+ return OK;
+}
+
void register_windows_exporter() {
EDITOR_DEF("export/windows/rcedit", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
-#ifndef WINDOWS_ENABLED
+#ifdef WINDOWS_ENABLED
+ EDITOR_DEF("export/windows/signtool", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
+#else
+ EDITOR_DEF("export/windows/osslsigncode", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/osslsigncode", PROPERTY_HINT_GLOBAL_FILE));
// On non-Windows we need WINE to run rcedit
EDITOR_DEF("export/windows/wine", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE));
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index d304a37f82..154e67b6f3 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -44,7 +44,7 @@ void GridContainer::_notification(int p_what) {
int hsep = get_constant("hseparation");
int vsep = get_constant("vseparation");
int max_col = MIN(get_child_count(), columns);
- int max_row = get_child_count() / columns;
+ int max_row = ceil((float)get_child_count() / (float)columns);
// Compute the per-column/per-row data.
int valid_controls_index = 0;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 4d06bee0d4..1a0539effa 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -926,7 +926,7 @@ void ItemList::_notification(int p_what) {
current_columns = max_columns;
while (true) {
- //repeat util all fits
+ //repeat until all fits
bool all_fit = true;
Vector2 ofs;
int col = 0;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 39c5759871..52ef225364 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1465,18 +1465,19 @@ void Viewport::_gui_show_tooltip() {
rp->add_child(gui.tooltip_popup);
gui.tooltip_popup->force_parent_owned();
gui.tooltip_popup->set_as_toplevel(true);
- //gui.tooltip_popup->hide();
+ if (gui.tooltip) // Avoids crash when rapidly switching controls.
+ gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
Rect2 vr = gui.tooltip_popup->get_viewport_rect();
- if (r.size.x + r.position.x > vr.size.x)
- r.position.x = vr.size.x - r.size.x;
+ if (r.size.x * gui.tooltip_popup->get_scale().x + r.position.x > vr.size.x)
+ r.position.x = vr.size.x - r.size.x * gui.tooltip_popup->get_scale().x;
else if (r.position.x < 0)
r.position.x = 0;
- if (r.size.y + r.position.y > vr.size.y)
- r.position.y = vr.size.y - r.size.y;
+ if (r.size.y * gui.tooltip_popup->get_scale().y + r.position.y > vr.size.y)
+ r.position.y = vr.size.y - r.size.y * gui.tooltip_popup->get_scale().y;
else if (r.position.y < 0)
r.position.y = 0;
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index e4a64a1de1..b5354bc3e2 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -197,16 +197,14 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
| 4 | 8 | <- current pixel (curx,cury)
+---+---+
*/
- //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel
- Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2));
Point2i tl = Point2i(curx - 1, cury - 1);
- sv += (fixed_rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
+ sv += (rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
Point2i tr = Point2i(curx, cury - 1);
- sv += (fixed_rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
+ sv += (rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
Point2i bl = Point2i(curx - 1, cury);
- sv += (fixed_rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
+ sv += (rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
Point2i br = Point2i(curx, cury);
- sv += (fixed_rect.has_point(br) && get_bit(br)) ? 8 : 0;
+ sv += (rect.has_point(br) && get_bit(br)) ? 8 : 0;
ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>());
}
@@ -300,15 +298,15 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
+---+---+
| 4 | |
+---+---+
- this normally go RIGHT, but if its coming from UP, it should go LEFT
+ this normally go RIGHT, but if its coming from RIGHT, it should go LEFT
*/
if (case6s.has(Point2i(curx, cury))) {
- //found, so we go down, and delete from case6s;
+ //found, so we go left, and delete from case6s;
stepx = -1;
stepy = 0;
case6s.erase(Point2i(curx, cury));
} else {
- //not found, we go up, and add to case6s;
+ //not found, we go right, and add to case6s;
stepx = 1;
stepy = 0;
case6s.insert(Point2i(curx, cury));
@@ -510,12 +508,19 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
+ fill_bits(this, fill, Point2i(j, i), r);
+
Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
print_verbose("BitMap: Pre reduce: " + itos(polygon.size()));
polygon = reduce(polygon, r, p_epsilon);
print_verbose("BitMap: Post reduce: " + itos(polygon.size()));
+
+ if (polygon.size() < 3) {
+ print_verbose("Invalid polygon, skipped");
+ continue;
+ }
+
polygons.push_back(polygon);
- fill_bits(this, fill, Point2i(j, i), r);
}
}
}
@@ -525,6 +530,13 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
+ if (p_pixels == 0) {
+ return;
+ }
+
+ bool bit_value = (p_pixels > 0) ? true : false;
+ p_pixels = Math::abs(p_pixels);
+
Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
Ref<BitMap> copy;
@@ -534,7 +546,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
- if (copy->get_bit(Point2(j, i)))
+ if (bit_value == get_bit(Point2(j, i)))
continue;
bool found = false;
@@ -542,16 +554,21 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
for (int y = i - p_pixels; y <= i + p_pixels; y++) {
for (int x = j - p_pixels; x <= j + p_pixels; x++) {
- if (x < p_rect.position.x || x >= p_rect.position.x + p_rect.size.x)
- continue;
- if (y < p_rect.position.y || y >= p_rect.position.y + p_rect.size.y)
- continue;
+ bool outside = false;
+
+ if ((x < p_rect.position.x) || (x >= p_rect.position.x + p_rect.size.x) || (y < p_rect.position.y) || (y >= p_rect.position.y + p_rect.size.y)) {
+ // outside of rectangle counts as bit not set
+ if (!bit_value)
+ outside = true;
+ else
+ continue;
+ }
float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON;
if (d > p_pixels)
continue;
- if (copy->get_bit(Point2(x, y))) {
+ if (outside || (bit_value == copy->get_bit(Point2(x, y)))) {
found = true;
break;
}
@@ -561,12 +578,17 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
}
if (found) {
- set_bit(Point2(j, i), true);
+ set_bit(Point2(j, i), bit_value);
}
}
}
}
+void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) {
+
+ grow_mask(-p_pixels, p_rect);
+}
+
Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
Vector<Vector<Vector2> > result = clip_opaque_to_polygons(p_rect, p_epsilon);
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index daf24affb1..b062dd7376 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -67,6 +67,7 @@ public:
void resize(const Size2 &p_new_size);
void grow_mask(int p_pixels, const Rect2 &p_rect);
+ void shrink_mask(int p_pixels, const Rect2 &p_rect);
void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap);
Ref<Image> convert_to_image() const;
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
index f5a1276c27..ed06a67e4c 100644
--- a/servers/visual/visual_server_canvas.cpp
+++ b/servers/visual/visual_server_canvas.cpp
@@ -680,11 +680,22 @@ void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const R
rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H;
rect->rect.size.x = -rect->rect.size.x;
}
+ if (p_src_rect.size.x < 0) {
+
+ rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_H;
+ rect->source.size.x = -rect->source.size.x;
+ }
if (p_rect.size.y < 0) {
rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V;
rect->rect.size.y = -rect->rect.size.y;
}
+ if (p_src_rect.size.y < 0) {
+
+ rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_V;
+ rect->source.size.y = -rect->source.size.y;
+ }
+
if (p_transpose) {
rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE;
SWAP(rect->rect.size.x, rect->rect.size.y);