summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUE_TEMPLATE.md11
-rw-r--r--SConstruct6
-rw-r--r--core/dictionary.cpp2
-rw-r--r--core/dictionary.h2
-rw-r--r--core/io/resource_loader.cpp44
-rw-r--r--core/variant_call.cpp2
-rw-r--r--doc/classes/BakedLightmap.xml16
-rw-r--r--doc/classes/BakedLightmapData.xml2
-rw-r--r--doc/classes/Dictionary.xml6
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp1
-rw-r--r--drivers/gles3/shader_gles3.cpp1
-rw-r--r--drivers/gles3/shaders/canvas.glsl2
-rw-r--r--editor/editor_autoload_settings.cpp28
-rw-r--r--editor/editor_export.cpp19
-rw-r--r--editor/editor_file_dialog.cpp5
-rw-r--r--editor/editor_help.cpp4
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/export_template_manager.cpp19
-rw-r--r--editor/icons/SCsub3
-rw-r--r--editor/icons/icon_GUI_visibility_hidden.svg2
-rw-r--r--editor/icons/icon_a_a_b_b.svg (renamed from editor/icons/icon_mini_aabb.svg)0
-rw-r--r--editor/icons/icon_array.svg (renamed from editor/icons/icon_mini_array.svg)0
-rw-r--r--editor/icons/icon_basis.svg4
-rw-r--r--editor/icons/icon_bool.svg3
-rw-r--r--editor/icons/icon_color.svg7
-rw-r--r--editor/icons/icon_dictionary.svg3
-rw-r--r--editor/icons/icon_float.svg3
-rw-r--r--editor/icons/icon_int.svg3
-rw-r--r--editor/icons/icon_kinematic_body.svg4
-rw-r--r--editor/icons/icon_kinematic_body_2d.svg6
-rw-r--r--editor/icons/icon_match_case.svg3
-rw-r--r--editor/icons/icon_member_constant.svg3
-rw-r--r--editor/icons/icon_member_method.svg3
-rw-r--r--editor/icons/icon_member_property.svg3
-rw-r--r--editor/icons/icon_member_signal.svg3
-rw-r--r--editor/icons/icon_member_theme.svg6
-rw-r--r--editor/icons/icon_mini_basis.svg6
-rw-r--r--editor/icons/icon_mini_boolean.svg5
-rw-r--r--editor/icons/icon_mini_color.svg7
-rw-r--r--editor/icons/icon_mini_color_array.svg14
-rw-r--r--editor/icons/icon_mini_dictionary.svg5
-rw-r--r--editor/icons/icon_mini_float.svg5
-rw-r--r--editor/icons/icon_mini_float_array.svg7
-rw-r--r--editor/icons/icon_mini_int_array.svg7
-rw-r--r--editor/icons/icon_mini_integer.svg5
-rw-r--r--editor/icons/icon_mini_object.svg4
-rw-r--r--editor/icons/icon_mini_path.svg5
-rw-r--r--editor/icons/icon_mini_plane.svg5
-rw-r--r--editor/icons/icon_mini_quat.svg7
-rw-r--r--editor/icons/icon_mini_raw_array.svg7
-rw-r--r--editor/icons/icon_mini_rect2.svg5
-rw-r--r--editor/icons/icon_mini_string.svg5
-rw-r--r--editor/icons/icon_mini_string_array.svg7
-rw-r--r--editor/icons/icon_mini_transform.svg6
-rw-r--r--editor/icons/icon_mini_transform2D.svg6
-rw-r--r--editor/icons/icon_mini_variant.svg5
-rw-r--r--editor/icons/icon_mini_vector2.svg6
-rw-r--r--editor/icons/icon_mini_vector2_array.svg7
-rw-r--r--editor/icons/icon_mini_vector3.svg6
-rw-r--r--editor/icons/icon_mini_vector3_array.svg7
-rw-r--r--editor/icons/icon_nil.svg3
-rw-r--r--editor/icons/icon_node_path.svg3
-rw-r--r--editor/icons/icon_plane.svg6
-rw-r--r--editor/icons/icon_pool_byte_array.svg5
-rw-r--r--editor/icons/icon_pool_color_array.svg8
-rw-r--r--editor/icons/icon_pool_int_array.svg5
-rw-r--r--editor/icons/icon_pool_real_array.svg5
-rw-r--r--editor/icons/icon_pool_string_array.svg5
-rw-r--r--editor/icons/icon_pool_vector2_array.svg5
-rw-r--r--editor/icons/icon_pool_vector3_array.svg5
-rw-r--r--editor/icons/icon_quat.svg8
-rw-r--r--editor/icons/icon_r_i_d.svg (renamed from editor/icons/icon_mini_rid.svg)0
-rw-r--r--editor/icons/icon_range.svg5
-rw-r--r--editor/icons/icon_rect2.svg3
-rw-r--r--editor/icons/icon_scroll_bar.svg5
-rw-r--r--editor/icons/icon_string.svg3
-rw-r--r--editor/icons/icon_theme.svg16
-rw-r--r--editor/icons/icon_transform.svg4
-rw-r--r--editor/icons/icon_transform_2_D.svg4
-rw-r--r--editor/icons/icon_variant.svg17
-rw-r--r--editor/icons/icon_vector2.svg4
-rw-r--r--editor/icons/icon_vector3.svg4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp6
-rw-r--r--editor/progress_dialog.cpp3
-rw-r--r--editor/project_settings_editor.cpp8
-rw-r--r--editor/property_editor.cpp4
-rw-r--r--editor/property_editor.h4
-rw-r--r--editor/scene_tree_dock.cpp12
-rw-r--r--editor/scene_tree_dock.h1
-rw-r--r--editor/settings_config_dialog.cpp76
-rw-r--r--editor/settings_config_dialog.h6
-rw-r--r--main/main.cpp4
-rw-r--r--methods.py18
-rw-r--r--modules/gdnative/SCsub4
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp423
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.h113
-rw-r--r--modules/gdnative/gdnative_library_singleton_editor.cpp (renamed from modules/gdnative/gd_native_library_editor.cpp)19
-rw-r--r--modules/gdnative/gdnative_library_singleton_editor.h (renamed from modules/gdnative/gd_native_library_editor.h)6
-rw-r--r--modules/gdnative/register_types.cpp7
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml30
-rw-r--r--modules/gridmap/grid_map.cpp251
-rw-r--r--modules/gridmap/grid_map.h13
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp4
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp16
-rw-r--r--modules/thekla_unwrap/register_types.cpp2
-rw-r--r--modules/visual_script/visual_script_editor.cpp110
-rw-r--r--platform/android/godot_android.cpp2
-rw-r--r--platform/android/java_glue.cpp3
-rw-r--r--scene/3d/baked_lightmap.cpp72
-rw-r--r--scene/3d/baked_lightmap.h5
-rw-r--r--scene/3d/sprite_3d.cpp1
-rw-r--r--scene/3d/voxel_light_baker.cpp123
-rw-r--r--scene/3d/voxel_light_baker.h3
-rw-r--r--scene/gui/label.cpp2
-rw-r--r--scene/gui/popup_menu.cpp47
-rw-r--r--scene/main/node.cpp4
-rw-r--r--scene/main/scene_tree.cpp24
-rw-r--r--scene/main/scene_tree.h5
-rw-r--r--scene/main/viewport.cpp7
-rw-r--r--scene/register_scene_types.cpp6
-rw-r--r--scene/resources/dynamic_font.cpp32
-rw-r--r--scene/resources/dynamic_font.h13
-rw-r--r--scene/resources/font.cpp4
-rw-r--r--thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp1992
-rw-r--r--thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h71
-rw-r--r--thirdparty/thekla_atlas/thekla/thekla_atlas.cpp425
127 files changed, 2702 insertions, 1784 deletions
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index 2a3c298633..dbfb2bdeab 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -1,4 +1,9 @@
-**Operating system or device, Godot version, GPU Model and driver (if graphics related):**
+**Godot version:**
+<!-- If thirdparty of self-compiled, specify the build date or commit hash. -->
+
+
+**OS/device including version:**
+<!-- If graphics related, specify also GPU model and drivers. -->
**Issue description:**
@@ -8,5 +13,5 @@
**Steps to reproduce:**
-**Link to minimal example project:**
-<!-- Optional but very welcome. You can drag and drop a zip archive to upload it. -->
+**Minimal reproduction project:**
+<!-- Optional but greatly speeds up debugging. You can drag and drop a zip archive to upload it. -->
diff --git a/SConstruct b/SConstruct
index ad6b6ee445..88cd1494f1 100644
--- a/SConstruct
+++ b/SConstruct
@@ -557,9 +557,9 @@ class cache_progress:
# decay since the ctime, and return a list with the entries
# (filename, size, weight).
current_time = time.time()
- file_stat = [(x[0], x[1][0], x[1][0] * math.exp(self.exponent_scale * (x[1][1] - current_time))) for x in file_stat]
- # Sort by highest weight (most sensible to keep) first
- file_stat.sort(key=lambda x: x[2], reverse=True)
+ file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat]
+ # Sort by the most resently accessed files (most sensible to keep) first
+ file_stat.sort(key=lambda x: x[2])
# Search for the first entry where the storage limit is
# reached
sum, mark = 0, None
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index 44fce2474f..66af6a1a9a 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -215,7 +215,7 @@ const Variant *Dictionary::next(const Variant *p_key) const {
return NULL;
}
-Dictionary Dictionary::copy() const {
+Dictionary Dictionary::duplicate() const {
Dictionary n;
diff --git a/core/dictionary.h b/core/dictionary.h
index c8177d5648..1d8ca0023e 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -74,7 +74,7 @@ public:
Array keys() const;
Array values() const;
- Dictionary copy() const;
+ Dictionary duplicate() const;
Dictionary(const Dictionary &p_from);
Dictionary();
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index d2aad1d63a..dea9f38634 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -35,6 +35,7 @@
#include "print_string.h"
#include "project_settings.h"
#include "translation.h"
+#include "variant_parser.h"
ResourceFormatLoader *ResourceLoader::loader[MAX_LOADERS];
int ResourceLoader::loader_count = 0;
@@ -454,6 +455,49 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
if (path_remaps.has(new_path)) {
new_path = path_remaps[new_path];
}
+
+ if (new_path == p_path) { //did not remap
+ //try file remap
+ Error err;
+ FileAccess *f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err);
+
+ if (f) {
+
+ VariantParser::StreamFile stream;
+ stream.f = f;
+
+ String assign;
+ Variant value;
+ VariantParser::Tag next_tag;
+
+ int lines = 0;
+ String error_text;
+ while (true) {
+
+ assign = Variant();
+ next_tag.fields.clear();
+ next_tag.name = String();
+
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ if (err == ERR_FILE_EOF) {
+ break;
+ } else if (err != OK) {
+ ERR_PRINTS("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text);
+ break;
+ }
+
+ if (assign == "path") {
+ new_path = value;
+ break;
+ } else if (next_tag.name != "remap") {
+ break;
+ }
+ }
+
+ memdelete(f);
+ }
+ }
+
return new_path;
}
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 2b99a60ba5..0284c4d866 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -462,6 +462,7 @@ struct _VariantCall {
VCALL_LOCALMEM0R(Dictionary, hash);
VCALL_LOCALMEM0R(Dictionary, keys);
VCALL_LOCALMEM0R(Dictionary, values);
+ VCALL_LOCALMEM0R(Dictionary, duplicate);
VCALL_LOCALMEM2(Array, set);
VCALL_LOCALMEM1R(Array, get);
@@ -1607,6 +1608,7 @@ void register_variant_methods() {
ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray());
ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray());
ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray());
+ ADDFUNC0R(DICTIONARY, DICTIONARY, Dictionary, duplicate, varray());
ADDFUNC0R(ARRAY, INT, Array, size, varray());
ADDFUNC0R(ARRAY, BOOL, Array, empty, varray());
diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml
index 8084af3817..b351aeac05 100644
--- a/doc/classes/BakedLightmap.xml
+++ b/doc/classes/BakedLightmap.xml
@@ -57,11 +57,7 @@
</constant>
<constant name="SUBDIV_1024" value="3" enum="Subdiv">
</constant>
- <constant name="SUBDIV_2048" value="4" enum="Subdiv">
- </constant>
- <constant name="SUBDIV_4096" value="5" enum="Subdiv">
- </constant>
- <constant name="SUBDIV_MAX" value="6" enum="Subdiv">
+ <constant name="SUBDIV_MAX" value="4" enum="Subdiv">
</constant>
<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">
</constant>
@@ -73,5 +69,15 @@
</constant>
<constant name="BAKE_MODE_RAY_TRACE" value="1" enum="BakeMode">
</constant>
+ <constant name="BAKE_ERROR_OK" value="0" enum="BakeError">
+ </constant>
+ <constant name="BAKE_ERROR_NO_SAVE_PATH" value="1" enum="BakeError">
+ </constant>
+ <constant name="BAKE_ERROR_NO_MESHES" value="2" enum="BakeError">
+ </constant>
+ <constant name="BAKE_ERROR_CANT_CREATE_IMAGE" value="3" enum="BakeError">
+ </constant>
+ <constant name="BAKE_ERROR_USER_ABORTED" value="4" enum="BakeError">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/BakedLightmapData.xml b/doc/classes/BakedLightmapData.xml
index 6997dcb0b2..2b95cff136 100644
--- a/doc/classes/BakedLightmapData.xml
+++ b/doc/classes/BakedLightmapData.xml
@@ -16,6 +16,8 @@
</argument>
<argument index="1" name="lightmap" type="Texture">
</argument>
+ <argument index="2" name="instance" type="int">
+ </argument>
<description>
</description>
</method>
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 40b60f00cf..08c01c1d85 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -16,6 +16,12 @@
Clear the dictionary, removing all key/value pairs.
</description>
</method>
+ <method name="duplicate">
+ <return type="Dictionary">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="empty">
<return type="bool">
</return>
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 5d93c6a982..a4daa77b50 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1784,6 +1784,8 @@ void RasterizerCanvasGLES3::initialize() {
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
}
void RasterizerCanvasGLES3::finalize() {
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index ee6c738a05..8ee9e3fdb8 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -6048,6 +6048,7 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) {
glDeleteTextures(1, &rt->effects.mip_maps[i].color);
rt->effects.mip_maps[i].sizes.clear();
rt->effects.mip_maps[i].levels = 0;
+ rt->effects.mip_maps[i].color = 0;
}
}
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 20b2bc0a28..56b1cfdf0f 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -465,7 +465,6 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
if (feedbacks[i].conditional == -1 || (1 << feedbacks[i].conditional) & conditional_version.version) {
//conditional for this feedback is enabled
- print_line("tf varying: " + itos(feedback.size()) + " " + String(feedbacks[i].name));
feedback.push_back(feedbacks[i].name);
}
}
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 4bbb18ce42..0b8230234b 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -171,7 +171,7 @@ VERTEX_SHADER_CODE
#ifdef USE_PIXEL_SNAP
- outvec.xy=floor(outvec+0.5);
+ outvec.xy=floor(outvec+0.5).xy;
#endif
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index ae7ed7ce61..2796f776d7 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -548,34 +548,28 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
HBoxContainer *hbc = memnew(HBoxContainer);
add_child(hbc);
- VBoxContainer *vbc_path = memnew(VBoxContainer);
- vbc_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ Label *l = memnew(Label);
+ l->set_text(TTR("Path:"));
+ hbc->add_child(l);
autoload_add_path = memnew(EditorLineEditFileChooser);
autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL);
-
autoload_add_path->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE);
autoload_add_path->get_file_dialog()->connect("file_selected", this, "_autoload_file_callback");
+ hbc->add_child(autoload_add_path);
- vbc_path->add_margin_child(TTR("Path:"), autoload_add_path);
- hbc->add_child(vbc_path);
-
- VBoxContainer *vbc_name = memnew(VBoxContainer);
- vbc_name->set_h_size_flags(SIZE_EXPAND_FILL);
-
- HBoxContainer *hbc_name = memnew(HBoxContainer);
+ l = memnew(Label);
+ l->set_text(TTR("Node Name:"));
+ hbc->add_child(l);
autoload_add_name = memnew(LineEdit);
autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL);
- hbc_name->add_child(autoload_add_name);
+ hbc->add_child(autoload_add_name);
Button *add_autoload = memnew(Button);
add_autoload->set_text(TTR("Add"));
- hbc_name->add_child(add_autoload);
add_autoload->connect("pressed", this, "_autoload_add");
-
- vbc_name->add_margin_child(TTR("Node Name:"), hbc_name);
- hbc->add_child(vbc_name);
+ hbc->add_child(add_autoload);
tree = memnew(Tree);
tree->set_hide_root(true);
@@ -606,5 +600,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
tree->connect("item_edited", this, "_autoload_edited");
tree->connect("button_pressed", this, "_autoload_button_pressed");
- add_margin_child(TTR("List:"), tree, true);
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ add_child(tree, true);
}
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 3585417d13..1b88a56b75 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -740,7 +740,24 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
ProjectSettings::CustomMap custom_map;
if (path_remaps.size()) {
- custom_map["path_remap/remapped_paths"] = path_remaps;
+ if (1) { //new remap mode, use always as it's friendlier with multiple .pck exports
+ for (int i = 0; i < path_remaps.size(); i += 2) {
+ String from = path_remaps[i];
+ String to = path_remaps[i + 1];
+ String remap_file = "[remap]\n\npath=\"" + to.c_escape() + "\"\n";
+ CharString utf8 = remap_file.utf8();
+ Vector<uint8_t> new_file;
+ new_file.resize(utf8.length());
+ for (int j = 0; j < utf8.length(); j++) {
+ new_file[j] = utf8[j];
+ }
+
+ p_func(p_udata, from + ".remap", new_file, idx, total);
+ }
+ } else {
+ //old remap mode, will still work, but it's unused because it's not multiple pck export friendly
+ custom_map["path_remap/remapped_paths"] = path_remaps;
+ }
}
// Store icon and splash images directly, they need to bypass the import system and be loaded as images
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index eaa57fa46b..deba16a524 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -107,8 +107,8 @@ void EditorFileDialog::_notification(int p_what) {
fav_up->set_icon(get_icon("MoveUp", "EditorIcons"));
fav_down->set_icon(get_icon("MoveDown", "EditorIcons"));
fav_rm->set_icon(get_icon("Remove", "EditorIcons"));
-
- update_file_list();
+ // DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD
+ invalidate();
}
}
@@ -637,6 +637,7 @@ bool EditorFileDialog::_is_open_should_be_disabled() {
return false;
}
+// DO NOT USE THIS FUNCTION UNLESS NEEDED, CALL INVALIDATE() INSTEAD.
void EditorFileDialog::update_file_list() {
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index d20b55e268..46badc8c86 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1016,6 +1016,10 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop(); //cell
}
+ if (m[i].description != "") {
+ method_descr = true;
+ }
+
_add_method(m[i], true);
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0eb8ea6e46..f8e350bee3 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5033,7 +5033,7 @@ EditorNode::EditorNode() {
scene_root_parent->set_v_size_flags(Control::SIZE_EXPAND_FILL);
scene_root = memnew(Viewport);
- scene_root->set_usage(Viewport::USAGE_2D);
+ //scene_root->set_usage(Viewport::USAGE_2D); canvas BG mode prevents usage of this as 2D
scene_root->set_disable_3d(true);
VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true);
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 3eaa6e44fd..a72769b222 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -273,7 +273,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
char fname[16384];
unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
- String file = fname;
+ String file = String(fname).get_file();
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
@@ -283,21 +283,18 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
- print_line(fname);
- /*
- for(int i=0;i<512;i++) {
- print_line(itos(data[i]));
- }
- */
-
- file = file.get_file();
if (p) {
p->step(TTR("Importing:") + " " + file, fc);
}
FileAccess *f = FileAccess::open(template_path.plus_file(file), FileAccess::WRITE);
- ERR_CONTINUE(!f);
+ if (!f) {
+ ret = unzGoToNextFile(pkg);
+ fc++;
+ ERR_CONTINUE(!f);
+ }
+
f->store_buffer(data.ptr(), data.size());
memdelete(f);
@@ -555,7 +552,7 @@ ExportTemplateManager::ExportTemplateManager() {
template_open->add_filter("*.tpz ; Godot Export Templates");
template_open->set_access(FileDialog::ACCESS_FILESYSTEM);
template_open->set_mode(FileDialog::MODE_OPEN_FILE);
- template_open->connect("file_selected", this, "_install_from_file");
+ template_open->connect("file_selected", this, "_install_from_file", varray(true));
add_child(template_open);
set_title(TTR("Export Template Manager"));
diff --git a/editor/icons/SCsub b/editor/icons/SCsub
index e28c229a38..0e4a4796ec 100644
--- a/editor/icons/SCsub
+++ b/editor/icons/SCsub
@@ -49,6 +49,9 @@ def make_editor_icons_action(target, source, env):
fname = str(f)
icon_name = os.path.basename(fname)[5:-4].title().replace("_", "")
+ # some special cases
+ if icon_name in ['Int', 'Bool', 'Float']:
+ icon_name = icon_name.lower()
if icon_name.endswith("MediumThumb"): # dont know a better way to handle this
thumb_medium_indices.append(str(index))
if icon_name.endswith("BigThumb"): # dont know a better way to handle this
diff --git a/editor/icons/icon_GUI_visibility_hidden.svg b/editor/icons/icon_GUI_visibility_hidden.svg
index 61131c77c8..7b7f3c8031 100644
--- a/editor/icons/icon_GUI_visibility_hidden.svg
+++ b/editor/icons/icon_GUI_visibility_hidden.svg
@@ -1,3 +1,3 @@
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<path d="m7.9998 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -0.00586 0.5703c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0 -0.5527c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" fill="#e0e0e0" fill-opacity=".39216" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
+<path d="m2.9609 7.7266-1.9219 0.54883c0.31999 1.12 0.8236 2.0593 1.4316 2.8398l-0.83398 0.83398 1.4141 1.4141 0.84375-0.84375c0.98585 0.74762 2.0766 1.2067 3.1055 1.3867v1.0938h2v-1.0938c1.0288-0.17998 2.1196-0.6391 3.1055-1.3867l0.84375 0.84375 1.4141-1.4141-0.83398-0.83398c0.60804-0.78055 1.1117-1.7199 1.4316-2.8398l-1.9219-0.54883c-0.8756 3.0646-3.5391 4.2734-5.0391 4.2734s-4.1635-1.2088-5.0391-4.2734z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
</svg>
diff --git a/editor/icons/icon_mini_aabb.svg b/editor/icons/icon_a_a_b_b.svg
index 1af05f9b68..1af05f9b68 100644
--- a/editor/icons/icon_mini_aabb.svg
+++ b/editor/icons/icon_a_a_b_b.svg
diff --git a/editor/icons/icon_mini_array.svg b/editor/icons/icon_array.svg
index 4a279bf87b..4a279bf87b 100644
--- a/editor/icons/icon_mini_array.svg
+++ b/editor/icons/icon_array.svg
diff --git a/editor/icons/icon_basis.svg b/editor/icons/icon_basis.svg
new file mode 100644
index 0000000000..e9bee04f56
--- /dev/null
+++ b/editor/icons/icon_basis.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 2v8h2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3v-2zm10 0v2h2v-2zm-3 2a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324 -1 2 2 0 0 0 0 -2 2 2 0 0 0 -1.7324 -1h2v-2zm7 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v-2h-2v4h4a2 2 0 0 0 1.7324 -1 2 2 0 0 0 0 -2 2 2 0 0 0 -1.7324 -1h2v-2zm-12 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#e3ec69"/>
+<path d="m10 2v2h2v-2zm0 4v4h2v-4z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_bool.svg b/editor/icons/icon_bool.svg
new file mode 100644
index 0000000000..c4c919dfca
--- /dev/null
+++ b/editor/icons/icon_bool.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 2v8h2a3 3 0 0 0 2.5 -1.3457 3 3 0 0 0 2.5 1.3457 3 3 0 0 0 2 -0.76758 3 3 0 0 0 2 0.76758 3 3 0 0 0 2.5 -1.3457 3 3 0 0 0 2.5 1.3457v-2a1 1 0 0 1 -1 -1v-5h-2v2.7695a3 3 0 0 0 -2 -0.76953 3 3 0 0 0 -2 0.76758 3 3 0 0 0 -2 -0.76758 3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5 -1.3457v-2zm2 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#8da6f0"/>
+</svg>
diff --git a/editor/icons/icon_color.svg b/editor/icons/icon_color.svg
new file mode 100644
index 0000000000..52c7890e60
--- /dev/null
+++ b/editor/icons/icon_color.svg
@@ -0,0 +1,7 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<g>
+<path d="m4 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2z" fill="#ff8484"/>
+<path d="m14 4a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v-2z" fill="#84c2ff"/>
+<path d="m6 2v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-5z" fill="#84ffb1"/>
+</g>
+</svg>
diff --git a/editor/icons/icon_dictionary.svg b/editor/icons/icon_dictionary.svg
new file mode 100644
index 0000000000..b0146bb5d3
--- /dev/null
+++ b/editor/icons/icon_dictionary.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m3 2v2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-8h-2zm3 0v2h2v-2h-2zm7 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2zm-2 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1zm-3 3v-1h-2v4h2v-3zm-5-1v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#77edb1"/>
+</svg>
diff --git a/editor/icons/icon_float.svg b/editor/icons/icon_float.svg
new file mode 100644
index 0000000000..4091101fd1
--- /dev/null
+++ b/editor/icons/icon_float.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m3 2a3 3 0 0 0 -3 3v5h2v-2h2v-2h-2v-1a1 1 0 0 1 1 -1h1v-2zm3 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-5zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2z" fill="#61daf4"/>
+</svg>
diff --git a/editor/icons/icon_int.svg b/editor/icons/icon_int.svg
new file mode 100644
index 0000000000..e16bb2ec07
--- /dev/null
+++ b/editor/icons/icon_int.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m1 2v2h2v-2zm11 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2zm-8 2v6h2v-4h1a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-1zm-3 2v4h2v-4z" fill="#7dc6ef"/>
+</svg>
diff --git a/editor/icons/icon_kinematic_body.svg b/editor/icons/icon_kinematic_body.svg
index 6f8d69fa53..c5f817c68c 100644
--- a/editor/icons/icon_kinematic_body.svg
+++ b/editor/icons/icon_kinematic_body.svg
@@ -1,5 +1,3 @@
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m6 1c-0.55401 0-1 0.44599-1 1v3c0 0.55401 0.44599 1 1 1h1v0.99023a1.0001 1.0001 0 0 0 -0.31641 0.0625l-2.0508 0.68359-0.68359-2.0508a1.0001 1.0001 0 0 0 -0.99023 -0.69727 1.0001 1.0001 0 0 0 -0.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656 0.63281l1.6836-0.56055v0.61133c0 0.040884 0.018715 0.075662 0.023438 0.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109 0.50195l3-1a1.0001 1.0001 0 1 0 -0.63281 -1.8965l-2.1777 0.72461-0.97461-1.9512c0.2759-0.17764 0.46875-0.47227 0.46875-0.82617v-1h1.3828l0.72266 1.4473a1.0001 1.0001 0 1 0 1.7891 -0.89453l-1-2a1.0001 1.0001 0 0 0 -0.89453 -0.55273h-3v-1h1c0.55401 0 1-0.44599 1-1v-3c0-0.55401-0.44599-1-1-1h-4zm0 2h1v2h-1v-2z" fill="#fc9c9c" fill-opacity=".99608"/>
-</g>
+<path d="m6 1c-0.55401 0-1 0.44599-1 1v3c0 0.55401 0.44599 1 1 1h1v0.99023a1.0001 1.0001 0 0 0 -0.31641 0.0625l-2.0508 0.68359-0.68359-2.0508a1.0001 1.0001 0 0 0 -0.99023 -0.69727 1.0001 1.0001 0 0 0 -0.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656 0.63281l1.6836-0.56055v0.61133c0 0.04088 0.018715 0.07566 0.023437 0.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109 0.50195l3-1a1.0001 1.0001 0 1 0 -0.63281 -1.8965l-2.1777 0.72461-0.97461-1.9512c0.2759-0.17764 0.46875-0.47227 0.46875-0.82617v-1h1.3828l0.72266 1.4473a1.0001 1.0001 0 1 0 1.7891 -0.89453l-1-2a1.0001 1.0001 0 0 0 -0.89453 -0.55273h-3v-1h1c0.55401 0 1-0.44599 1-1v-3c0-0.55401-0.44599-1-1-1zm0 2h1v2h-1z" fill="#fc9c9c" fill-opacity=".99608"/>
</svg>
diff --git a/editor/icons/icon_kinematic_body_2d.svg b/editor/icons/icon_kinematic_body_2d.svg
index 0441e499c0..cac3ac7684 100644
--- a/editor/icons/icon_kinematic_body_2d.svg
+++ b/editor/icons/icon_kinematic_body_2d.svg
@@ -1,7 +1,3 @@
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<g transform="translate(.49212 -.0044019)" fill="#a5b7f3">
-<path transform="translate(0 1036.4)" d="m6 1c-0.55401 0-1 0.44599-1 1v3c0 0.55401 0.44599 1 1 1h1v0.99023a1.0001 1.0001 0 0 0 -0.31641 0.0625l-2.0508 0.68359-0.68359-2.0508a1.0001 1.0001 0 0 0 -0.99023 -0.69727 1.0001 1.0001 0 0 0 -0.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656 0.63281l1.6836-0.56055v0.61133c0 0.04088 0.018715 0.07566 0.023437 0.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109 0.50195l3-1a1.0001 1.0001 0 1 0 -0.63281 -1.8965l-2.1777 0.72461-0.97461-1.9512c0.2759-0.17764 0.46875-0.47227 0.46875-0.82617v-1h1.3828l0.72266 1.4473a1.0001 1.0001 0 1 0 1.7891 -0.89453l-1-2a1.0001 1.0001 0 0 0 -0.89453 -0.55273h-3v-1h1c0.55401 0 1-0.44599 1-1v-3c0-0.55401-0.44599-1-1-1zm0 2h1v2h-1z" fill="#a5b7f3"/>
-</g>
-</g>
+<path d="m6.4921 1c-0.55401 0-1 0.446-1 1v3c0 0.554 0.44599 1 1 1h1v0.9902a1.0001 1.0001 0 0 0 -0.31641 0.062l-2.0508 0.6836-0.68359-2.0508a1.0001 1.0001 0 0 0 -0.99023 -0.6972 1.0001 1.0001 0 0 0 -0.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656 0.6328l1.6836-0.5605v0.6113c0 0.041 0.018715 0.076 0.023437 0.1152l-4.5781 3.0528a1.0001 1.0001 0 1 0 1.1094 1.664l5.0566-3.3711 1.4941 2.9864a1.0001 1.0001 0 0 0 1.2109 0.5019l3-1a1.0001 1.0001 0 1 0 -0.63281 -1.8965l-2.1777 0.7246-0.97461-1.9511c0.2759-0.1777 0.46875-0.4723 0.46875-0.8262v-1h1.3828l0.72266 1.4473a1.0001 1.0001 0 1 0 1.7891 -0.8946l-1-2a1.0001 1.0001 0 0 0 -0.89453 -0.5527h-3v-1h1c0.55401 0 1-0.446 1-1v-3c0-0.554-0.44599-1-1-1zm0 2h1v2h-1z" fill="#a5b7f3"/>
</svg>
diff --git a/editor/icons/icon_match_case.svg b/editor/icons/icon_match_case.svg
new file mode 100644
index 0000000000..2958933aca
--- /dev/null
+++ b/editor/icons/icon_match_case.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m4 1c-2.2091-6.6e-7 -4.069 1.7919-4 4v10h2v-4h4v4h2v-10c0-2.2091-1.7909-4-4-4zm5 11c0 1.6569 1.3431 3 3 3 0.3409-0.0014 0.67908-0.0608 1-0.17578v0.17578h2v-6c0-1.6569-1.3431-3-3-3h-1v2h1c0.55228 0 1 0.44772 1 1v0.17383c-0.32104-0.11432-0.65921-0.1731-1-0.17383-1.6569 0-3 1.3431-3 3zm-5-9c1.1046-1e-7 1.914 0.89879 2 2v4h-4v-4c0-1.1046 0.89543-2 2-2zm8 8c0.55228 0 1 0.44772 1 1s-0.44772 1-1 1-1-0.44772-1-1 0.44772-1 1-1z" fill="#e0e0e0" stroke-width="0"/>
+</svg>
diff --git a/editor/icons/icon_member_constant.svg b/editor/icons/icon_member_constant.svg
new file mode 100644
index 0000000000..0f8c6966c4
--- /dev/null
+++ b/editor/icons/icon_member_constant.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m10.135 3.002c-1.5244-0.04132-2.9843 0.61528-3.9648 1.7832-1.5607 1.8591-1.5607 4.5706 0 6.4297 1.5599 1.8584 4.229 2.3286 6.3301 1.1152l-1.0039-1.7363c-0.45449 0.26416-0.97042 0.40425-1.4961 0.40625-1.6569 0-3-1.3431-3-3-1e-7 -1.6569 1.3431-3 3-3 0.5255 0.0014061 1.0414 0.14082 1.4961 0.4043l1.0039-1.7344c-0.72056-0.41598-1.5335-0.64557-2.3652-0.66797zm-7.1348 7.998c-0.55228 0-1 0.44772-1 1-1e-7 0.55228 0.44772 1 1 1s1-0.44772 1-1c1e-7 -0.55228-0.44772-1-1-1z" fill="#e0e0e0" stroke-width="0"/>
+</svg>
diff --git a/editor/icons/icon_member_method.svg b/editor/icons/icon_member_method.svg
new file mode 100644
index 0000000000..57c93339b6
--- /dev/null
+++ b/editor/icons/icon_member_method.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m6.0215 3c-0.40133-0.0028518-0.79916 0.074854-1.1699 0.22852-1.1208 0.46444-1.8516 1.5582-1.8516 2.7715v7h2v-3h2v-2h-2v-2c0-0.55228 0.44772-1 1-1 0.2652 4.01e-5 0.51953 0.10542 0.70703 0.29297l1.4141-1.4141c-0.55724-0.5574-1.3115-0.87312-2.0996-0.87891zm2.9785 3c-1.3263 2.6586-1.3404 4.3252 0 7h2c-1.3404-2.6748-1.3263-4.3414 0-7h-2zm4 0c1.3263 2.6586 1.3404 4.3252 0 7h2c1.3404-2.6748 1.3263-4.3414 0-7h-2zm-12 5a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 -1 1 1 0 0 0 -1 -1z" fill="#e0e0e0" stroke-width="0"/>
+</svg>
diff --git a/editor/icons/icon_member_property.svg b/editor/icons/icon_member_property.svg
new file mode 100644
index 0000000000..918d0a64e9
--- /dev/null
+++ b/editor/icons/icon_member_property.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m7 4v9h2v-3h1c1.6569 0 3-1.3431 3-3s-1.3431-3-3-3zm2 2h1c0.55228 0 1 0.44772 1 1s-0.44798 0.98275-1 1h-1zm-5 5c-0.55228 0-1 0.44772-1 1-1e-7 0.55228 0.44772 1 1 1s1-0.44772 1-1c1e-7 -0.55228-0.44772-1-1-1z" fill="#e0e0e0" stroke-width="0"/>
+</svg>
diff --git a/editor/icons/icon_member_signal.svg b/editor/icons/icon_member_signal.svg
new file mode 100644
index 0000000000..2957cbbc50
--- /dev/null
+++ b/editor/icons/icon_member_signal.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m6 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1c4.4301 0 8 3.5699 8 8a1 1 0 0 0 1 1 1 1 0 0 0 1 -1c0-5.511-4.489-10-10-10zm0 4a1 1 0 0 0 -1 1 1 1 0 0 0 1 1c2.221 0 4 1.779 4 4a1 1 0 0 0 1 1 1 1 0 0 0 1 -1c0-3.3018-2.6981-6-6-6zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm-5 2c-0.55228 0-1 0.44772-1 1-1e-7 0.55228 0.44772 1 1 1s1-0.44772 1-1c1e-7 -0.55228-0.44772-1-1-1z" fill="#e0e0e0" stroke-width="0"/>
+</svg>
diff --git a/editor/icons/icon_member_theme.svg b/editor/icons/icon_member_theme.svg
new file mode 100644
index 0000000000..880450abae
--- /dev/null
+++ b/editor/icons/icon_member_theme.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g fill="#e0e0e0" stroke-width="0">
+<path d="m3 11c-0.55228 0-1 0.44772-1 1-1e-7 0.55228 0.44772 1 1 1s1-0.44772 1-1c1e-7 -0.55228-0.44772-1-1-1z"/>
+<path d="m10 2c-2.4 4-4 4.7909-4 7 0 2.2091 1.8297 4 4 4 2.1703 0 4-1.7909 4-4 0-2.2091-1.6-3-4-7z"/>
+</g>
+</svg>
diff --git a/editor/icons/icon_mini_basis.svg b/editor/icons/icon_mini_basis.svg
deleted file mode 100644
index 21b4f29aa4..0000000000
--- a/editor/icons/icon_mini_basis.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 2v4 4h2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3v-2h-2zm10 0v2h2v-2h-2zm-3 2a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324 -1 2 2 0 0 0 0 -2 2 2 0 0 0 -1.7324 -1h2v-2h-2zm7 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v-2h-2v4h2 2a2 2 0 0 0 1.7324 -1 2 2 0 0 0 0 -2 2 2 0 0 0 -1.7324 -1h2v-2h-2zm-12 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2z" fill="#e3ec69"/>
-<path d="m10 1042.4v2h2v-2zm0 4v4h2v-4z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_boolean.svg b/editor/icons/icon_mini_boolean.svg
deleted file mode 100644
index b1e169d73c..0000000000
--- a/editor/icons/icon_mini_boolean.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 2v4 4h2a3 3 0 0 0 2.5 -1.3457 3 3 0 0 0 2.5 1.3457 3 3 0 0 0 2 -0.76758 3 3 0 0 0 2 0.76758 3 3 0 0 0 2.5 -1.3457 3 3 0 0 0 2.5 1.3457v-2a1 1 0 0 1 -1 -1v-5h-2v2.7695a3 3 0 0 0 -2 -0.76953 3 3 0 0 0 -2 0.76758 3 3 0 0 0 -2 -0.76758 3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5 -1.3457v-2h-2zm2 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#8da6f0"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_color.svg b/editor/icons/icon_mini_color.svg
deleted file mode 100644
index 623f922158..0000000000
--- a/editor/icons/icon_mini_color.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m4 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1z" fill="#ff8484"/>
-<path transform="translate(0 1040.4)" d="m14 4a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v-2h-1z" fill="#84c2ff"/>
-<path transform="translate(0 1040.4)" d="m6 2v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-5h-2z" fill="#84ffb1"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_color_array.svg b/editor/icons/icon_mini_color_array.svg
deleted file mode 100644
index 2a5588a698..0000000000
--- a/editor/icons/icon_mini_color_array.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<rect y="1050.4" width="4" height="2" fill="#e0e0e0"/>
-<rect y="1040.4" width="2" height="12" fill="#e0e0e0"/>
-<rect y="1040.4" width="4" height="2" fill="#e0e0e0"/>
-<rect transform="scale(-1,1)" x="-16" y="1050.4" width="4" height="2" fill="#e0e0e0"/>
-<rect transform="scale(-1,1)" x="-16" y="1040.4" width="2" height="12" fill="#e0e0e0"/>
-<rect transform="scale(-1,1)" x="-16" y="1040.4" width="4" height="2" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m6 3.5a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1z" fill="#ff7070"/>
-<rect x="10" y="1046.9" width="2" height="3" fill="#70bfff"/>
-<path d="m13 1043.9a3 3 0 0 0 -3 3h2a1 1 0 0 1 1 -1v-2z" fill="#70bfff"/>
-<path transform="translate(0 1040.4)" d="m7 1.5v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5h-2z" fill="#7aff70"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_dictionary.svg b/editor/icons/icon_mini_dictionary.svg
deleted file mode 100644
index 814f27e2f9..0000000000
--- a/editor/icons/icon_mini_dictionary.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m3 2v2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-8h-2zm3 0v2h2v-2h-2zm7 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2zm-2 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1zm-3 3v-1h-2v4h2v-3zm-5-1v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#77edb1"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_float.svg b/editor/icons/icon_mini_float.svg
deleted file mode 100644
index 68f09ef07a..0000000000
--- a/editor/icons/icon_mini_float.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m3 2a3 3 0 0 0 -3 3v5h2v-2h2v-2h-2v-1a1 1 0 0 1 1 -1h1v-2h-1zm3 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-5h-2zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2h-2z" fill="#61daf4"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_float_array.svg b/editor/icons/icon_mini_float_array.svg
deleted file mode 100644
index 3e3c88cc99..0000000000
--- a/editor/icons/icon_mini_float_array.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 0v2 8 2h4v-2h-2v-8h2v-2h-2-2zm12 0v2h2v8h-2v2h4v-2-10h-4z" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1 -1v-2zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5h-2zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2z" fill="#61daf4"/>
-<path d="m7 1042.4v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5h-2z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_int_array.svg b/editor/icons/icon_mini_int_array.svg
deleted file mode 100644
index 04957c8d4b..0000000000
--- a/editor/icons/icon_mini_int_array.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 0v2 8 2h2 2v-2h-2v-8h2v-2h-4zm12 0v2h2v8h-2v2h4v-2-8-2h-2-2z" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m3 2v2h2v-2h-2zm2 2v2h-2v4h2 2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2v5z" fill="#7dc6ef"/>
-<path transform="translate(0 1040.4)" d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_integer.svg b/editor/icons/icon_mini_integer.svg
deleted file mode 100644
index 3bfe95980d..0000000000
--- a/editor/icons/icon_mini_integer.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m1 2v2h2v-2h-2zm11 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2h-2zm-8 2v6h2v-4h1a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-1-2zm-3 2v4h2v-4h-2z" fill="#7dc6ef"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_object.svg b/editor/icons/icon_mini_object.svg
index a59808b970..ffac2061c5 100644
--- a/editor/icons/icon_mini_object.svg
+++ b/editor/icons/icon_mini_object.svg
@@ -1,5 +1,3 @@
<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m6 2v5 3h2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3v-2h-2zm0 5a3 3 0 0 0 -3 -3 3 3 0 0 0 -3 3 3 3 0 0 0 3 3 3 3 0 0 0 3 -3zm7-3v5a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3 -3v-5h-2zm-10 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2z" fill="#79f3e8"/>
-</g>
+<path d="m6 2v8h2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3v-2zm0 5a3 3 0 0 0 -3 -3 3 3 0 0 0 -3 3 3 3 0 0 0 3 3 3 3 0 0 0 3 -3zm7-3v5a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3 -3v-5zm-10 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#79f3e8"/>
</svg>
diff --git a/editor/icons/icon_mini_path.svg b/editor/icons/icon_mini_path.svg
deleted file mode 100644
index 4c99ad8cc0..0000000000
--- a/editor/icons/icon_mini_path.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 2v8h2v-2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3h-2zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2h-2zm5 0v8h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3v-2h-2zm-9 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2z" fill="#6993ec"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_plane.svg b/editor/icons/icon_mini_plane.svg
deleted file mode 100644
index e02fded99f..0000000000
--- a/editor/icons/icon_mini_plane.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m1 2v8h2v-2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3h-2zm6 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5h-2zm-4 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2zm8 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2z" fill="#f77070"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_quat.svg b/editor/icons/icon_mini_quat.svg
deleted file mode 100644
index c705fae2b6..0000000000
--- a/editor/icons/icon_mini_quat.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m3 3a3 3 0 0 0 -3 3 3 3 0 0 0 3 3v2h2v-2.7695a3 3 0 0 0 2 0.76953h2v-6h-2v4a1 1 0 0 1 -1 -1v-3h-1-1-1zm0 2v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#ec69a3"/>
-<path d="m4 1043.4v3a3 3 0 0 0 3 3h2v-6h-2v4a1 1 0 0 1 -1 -1v-3z" fill="#fff" fill-opacity=".39216"/>
-<path transform="translate(0 1040.4)" d="m13 1v2h-2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2zm-2 4v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#ec69a3"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_raw_array.svg b/editor/icons/icon_mini_raw_array.svg
deleted file mode 100644
index ebd6c9a225..0000000000
--- a/editor/icons/icon_mini_raw_array.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 0v2 8 2h4v-2h-2v-8h2v-2h-2-2zm12 0v2h2v8h-2v2h4v-2-8-2h-2-2z" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m5 3a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v4h2a3 3 0 0 0 1 -0.17578v0.17578h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-1-3h-2v3a1 1 0 0 1 -1 1v-4h-2-1z" fill="#69ec9e"/>
-<path d="m6 1049.4v-6h2v4a1 1 0 0 0 1 -1v-3h2v3 1a1 1 0 0 0 1 -1v-3h2v3a3 3 0 0 1 -3 3h-2v-0.1758a3 3 0 0 1 -1 0.1758h-2z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_rect2.svg b/editor/icons/icon_mini_rect2.svg
deleted file mode 100644
index 9dec66dfa1..0000000000
--- a/editor/icons/icon_mini_rect2.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m13 2v2h-1a3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5 -1.3457 3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1h2 1a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v1a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v-2h-1z" fill="#f191a5"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_string.svg b/editor/icons/icon_mini_string.svg
deleted file mode 100644
index 17e565cd75..0000000000
--- a/editor/icons/icon_mini_string.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m5 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3 -3v-2a1 1 0 0 1 1 -1h1v-2h-1zm2 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2h-2zm8 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v-2h-1z" fill="#6ba7ec"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_string_array.svg b/editor/icons/icon_mini_string_array.svg
deleted file mode 100644
index af81cabce4..0000000000
--- a/editor/icons/icon_mini_string_array.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 0v2 8 2h2 2v-2h-2v-8h2v-2h-2-2zm12 0v2h2v8h-2v2h4v-2-10h-4z" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m7 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3 -3v-2a1 1 0 0 1 1 -1h1v3a3 3 0 0 0 3 3h2v-3a1 1 0 0 1 1 -1v-2a3 3 0 0 0 -3 3v1a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2-1z" fill="#6ba7ec"/>
-<path d="m8 1042.4v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_transform.svg b/editor/icons/icon_mini_transform.svg
deleted file mode 100644
index 53bad91efc..0000000000
--- a/editor/icons/icon_mini_transform.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 2l2 4-2 4h2l0.9082-2.1816 1.0918 2.1816h2l-2-4 2-4h-2l-0.9082 2.1816-1.0918-2.1816h-2zm6 8h2v-2h1v-2h-1v-1a1 1 0 0 1 1 -1h1v-2h-1a3 3 0 0 0 -3 3v5zm4-6v2 2 2h2v-2l1 1 1-1v2h2v-2-2-2h-2l-1 2-1-2h-2z" fill="#f6a86e"/>
-<path d="m9 1042.4a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1 -1h1v-2h-1z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_transform2D.svg b/editor/icons/icon_mini_transform2D.svg
deleted file mode 100644
index b4723d37c4..0000000000
--- a/editor/icons/icon_mini_transform2D.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 2v2h2v6h2v-6h2v-2h-6zm7 0v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.0019531v0.046875 1.9531h2 3 2a4 4 0 0 0 3.4648 -2 4 4 0 0 0 0 -4 4 4 0 0 0 -3.4648 -2h-2v6h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5zm5 2a2 2 0 0 1 1.7324 1 2 2 0 0 1 0 2 2 2 0 0 1 -1.7324 1v-4z" fill="#c4ec69"/>
-<path transform="translate(0 1040.4)" d="m7 2v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.0019531v0.046875 1.9531h2 3v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_variant.svg b/editor/icons/icon_mini_variant.svg
deleted file mode 100644
index 4b9a2a5f18..0000000000
--- a/editor/icons/icon_mini_variant.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m3 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6h-2zm3 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2zm5 3a3 3 0 0 0 3 3v2h2v-8h-2v4a1 1 0 0 1 -1 -1v-3h-2v3zm-8-1v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#69ecbd"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_vector2.svg b/editor/icons/icon_mini_vector2.svg
deleted file mode 100644
index 907e6ba84d..0000000000
--- a/editor/icons/icon_mini_vector2.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.001953v2h5v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5h-1zm-11 2v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#bd91f1"/>
-<path transform="translate(0 1040.4)" d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.001953v2h5v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5h-1z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_vector2_array.svg b/editor/icons/icon_mini_vector2_array.svg
deleted file mode 100644
index e05eefc46a..0000000000
--- a/editor/icons/icon_mini_vector2_array.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 0v2 10h2 2v-2h-2v-8h2v-2h-2-2zm12 0v2h2v8h-2v2h4v-2-10h-4z" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.0019531v0.046875 1.9531h2 3v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5h-1zm-6 1v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2z" fill="#bd91f1"/>
-<path d="m9 1042.4v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.00195v0.047 1.9531h2 3v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5001h-1z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_vector3.svg b/editor/icons/icon_mini_vector3.svg
deleted file mode 100644
index be1f8ec360..0000000000
--- a/editor/icons/icon_mini_vector3.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -0.36523 -0.50195 3 3 0 0 0 0.36523 -0.49805 3 3 0 0 0 0.39844 -1.5h0.003906v-2h-4zm-11 2v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#e286f0"/>
-<path transform="translate(0 1040.4)" d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -0.36523 -0.50195 3 3 0 0 0 0.36523 -0.49805 3 3 0 0 0 0.39844 -1.5h0.003906v-2h-4z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_mini_vector3_array.svg b/editor/icons/icon_mini_vector3_array.svg
deleted file mode 100644
index e2843d2e68..0000000000
--- a/editor/icons/icon_mini_vector3_array.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1040.4)">
-<path transform="translate(0 1040.4)" d="m0 0v2 8 2h4v-2h-2v-8h2v-2h-2-2zm12 0v2h2v8h-2v2h4v-2-10h-4z" fill="#e0e0e0"/>
-<path transform="translate(0 1040.4)" d="m8 1v2h1 1a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -0.36523 -0.50195 3 3 0 0 0 0.36523 -0.49805 3 3 0 0 0 0.39844 -1.5h0.003906v-2h-0.76562-2.2344-1zm0 2h-2v3a1 1 0 0 1 -1 1v-4h-2v6h2a3 3 0 0 0 3 -3v-3z" fill="#e286f0"/>
-<path transform="translate(0 1040.4)" d="m8 1v2h1 1a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -0.36523 -0.50195 3 3 0 0 0 0.36523 -0.49805 3 3 0 0 0 0.39844 -1.5h0.003906v-2h-0.76562-2.2344-1z" fill="#fff" fill-opacity=".39216"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_nil.svg b/editor/icons/icon_nil.svg
new file mode 100644
index 0000000000..b266161c2b
--- /dev/null
+++ b/editor/icons/icon_nil.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m8 2v2h2v-2zm4 0v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-0.55228-9.6e-6 -0.99999-0.44772-1-1v-5zm-11 2v6h2v-4h1c0.55228 9.6e-6 0.99999 0.44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3zm7 2v4h2v-4z" fill="#e0e0e0"/>
+</svg>
diff --git a/editor/icons/icon_node_path.svg b/editor/icons/icon_node_path.svg
new file mode 100644
index 0000000000..1697c026a3
--- /dev/null
+++ b/editor/icons/icon_node_path.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 2v8h2v-2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3h-2zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2h-2zm5 0v8h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3v-2h-2zm-9 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2z" fill="#6993ec"/>
+</svg>
diff --git a/editor/icons/icon_plane.svg b/editor/icons/icon_plane.svg
index d0525e13dc..e02fded99f 100644
--- a/editor/icons/icon_plane.svg
+++ b/editor/icons/icon_plane.svg
@@ -1,5 +1,5 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path d="m1 1044.4 7 3 7-3-7-3z" fill="#e0e0e0" fill-rule="evenodd"/>
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1040.4)">
+<path transform="translate(0 1040.4)" d="m1 2v8h2v-2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3h-2zm6 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5h-2zm-4 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2zm8 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2z" fill="#f77070"/>
</g>
</svg>
diff --git a/editor/icons/icon_pool_byte_array.svg b/editor/icons/icon_pool_byte_array.svg
new file mode 100644
index 0000000000..29d6bfe4f0
--- /dev/null
+++ b/editor/icons/icon_pool_byte_array.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 0v12h4v-2h-2v-8h2v-2h-2zm12 0v2h2v8h-2v2h4v-12h-2z" fill="#e0e0e0"/>
+<path d="m5 3a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v4h2a3 3 0 0 0 1 -0.17578v0.17578h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2v3a1 1 0 0 1 -1 1v-4h-2z" fill="#69ec9e"/>
+<path d="m6 9v-6h2v4a1 1 0 0 0 1 -1v-3h2v4a1 1 0 0 0 1 -1v-3h2v3a3 3 0 0 1 -3 3h-2v-0.1758a3 3 0 0 1 -1 0.1758z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_pool_color_array.svg b/editor/icons/icon_pool_color_array.svg
new file mode 100644
index 0000000000..dcce58f9c6
--- /dev/null
+++ b/editor/icons/icon_pool_color_array.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<g>
+<path d="m0 0v12h4v-2h-2v-8h2v-2h-4zm12 0v2h2v8h-2v2h4v-12h-4z" fill="#e0e0e0"/>
+<path d="m6 3.5a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2z" fill="#ff7070"/>
+<path d="m13 3.5a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1z" fill="#70bfff"/>
+<path d="m7 1.5v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5z" fill="#7aff70"/>
+</g>
+</svg>
diff --git a/editor/icons/icon_pool_int_array.svg b/editor/icons/icon_pool_int_array.svg
new file mode 100644
index 0000000000..d59f9e1531
--- /dev/null
+++ b/editor/icons/icon_pool_int_array.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/>
+<path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2z" fill="#7dc6ef"/>
+<path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_pool_real_array.svg b/editor/icons/icon_pool_real_array.svg
new file mode 100644
index 0000000000..78a8064611
--- /dev/null
+++ b/editor/icons/icon_pool_real_array.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/>
+<path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1 -1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2z" fill="#61daf4"/>
+<path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-5z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_pool_string_array.svg b/editor/icons/icon_pool_string_array.svg
new file mode 100644
index 0000000000..401bfe6145
--- /dev/null
+++ b/editor/icons/icon_pool_string_array.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/>
+<path d="m7 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3 -3v-2a1 1 0 0 1 1 -1h1v3a3 3 0 0 0 3 3h2v-3a1 1 0 0 1 1 -1v-2a3 3 0 0 0 -3 3v1a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2h-2z" fill="#6ba7ec"/>
+<path d="m8 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_pool_vector2_array.svg b/editor/icons/icon_pool_vector2_array.svg
new file mode 100644
index 0000000000..bb089a26ef
--- /dev/null
+++ b/editor/icons/icon_pool_vector2_array.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/>
+<path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.0019531v2h5v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5zm-6 1v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#bd91f1"/>
+<path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.00195v2.0001h5v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5001z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_pool_vector3_array.svg b/editor/icons/icon_pool_vector3_array.svg
new file mode 100644
index 0000000000..4f69183e30
--- /dev/null
+++ b/editor/icons/icon_pool_vector3_array.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/>
+<path d="m8 1v2h2c0 0.55228-0.44772 1-1 1v2c0.55228 0 1 0.44772 1 1s-0.44772 1-1 1h-1v2h1c1.0716-1.501e-4 2.0618-0.57193 2.5977-1.5 0.5359-0.9282 0.5359-2.0718 0-3-0.10406-0.1795-0.22646-0.34772-0.36523-0.50195 0.13856-0.15301 0.26095-0.31991 0.36523-0.49805 0.26209-0.45639 0.3995-0.97371 0.39844-1.5h0.003906v-2zm0 2h-2v3c-9.6e-6 0.55228-0.44772 0.99999-1 1v-4h-2v6h2c1.6569 0 3-1.3431 3-3z" fill="#e286f0"/>
+<path d="m8 1v2h2c0 0.55228-0.44772 1-1 1v2c0.55228 0 1 0.44772 1 1s-0.44772 1-1 1h-1v2h1c1.0716-1.501e-4 2.0618-0.57193 2.5977-1.5 0.5359-0.9282 0.5359-2.0718 0-3-0.10406-0.1795-0.22646-0.34772-0.36523-0.50195 0.13856-0.15301 0.26095-0.31991 0.36523-0.49805 0.26209-0.45639 0.3995-0.97371 0.39844-1.5h0.003906v-2z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_quat.svg b/editor/icons/icon_quat.svg
index fc99c33aeb..07433920a1 100644
--- a/editor/icons/icon_quat.svg
+++ b/editor/icons/icon_quat.svg
@@ -1,5 +1,5 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7 1v6h2v-6h-2zm4 2.3906v2.0137a5 2 0 0 1 2 1.5957 5 2 0 0 1 -5 2 5 2 0 0 1 -5 -2 5 2 0 0 1 2 -1.5977v-2.0098a7 4 0 0 0 -4 3.6074 7 4 0 0 0 7 4 7 4 0 0 0 7 -4 7 4 0 0 0 -4 -3.6094zm-4 9.6094v2h2v-2h-2z" fill="#e0e0e0"/>
-</g>
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m3 3a3 3 0 0 0 -3 3 3 3 0 0 0 3 3v2h2v-2.7695a3 3 0 0 0 2 0.76953h2v-6h-2v4a1 1 0 0 1 -1 -1v-3h-2zm0 2v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#ec69a3"/>
+<path d="m4 3v3a3 3 0 0 0 3 3h2v-6h-2v4a1 1 0 0 1 -1 -1v-3z" fill="#fff" fill-opacity=".39216"/>
+<path d="m13 1v2h-2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2zm-2 4v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#ec69a3"/>
</svg>
diff --git a/editor/icons/icon_mini_rid.svg b/editor/icons/icon_r_i_d.svg
index f1709a5acc..f1709a5acc 100644
--- a/editor/icons/icon_mini_rid.svg
+++ b/editor/icons/icon_r_i_d.svg
diff --git a/editor/icons/icon_range.svg b/editor/icons/icon_range.svg
deleted file mode 100644
index 4bf0170e55..0000000000
--- a/editor/icons/icon_range.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m1 3v10h2v-4h2v2h2v-2h2v2h2v-2h2v4h2v-10h-2v4h-2v-2h-2v2h-2v-2h-2v2h-2v-4z" fill="#a5efac"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_rect2.svg b/editor/icons/icon_rect2.svg
new file mode 100644
index 0000000000..05d1022e5b
--- /dev/null
+++ b/editor/icons/icon_rect2.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m13 2v2h-1a3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5 -1.3457 3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1h3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v1a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1 -1v-1h1v-2h-1v-2zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v-2z" fill="#f191a5"/>
+</svg>
diff --git a/editor/icons/icon_scroll_bar.svg b/editor/icons/icon_scroll_bar.svg
deleted file mode 100644
index c58c31464d..0000000000
--- a/editor/icons/icon_scroll_bar.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m3 3c-1.1046 0-2 0.89543-2 2v6c0 1.1046 0.89543 2 2 2h10c1.1046 0 2-0.89543 2-2v-6c0-1.1046-0.89543-2-2-2h-10zm0 2h10v6h-10v-6zm1 1v4h4v-4h-4z" fill="#a5efac"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_string.svg b/editor/icons/icon_string.svg
new file mode 100644
index 0000000000..6618f3b7f9
--- /dev/null
+++ b/editor/icons/icon_string.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m5 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3 -3v-2a1 1 0 0 1 1 -1h1v-2zm2 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1v-1h2v-2h-2v-2zm8 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1 -1h1v-2z" fill="#6ba7ec"/>
+</svg>
diff --git a/editor/icons/icon_theme.svg b/editor/icons/icon_theme.svg
index 3dfb4aaa00..f44529c4cb 100644
--- a/editor/icons/icon_theme.svg
+++ b/editor/icons/icon_theme.svg
@@ -1,11 +1,11 @@
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7 1l-0.5 2h3l-0.5-2h-2zm-3.2422 1.3438l-0.65625 0.65625h1.75l-1.0938-0.65625zm8.4844 0l-1.0957 0.65625h1.752l-0.65625-0.65625z" fill="#ff7070"/>
-<path transform="translate(0 1036.4)" d="m3.1016 3l-0.75781 0.75781 0.74414 1.2422h9.8242l0.74414-1.2422-0.75781-0.75781h-1.752l-0.89844 0.53906a5 5 0 0 0 -0.68555 -0.28516l-0.0625-0.25391h-3l-0.064453 0.25781a5 5 0 0 0 -0.68945 0.2793l-0.89453-0.53711h-1.75z" fill="#ffeb70"/>
-<path transform="translate(0 1036.4)" d="m3.0879 5l0.45117 0.75195a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625h5.2695a2 2 0 0 1 1.7305 -1 2 2 0 0 1 1.7285 1h5.2715l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l0.44922-0.74805h-9.8242z" fill="#9dff70"/>
-<path transform="translate(0 1036.4)" d="m1 7v2h5.2715a2 2 0 0 1 -0.27148 -1 2 2 0 0 1 0.26953 -1h-5.2695zm8.7285 0a2 2 0 0 1 0.27148 1 2 2 0 0 1 -0.26953 1h5.2695v-2h-5.2715z" fill="#70ffb9"/>
-<path transform="translate(0 1036.4)" d="m1 9l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-0.44922 0.74805h9.8242l-0.45117-0.75195a5 5 0 0 0 0.28516 -0.68555l2.2539-0.5625h-5.2695a2 2 0 0 1 -1.7305 1 2 2 0 0 1 -1.7285 -1h-5.2715z" fill="#70deff"/>
-<path transform="translate(0 1036.4)" d="m3.1016 13l0.65625 0.65625 1.0957-0.65625h-1.752zm3.3984 0l0.5 2h2l0.5-2h-3zm4.6484 0l1.0938 0.65625 0.65625-0.65625h-1.75z" fill="#ff70ac"/>
-<path transform="translate(0 1036.4)" d="m3.0879 11l-0.74414 1.2422 0.75781 0.75781h1.752l0.89844-0.53906a5 5 0 0 0 0.68555 0.28516l0.0625 0.25391h3l0.064453-0.25781a5 5 0 0 0 0.6875 -0.2793l0.89648 0.53711h1.75l0.75781-0.75781-0.74414-1.2422h-9.8242z" fill="#9f70ff"/>
+<g transform="translate(0 -1036.4)" stroke-width="0">
+<path transform="translate(0 1036.4)" d="m6.7246 3c-0.52985 0.78935-0.96267 1.4021-1.3945 2h5.3398c-0.43187-0.59786-0.86468-1.2107-1.3945-2h-2.5508z" fill="#ffeb70"/>
+<path transform="translate(0 1036.4)" d="m5.3301 5c-0.52617 0.72841-1.0198 1.4208-1.375 2h8.0898c-0.35516-0.57924-0.84883-1.2716-1.375-2h-5.3398z" fill="#9dff70"/>
+<path transform="translate(0 1036.4)" d="m3.9551 7c-0.41451 0.67603-0.71534 1.3082-0.85547 2h9.8008c-0.14013-0.69181-0.44096-1.324-0.85547-2h-8.0898z" fill="#70ffb9"/>
+<path transform="translate(0 1036.4)" d="m3.0996 9c-0.063989 0.3159-0.099609 0.64498-0.099609 1 0 0.34242 0.034776 0.67693 0.10156 1h9.7969c0.066786-0.32307 0.10156-0.65758 0.10156-1 0-0.35502-0.03562-0.6841-0.099609-1h-9.8008z" fill="#70deff"/>
+<path transform="translate(0 1036.4)" d="m3.1016 11c0.15381 0.74405 0.48967 1.4159 0.93555 2h7.9258c0.44588-0.5841 0.78173-1.2559 0.93555-2h-9.7969z" fill="#9f70ff"/>
+<path transform="translate(0 1036.4)" d="m4.0371 13c0.9218 1.2076 2.3612 2 3.9629 2s3.0411-0.79243 3.9629-2h-7.9258z" fill="#ff70ac"/>
+<path transform="translate(0 1036.4)" d="m8 1c-0.45196 0.75327-0.87224 1.3994-1.2754 2h2.5508c-0.40315-0.6006-0.82343-1.2467-1.2754-2z" fill="#ff7070"/>
</g>
</svg>
diff --git a/editor/icons/icon_transform.svg b/editor/icons/icon_transform.svg
new file mode 100644
index 0000000000..7645622c28
--- /dev/null
+++ b/editor/icons/icon_transform.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 2 2 4-2 4h2l0.9082-2.1816 1.0918 2.1816h2l-2-4 2-4h-2l-0.9082 2.1816-1.0918-2.1816zm6 8h2v-2h1v-2h-1v-1c9.6e-6 -0.55228 0.44772-0.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3zm4-6v6h2v-2l1 1 1-1v2h2v-6h-2l-1 2-1-2z" fill="#f6a86e"/>
+<path d="m9 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1 -1h1v-2z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_transform_2_D.svg b/editor/icons/icon_transform_2_D.svg
new file mode 100644
index 0000000000..de05160dac
--- /dev/null
+++ b/editor/icons/icon_transform_2_D.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m0 2v2h2v6h2v-6h2v-2zm7 0v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.0019531v2h7a4 4 0 0 0 3.4648 -2 4 4 0 0 0 0 -4 4 4 0 0 0 -3.4648 -2h-2v6h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5zm5 2a2 2 0 0 1 1.7324 1 2 2 0 0 1 0 2 2 2 0 0 1 -1.7324 1z" fill="#c4ec69"/>
+<path d="m7 2v2c0.55228 0 1 0.44772 1 1s-0.44772 1-1 1c-0.71466-1.326e-4 -1.3751 0.38108-1.7324 1-0.17472 0.30426-0.26633 0.64914-0.26562 1h-0.0019531v2h5v-2h-3c1.0716-1.5e-4 2.0618-0.57193 2.5977-1.5 0.5359-0.9282 0.5359-2.0718 0-3-0.53582-0.92807-1.526-1.4998-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_variant.svg b/editor/icons/icon_variant.svg
index 32f72b1ce6..859578243c 100644
--- a/editor/icons/icon_variant.svg
+++ b/editor/icons/icon_variant.svg
@@ -1,16 +1,3 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<g transform="translate(0,-3)" fill="#e0e0e0">
-<rect x="3" y="1044.4" width="2" height="6"/>
-<rect x="6" y="1044.4" width="2" height="6"/>
-<rect x="3" y="1044.4" width="1" height="2"/>
-<path d="m3 1044.4a3 3 0 0 0 -3 3h2a1 1 0 0 1 1 -1z"/>
-<path d="m14 1050.4a3 3 0 0 1 -3 -3h2a1 1 0 0 0 1 1z"/>
-<rect transform="scale(1,-1)" x="14" y="-1052.4" width="2" height="8"/>
-<rect transform="scale(1,-1)" x="11" y="-1047.4" width="2" height="3"/>
-<path d="m3 1050.4a3 3 0 0 1 -3 -3h2a1 1 0 0 0 1 1z"/>
-<path d="m8 1044.4a3 3 0 0 1 3 3h-2a1 1 0 0 0 -1 -1z"/>
-<rect x="9" y="1047.4" width="2" height="3"/>
-</g>
-</g>
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m3 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm3 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3zm5 3a3 3 0 0 0 3 3v2h2v-8h-2v4a1 1 0 0 1 -1 -1v-3h-2zm-8-1v2a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#69ecbd"/>
</svg>
diff --git a/editor/icons/icon_vector2.svg b/editor/icons/icon_vector2.svg
new file mode 100644
index 0000000000..9fa798df5d
--- /dev/null
+++ b/editor/icons/icon_vector2.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.001953v2h5v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5zm-11 2v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#bd91f1"/>
+<path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -0.26562 1h-0.001953v2h5v-2h-3a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -2.5977 -1.5z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/icons/icon_vector3.svg b/editor/icons/icon_vector3.svg
new file mode 100644
index 0000000000..cf1d0d0136
--- /dev/null
+++ b/editor/icons/icon_vector3.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="12" version="1.1" viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
+<path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -0.36523 -0.50195 3 3 0 0 0 0.36523 -0.49805 3 3 0 0 0 0.39844 -1.5h0.003906v-2zm-11 2v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#e286f0"/>
+<path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977 -1.5 3 3 0 0 0 0 -3 3 3 0 0 0 -0.36523 -0.50195 3 3 0 0 0 0.36523 -0.49805 3 3 0 0 0 0.39844 -1.5h0.003906v-2z" fill="#fff" fill-opacity=".39216"/>
+</svg>
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 019e32f847..d70f41d2e0 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -1348,14 +1348,14 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
if (SpatialEditor::get_singleton()->is_visible()) {
// 3D
spatial_edit_state = SpatialEditor::get_singleton()->get_state();
- Dictionary new_state = spatial_edit_state.copy();
+ Dictionary new_state = spatial_edit_state.duplicate();
new_state["show_grid"] = false;
new_state["show_origin"] = false;
Array orig_vp = spatial_edit_state["viewports"];
Array vp;
vp.resize(4);
for (int i = 0; i < vp.size(); i++) {
- Dictionary d = ((Dictionary)orig_vp[i]).copy();
+ Dictionary d = ((Dictionary)orig_vp[i]).duplicate();
d["use_environment"] = false;
d["doppler"] = false;
d["gizmos"] = onion.include_gizmos ? d["gizmos"] : Variant(false);
@@ -1368,7 +1368,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
} else { // CanvasItemEditor
// 2D
canvas_edit_state = CanvasItemEditor::get_singleton()->get_state();
- Dictionary new_state = canvas_edit_state.copy();
+ Dictionary new_state = canvas_edit_state.duplicate();
new_state["show_grid"] = false;
new_state["show_rulers"] = false;
new_state["show_guides"] = false;
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index 2c2e5a7c9b..e02925e377 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -188,6 +188,9 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p
cancel_hb->raise();
cancelled = false;
_popup();
+ if (p_can_cancel) {
+ cancel->grab_focus();
+ }
}
bool ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) {
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 1a7b7f3575..6f8573cd70 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -1690,13 +1690,13 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0);
vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
- l = memnew(Label);
- vbc->add_child(l);
- l->set_text(TTR("Action:"));
-
hbc = memnew(HBoxContainer);
vbc->add_child(hbc);
+ l = memnew(Label);
+ hbc->add_child(l);
+ l->set_text(TTR("Action:"));
+
action_name = memnew(LineEdit);
action_name->set_h_size_flags(SIZE_EXPAND_FILL);
hbc->add_child(action_name);
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 623b0e15ab..47feac9a12 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -4599,7 +4599,7 @@ SectionedPropertyEditor::SectionedPropertyEditor() {
sections->set_v_size_flags(SIZE_EXPAND_FILL);
sections->set_hide_root(true);
- left_vb->add_margin_child(TTR("Sections:"), sections, true);
+ left_vb->add_child(sections, true);
VBoxContainer *right_vb = memnew(VBoxContainer);
right_vb->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -4608,7 +4608,7 @@ SectionedPropertyEditor::SectionedPropertyEditor() {
filter = memnew(SectionedPropertyEditorFilter);
editor = memnew(PropertyEditor);
editor->set_v_size_flags(SIZE_EXPAND_FILL);
- right_vb->add_margin_child(TTR("Properties:"), editor, true);
+ right_vb->add_child(editor, true);
editor->get_scene_tree()->set_column_titles_visible(false);
diff --git a/editor/property_editor.h b/editor/property_editor.h
index f684f5768d..115ce07339 100644
--- a/editor/property_editor.h
+++ b/editor/property_editor.h
@@ -314,9 +314,9 @@ public:
class SectionedPropertyEditorFilter;
-class SectionedPropertyEditor : public HBoxContainer {
+class SectionedPropertyEditor : public HSplitContainer {
- GDCLASS(SectionedPropertyEditor, HBoxContainer);
+ GDCLASS(SectionedPropertyEditor, HSplitContainer);
ObjectID obj;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 4d5d467857..6fbca5c904 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1699,12 +1699,11 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
icon = get_icon("Object", "EditorIcons");
if (menu->get_item_count() == 0) {
- menu->add_item(TTR("Sub-Resources:"));
- menu->set_item_disabled(0, true);
+ menu->add_submenu_item(TTR("Sub-Resources:"), "Sub-Resources");
}
- int index = menu->get_item_count();
- menu->add_icon_item(icon, E->get().name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
- menu->set_item_h_offset(index, p_depth * 10 * EDSCALE);
+ int index = menu_subresources->get_item_count();
+ menu_subresources->add_icon_item(icon, E->get().name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
+ menu_subresources->set_item_h_offset(index, p_depth * 10 * EDSCALE);
subresources.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
@@ -2049,6 +2048,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("id_pressed", this, "_tool_selected");
+ menu_subresources = memnew(PopupMenu);
+ menu_subresources->set_name("Sub-Resources");
+ menu->add_child(menu_subresources);
first_enter = true;
restore_script_editor_on_drag = false;
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 41d5bda180..6a281bb7e8 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -119,6 +119,7 @@ class SceneTreeDock : public VBoxContainer {
TextureRect *filter_icon;
PopupMenu *menu;
+ PopupMenu *menu_subresources;
ConfirmationDialog *clear_inherit_confirm;
bool first_enter;
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index fccd0c51aa..2bdc824248 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -100,6 +100,8 @@ void EditorSettingsDialog::popup_edit_settings() {
} else {
popup_centered_ratio(0.7);
}
+
+ _focus_current_search_box();
}
void EditorSettingsDialog::_clear_search_box() {
@@ -137,13 +139,18 @@ void EditorSettingsDialog::_notification(int p_what) {
undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
} break;
case NOTIFICATION_ENTER_TREE: {
- clear_button->set_icon(get_icon("Close", "EditorIcons"));
- shortcut_clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ _update_icons();
} break;
case NOTIFICATION_POPUP_HIDE: {
EditorSettings::get_singleton()->set("interface/dialogs/editor_settings_bounds", get_rect());
set_process_unhandled_input(false);
} break;
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ _update_icons();
+ // Update theme colors.
+ property_editor->update_category_list();
+ _update_shortcuts();
+ } break;
}
}
@@ -179,6 +186,14 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
}
}
+void EditorSettingsDialog::_update_icons() {
+
+ search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ shortcut_search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ shortcut_clear_button->set_icon(get_icon("Close", "EditorIcons"));
+}
+
void EditorSettingsDialog::_update_shortcuts() {
shortcuts->clear();
@@ -329,6 +344,26 @@ void EditorSettingsDialog::_press_a_key_confirm() {
undo_redo->commit_action();
}
+void EditorSettingsDialog::_tabs_tab_changed(int p_tab) {
+
+ _focus_current_search_box();
+}
+
+void EditorSettingsDialog::_focus_current_search_box() {
+
+ Control *tab = tabs->get_current_tab_control();
+ LineEdit *current_search_box;
+ if (tab == tab_general)
+ current_search_box = search_box;
+ else if (tab == tab_shortcuts)
+ current_search_box = shortcut_search_box;
+
+ if (current_search_box) {
+ current_search_box->grab_focus();
+ current_search_box->select_all();
+ }
+}
+
void EditorSettingsDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_input"), &EditorSettingsDialog::_unhandled_input);
@@ -342,6 +377,7 @@ void EditorSettingsDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts);
ClassDB::bind_method(D_METHOD("_press_a_key_confirm"), &EditorSettingsDialog::_press_a_key_confirm);
ClassDB::bind_method(D_METHOD("_wait_for_key"), &EditorSettingsDialog::_wait_for_key);
+ ClassDB::bind_method(D_METHOD("_tabs_tab_changed"), &EditorSettingsDialog::_tabs_tab_changed);
}
EditorSettingsDialog::EditorSettingsDialog() {
@@ -352,20 +388,19 @@ EditorSettingsDialog::EditorSettingsDialog() {
tabs = memnew(TabContainer);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
+ tabs->connect("tab_changed", this, "_tabs_tab_changed");
add_child(tabs);
//set_child_rect(tabs);
- VBoxContainer *vbc = memnew(VBoxContainer);
- tabs->add_child(vbc);
- vbc->set_name(TTR("General"));
+ // General Tab
+
+ tab_general = memnew(VBoxContainer);
+ tabs->add_child(tab_general);
+ tab_general->set_name(TTR("General"));
HBoxContainer *hbc = memnew(HBoxContainer);
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- vbc->add_child(hbc);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Search:") + " ");
- hbc->add_child(l);
+ tab_general->add_child(hbc);
search_box = memnew(LineEdit);
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -381,20 +416,18 @@ EditorSettingsDialog::EditorSettingsDialog() {
property_editor->register_search_box(search_box);
property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
property_editor->get_property_editor()->set_undo_redo(undo_redo);
- vbc->add_child(property_editor);
+ tab_general->add_child(property_editor);
property_editor->get_property_editor()->connect("property_edited", this, "_settings_property_edited");
- vbc = memnew(VBoxContainer);
- tabs->add_child(vbc);
- vbc->set_name(TTR("Shortcuts"));
+ // Shortcuts Tab
+
+ tab_shortcuts = memnew(VBoxContainer);
+ tabs->add_child(tab_shortcuts);
+ tab_shortcuts->set_name(TTR("Shortcuts"));
hbc = memnew(HBoxContainer);
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- vbc->add_child(hbc);
-
- l = memnew(Label);
- l->set_text(TTR("Search:") + " ");
- hbc->add_child(l);
+ tab_shortcuts->add_child(hbc);
shortcut_search_box = memnew(LineEdit);
shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -406,7 +439,8 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcut_clear_button->connect("pressed", this, "_clear_shortcut_search_box");
shortcuts = memnew(Tree);
- vbc->add_margin_child(TTR("Shortcut List:"), shortcuts, true);
+ tab_shortcuts->add_child(shortcuts, true);
+ shortcuts->set_v_size_flags(SIZE_EXPAND_FILL);
shortcuts->set_columns(2);
shortcuts->set_hide_root(true);
//shortcuts->set_hide_folding(true);
@@ -419,7 +453,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
press_a_key->set_focus_mode(FOCUS_ALL);
add_child(press_a_key);
- l = memnew(Label);
+ Label *l = memnew(Label);
l->set_text(TTR("Press a Key.."));
l->set_anchors_and_margins_preset(Control::PRESET_WIDE);
l->set_align(Label::ALIGN_CENTER);
diff --git a/editor/settings_config_dialog.h b/editor/settings_config_dialog.h
index a03b15c06d..64b8833821 100644
--- a/editor/settings_config_dialog.h
+++ b/editor/settings_config_dialog.h
@@ -41,6 +41,8 @@ class EditorSettingsDialog : public AcceptDialog {
bool updating;
TabContainer *tabs;
+ Control *tab_general;
+ Control *tab_shortcuts;
LineEdit *search_box;
LineEdit *shortcut_search_box;
@@ -68,10 +70,14 @@ class EditorSettingsDialog : public AcceptDialog {
void _unhandled_input(const Ref<InputEvent> &p_event);
void _notification(int p_what);
+ void _update_icons();
void _press_a_key_confirm();
void _wait_for_key(const Ref<InputEvent> &p_event);
+ void _tabs_tab_changed(int p_tab);
+ void _focus_current_search_box();
+
void _clear_shortcut_search_box();
void _clear_search_box();
diff --git a/main/main.cpp b/main/main.cpp
index ab520c5e7f..b53e9ef0f7 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1448,6 +1448,9 @@ bool Main::start() {
bool snap_controls = GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
sml->get_root()->set_snap_controls_to_pixels(snap_controls);
+ bool font_oversampling = GLOBAL_DEF("rendering/quality/dynamic_fonts/use_oversampling", false);
+ sml->set_use_font_oversampling(font_oversampling);
+
} else {
GLOBAL_DEF("display/window/stretch/mode", "disabled");
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport"));
@@ -1458,6 +1461,7 @@ bool Main::start() {
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
+ GLOBAL_DEF("rendering/quality/dynamic_fonts/use_oversampling", false);
}
String local_game_path;
diff --git a/methods.py b/methods.py
index e861303e63..f9da6c8dd5 100644
--- a/methods.py
+++ b/methods.py
@@ -1755,16 +1755,16 @@ def precious_program(env, program, sources, **args):
return program
def add_shared_library(env, name, sources, **args):
- library = env.SharedLibrary(name, sources, **args)
- env.NoCache(library)
- return library
+ library = env.SharedLibrary(name, sources, **args)
+ env.NoCache(library)
+ return library
def add_library(env, name, sources, **args):
- library = env.Library(name, sources, **args)
- env.NoCache(library)
- return library
+ library = env.Library(name, sources, **args)
+ env.NoCache(library)
+ return library
def add_program(env, name, sources, **args):
- program = env.Program(name, sources, **args)
- env.NoCache(program)
- return program
+ program = env.Program(name, sources, **args)
+ env.NoCache(program)
+ return program
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index fd11c8d094..4e73ebfb9d 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -3,12 +3,12 @@
Import('env')
gdn_env = env.Clone()
-
-gdn_env.add_source_files(env.modules_sources, "gd_native_library_editor.cpp")
gdn_env.add_source_files(env.modules_sources, "gdnative.cpp")
gdn_env.add_source_files(env.modules_sources, "register_types.cpp")
gdn_env.add_source_files(env.modules_sources, "gdnative/*.cpp")
gdn_env.add_source_files(env.modules_sources, "nativescript/*.cpp")
+gdn_env.add_source_files(env.modules_sources, "gdnative_library_singleton_editor.cpp")
+gdn_env.add_source_files(env.modules_sources, "gdnative_library_editor_plugin.cpp")
gdn_env.Append(CPPPATH=['#modules/gdnative/include/'])
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
new file mode 100644
index 0000000000..1e638ab702
--- /dev/null
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -0,0 +1,423 @@
+/*************************************************************************/
+/* gdnative_library_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+#include "gdnative_library_editor_plugin.h"
+#include "gdnative.h"
+
+void GDNativeLibraryEditor::edit(Ref<GDNativeLibrary> p_library) {
+ library = p_library;
+ Ref<ConfigFile> config = p_library->get_config_file();
+
+ for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
+ for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) {
+
+ String target = E->key() + "." + it->get();
+ TargetConfig ecfg;
+ ecfg.library = config->get_value("entry", target, "");
+ ecfg.dependencies = config->get_value("dependencies", target, Array());
+ entry_configs[target] = ecfg;
+ }
+ }
+
+ _update_tree();
+}
+
+void GDNativeLibraryEditor::_bind_methods() {
+
+ ClassDB::bind_method("_on_item_button", &GDNativeLibraryEditor::_on_item_button);
+ ClassDB::bind_method("_on_library_selected", &GDNativeLibraryEditor::_on_library_selected);
+ ClassDB::bind_method("_on_dependencies_selected", &GDNativeLibraryEditor::_on_dependencies_selected);
+ ClassDB::bind_method("_on_filter_selected", &GDNativeLibraryEditor::_on_filter_selected);
+ ClassDB::bind_method("_on_item_collapsed", &GDNativeLibraryEditor::_on_item_collapsed);
+ ClassDB::bind_method("_on_item_activated", &GDNativeLibraryEditor::_on_item_activated);
+ ClassDB::bind_method("_on_create_new_entry", &GDNativeLibraryEditor::_on_create_new_entry);
+}
+
+void GDNativeLibraryEditor::_update_tree() {
+
+ tree->clear();
+ TreeItem *root = tree->create_item();
+
+ for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
+
+ if (showing_platform != E->key() && showing_platform != "All")
+ continue;
+
+ TreeItem *platform = tree->create_item(root);
+ platform->set_text(0, E->get().name);
+ platform->set_metadata(0, E->get().library_extension);
+
+ platform->set_custom_bg_color(0, get_color("prop_category", "Editor"));
+ platform->set_custom_bg_color(1, get_color("prop_category", "Editor"));
+ platform->set_custom_bg_color(2, get_color("prop_category", "Editor"));
+ platform->set_selectable(0, false);
+ platform->set_expand_right(0, true);
+
+ for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) {
+
+ String target = E->key() + "." + it->get();
+ TreeItem *bit = tree->create_item(platform);
+
+ bit->set_text(0, it->get());
+ bit->set_metadata(0, target);
+ bit->set_selectable(0, false);
+ bit->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
+
+ bit->add_button(1, get_icon("Folder", "EditorIcons"), BUTTON_SELECT_LIBRARY, false, TTR("Select the dynamic library for this entry"));
+ String file = entry_configs[target].library;
+ if (!file.empty()) {
+ bit->add_button(1, get_icon("Clear", "EditorIcons"), BUTTON_CLEAR_LIBRARY, false, TTR("Clear"));
+ }
+ bit->set_text(1, file);
+
+ bit->add_button(2, get_icon("Folder", "EditorIcons"), BUTTON_SELECT_DEPENDENCES, false, TTR("Select dependencies of the library for this entry"));
+ Array files = entry_configs[target].dependencies;
+ if (files.size()) {
+ bit->add_button(2, get_icon("Clear", "EditorIcons"), BUTTON_CLEAR_DEPENDENCES, false, TTR("Clear"));
+ }
+ bit->set_text(2, Variant(files));
+
+ bit->add_button(3, get_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP, false, TTR("Move Up"));
+ bit->add_button(3, get_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN, false, TTR("Move Down"));
+ bit->add_button(3, get_icon("Remove", "EditorIcons"), BUTTON_ERASE_ENTRY, false, TTR("Remove current entry"));
+ }
+
+ TreeItem *new_arch = tree->create_item(platform);
+ new_arch->set_text(0, TTR("Double click to create a new entry"));
+ new_arch->set_text_align(0, TreeItem::ALIGN_CENTER);
+ new_arch->set_custom_color(0, get_color("accent_color", "Editor"));
+ new_arch->set_expand_right(0, true);
+ new_arch->set_metadata(1, E->key());
+
+ platform->set_collapsed(collapsed_items.find(E->get().name) != NULL);
+ }
+}
+
+void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
+
+ String target = Object::cast_to<TreeItem>(item)->get_metadata(0);
+ String platform = target.substr(0, target.find("."));
+ String entry = target.substr(platform.length() + 1, target.length());
+ String section = (id == BUTTON_SELECT_DEPENDENCES || id == BUTTON_CLEAR_DEPENDENCES) ? "dependencies" : "entry";
+
+ if (id == BUTTON_SELECT_LIBRARY || id == BUTTON_SELECT_DEPENDENCES) {
+
+ EditorFileDialog::Mode mode = EditorFileDialog::MODE_OPEN_FILE;
+ if (id == BUTTON_SELECT_DEPENDENCES)
+ mode = EditorFileDialog::MODE_OPEN_FILES;
+
+ file_dialog->set_meta("target", target);
+ file_dialog->set_meta("section", section);
+ file_dialog->clear_filters();
+ file_dialog->add_filter(Object::cast_to<TreeItem>(item)->get_parent()->get_metadata(0));
+ file_dialog->set_mode(mode);
+ file_dialog->popup_centered_ratio();
+
+ } else if (id == BUTTON_CLEAR_LIBRARY) {
+ _set_target_value(section, target, "");
+ } else if (id == BUTTON_CLEAR_DEPENDENCES) {
+ _set_target_value(section, target, Array());
+ } else if (id == BUTTON_ERASE_ENTRY) {
+ _erase_entry(platform, entry);
+ } else if (id == BUTTON_MOVE_UP || id == BUTTON_MOVE_DOWN) {
+ _move_entry(platform, entry, id);
+ }
+}
+
+void GDNativeLibraryEditor::_on_library_selected(const String &file) {
+
+ _set_target_value(file_dialog->get_meta("section"), file_dialog->get_meta("target"), file);
+}
+
+void GDNativeLibraryEditor::_on_dependencies_selected(const PoolStringArray &files) {
+
+ _set_target_value(file_dialog->get_meta("section"), file_dialog->get_meta("target"), files);
+}
+
+void GDNativeLibraryEditor::_on_filter_selected(int id) {
+
+ showing_platform = filter->get_item_metadata(id);
+ _update_tree();
+}
+
+void GDNativeLibraryEditor::_on_item_collapsed(Object *p_item) {
+
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ String name = item->get_text(0);
+
+ if (item->is_collapsed()) {
+ collapsed_items.insert(name);
+ } else if (Set<String>::Element *e = collapsed_items.find(name)) {
+ collapsed_items.erase(e);
+ }
+}
+
+void GDNativeLibraryEditor::_on_item_activated() {
+
+ TreeItem *item = tree->get_selected();
+ if (item && tree->get_selected_column() == 0 && item->get_metadata(0).get_type() == Variant::NIL) {
+ new_architecture_dialog->set_meta("platform", item->get_metadata(1));
+ new_architecture_dialog->popup_centered();
+ }
+}
+
+void GDNativeLibraryEditor::_on_create_new_entry() {
+
+ String platform = new_architecture_dialog->get_meta("platform");
+ String entry = new_architecture_input->get_text().strip_edges();
+ if (!entry.empty()) {
+ platforms[platform].entries.push_back(entry);
+ _update_tree();
+ }
+}
+
+void GDNativeLibraryEditor::_set_target_value(const String &section, const String &target, Variant file) {
+ if (section == "entry")
+ entry_configs[target].library = file;
+ else if (section == "dependencies")
+ entry_configs[target].dependencies = file;
+ _translate_to_config_file();
+ _update_tree();
+}
+
+void GDNativeLibraryEditor::_erase_entry(const String &platform, const String &entry) {
+
+ if (platforms.has(platform)) {
+ if (List<String>::Element *E = platforms[platform].entries.find(entry)) {
+
+ String target = platform + "." + entry;
+ Ref<ConfigFile> config = library->get_config_file();
+
+ platforms[platform].entries.erase(E);
+ _set_target_value("entry", target, "");
+ _set_target_value("dependencies", target, Array());
+ _translate_to_config_file();
+ _update_tree();
+ }
+ }
+}
+
+void GDNativeLibraryEditor::_move_entry(const String &platform, const String &entry, int dir) {
+ if (List<String>::Element *E = platforms[platform].entries.find(entry)) {
+ if (E->prev() && dir == BUTTON_MOVE_UP) {
+ platforms[platform].entries.insert_before(E->prev(), E->get());
+ platforms[platform].entries.erase(E);
+ } else if (E->next() && dir == BUTTON_MOVE_DOWN) {
+ platforms[platform].entries.insert_after(E->next(), E->get());
+ platforms[platform].entries.erase(E);
+ }
+ _translate_to_config_file();
+ _update_tree();
+ }
+}
+
+void GDNativeLibraryEditor::_translate_to_config_file() {
+
+ if (!library.is_null()) {
+
+ Ref<ConfigFile> config = library->get_config_file();
+ config->erase_section("entry");
+ config->erase_section("dependencies");
+
+ for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
+ for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) {
+
+ String target = E->key() + "." + it->get();
+ if (entry_configs[target].library.empty() && entry_configs[target].dependencies.empty())
+ continue;
+
+ config->set_value("entry", target, entry_configs[target].library);
+ config->set_value("dependencies", target, entry_configs[target].dependencies);
+ }
+ }
+
+ library->_change_notify();
+ }
+}
+
+GDNativeLibraryEditor::GDNativeLibraryEditor() {
+
+ showing_platform = "All";
+
+ { // Define platforms
+ NativePlatformConfig platform_windows;
+ platform_windows.name = "Windows";
+ platform_windows.entries.push_back("64");
+ platform_windows.entries.push_back("32");
+ platform_windows.library_extension = "*.dll";
+ platforms["Windows"] = platform_windows;
+
+ NativePlatformConfig platform_linux;
+ platform_linux.name = "Linux/X11";
+ platform_linux.entries.push_back("64");
+ platform_linux.entries.push_back("32");
+ platform_linux.library_extension = "*.so";
+ platforms["X11"] = platform_linux;
+
+ NativePlatformConfig platform_osx;
+ platform_osx.name = "Mac OSX";
+ platform_osx.entries.push_back("64");
+ platform_osx.entries.push_back("32");
+ platform_osx.library_extension = "*.dylib";
+ platforms["OSX"] = platform_osx;
+
+ NativePlatformConfig platform_haiku;
+ platform_haiku.name = "Haiku";
+ platform_haiku.entries.push_back("64");
+ platform_haiku.entries.push_back("32");
+ platform_haiku.library_extension = "*.so";
+ platforms["Haiku"] = platform_haiku;
+
+ NativePlatformConfig platform_uwp;
+ platform_uwp.name = "Windows Universal";
+ platform_uwp.entries.push_back("arm");
+ platform_uwp.entries.push_back("x86");
+ platform_uwp.entries.push_back("x64");
+ platform_uwp.library_extension = "*.dll";
+ platforms["UWP"] = platform_uwp;
+
+ NativePlatformConfig platform_android;
+ platform_android.name = "Android";
+ platform_android.entries.push_back("armeabi-v7a");
+ platform_android.entries.push_back("arm64-v8a");
+ platform_android.entries.push_back("x86");
+ platform_android.entries.push_back("x86_64");
+ platform_android.library_extension = "*.so";
+ platforms["Android"] = platform_android;
+
+ // TODO: Javascript platform is not supported yet
+ // NativePlatformConfig platform_html5;
+ // platform_html5.name = "HTML5";
+ // platform_html5.library_extension = "*.wasm";
+ // platforms["Javascript"] = platform_html5;
+
+ NativePlatformConfig platform_ios;
+ platform_ios.name = "iOS";
+ platform_ios.entries.push_back("armv7");
+ platform_ios.entries.push_back("arm64");
+ platform_ios.library_extension = "*.dylib";
+ platforms["iOS"] = platform_ios;
+ }
+
+ VBoxContainer *container = memnew(VBoxContainer);
+ add_child(container);
+ container->set_anchors_and_margins_preset(PRESET_WIDE);
+
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ container->add_child(hbox);
+ Label *label = memnew(Label);
+ label->set_text(TTR("Platform:"));
+ hbox->add_child(label);
+ filter = memnew(OptionButton);
+ hbox->add_child(filter);
+ filter->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ int idx = 0;
+ filter->add_item(TTR("All"), idx);
+ filter->set_item_metadata(idx, "All");
+ idx += 1;
+ for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
+ filter->add_item(E->get().name, idx);
+ filter->set_item_metadata(idx, E->key());
+ idx += 1;
+ }
+ filter->connect("item_selected", this, "_on_filter_selected");
+
+ tree = memnew(Tree);
+ container->add_child(tree);
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree->set_hide_root(true);
+ tree->set_column_titles_visible(true);
+ tree->set_columns(4);
+ tree->set_column_expand(0, false);
+ tree->set_column_min_width(0, int(200 * EDSCALE));
+ tree->set_column_title(0, TTR("Platform"));
+ tree->set_column_title(1, TTR("Dynamic Library"));
+ tree->set_column_title(2, TTR("Dependencies"));
+ tree->set_column_expand(3, false);
+ tree->set_column_min_width(3, int(110 * EDSCALE));
+ tree->connect("button_pressed", this, "_on_item_button");
+ tree->connect("item_collapsed", this, "_on_item_collapsed");
+ tree->connect("item_activated", this, "_on_item_activated");
+
+ file_dialog = memnew(EditorFileDialog);
+ file_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
+ file_dialog->set_resizable(true);
+ add_child(file_dialog);
+ file_dialog->connect("file_selected", this, "_on_library_selected");
+ file_dialog->connect("files_selected", this, "_on_dependencies_selected");
+
+ new_architecture_dialog = memnew(ConfirmationDialog);
+ add_child(new_architecture_dialog);
+ new_architecture_dialog->set_title(TTR("Add an architecture entry"));
+ new_architecture_input = memnew(LineEdit);
+ new_architecture_dialog->add_child(new_architecture_input);
+ new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE);
+ new_architecture_input->set_anchors_and_margins_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE);
+ new_architecture_dialog->get_ok()->connect("pressed", this, "_on_create_new_entry");
+}
+
+void GDNativeLibraryEditorPlugin::edit(Object *p_node) {
+
+ if (Object::cast_to<GDNativeLibrary>(p_node)) {
+ library_editor->edit(Object::cast_to<GDNativeLibrary>(p_node));
+ library_editor->show();
+ } else
+ library_editor->hide();
+}
+
+bool GDNativeLibraryEditorPlugin::handles(Object *p_node) const {
+
+ return p_node->is_class("GDNativeLibrary");
+}
+
+void GDNativeLibraryEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ button->show();
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(library_editor);
+
+ } else {
+ if (library_editor->is_visible_in_tree())
+ EditorNode::get_singleton()->hide_bottom_panel();
+ button->hide();
+ }
+}
+
+GDNativeLibraryEditorPlugin::GDNativeLibraryEditorPlugin(EditorNode *p_node) {
+
+ library_editor = memnew(GDNativeLibraryEditor);
+ library_editor->set_custom_minimum_size(Size2(0, 250 * EDSCALE));
+ button = p_node->add_bottom_panel_item(TTR("GDNativeLibrary"), library_editor);
+ button->hide();
+}
+
+#endif
diff --git a/modules/gdnative/gdnative_library_editor_plugin.h b/modules/gdnative/gdnative_library_editor_plugin.h
new file mode 100644
index 0000000000..1fa6a0c945
--- /dev/null
+++ b/modules/gdnative/gdnative_library_editor_plugin.h
@@ -0,0 +1,113 @@
+/*************************************************************************/
+/* gdnative_library_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GDNATIVE_LIBRARY_EDITOR_PLUGIN_H
+#define GDNATIVE_LIBRARY_EDITOR_PLUGIN_H
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#include "gdnative.h"
+
+class GDNativeLibraryEditor : public Control {
+
+ GDCLASS(GDNativeLibraryEditor, Control);
+
+ struct NativePlatformConfig {
+ String name;
+ String library_extension;
+ List<String> entries;
+ };
+
+ struct TargetConfig {
+ String library;
+ Array dependencies;
+ };
+
+ enum ItemButton {
+ BUTTON_SELECT_LIBRARY,
+ BUTTON_CLEAR_LIBRARY,
+ BUTTON_SELECT_DEPENDENCES,
+ BUTTON_CLEAR_DEPENDENCES,
+ BUTTON_ERASE_ENTRY,
+ BUTTON_MOVE_UP,
+ BUTTON_MOVE_DOWN,
+ };
+
+ Tree *tree;
+ OptionButton *filter;
+ EditorFileDialog *file_dialog;
+ ConfirmationDialog *new_architecture_dialog;
+ LineEdit *new_architecture_input;
+ Set<String> collapsed_items;
+
+ String showing_platform;
+ Ref<GDNativeLibrary> library;
+ Map<String, NativePlatformConfig> platforms;
+ Map<String, TargetConfig> entry_configs;
+
+protected:
+ static void _bind_methods();
+ void _update_tree();
+ void _on_item_button(Object *item, int column, int id);
+ void _on_library_selected(const String &file);
+ void _on_dependencies_selected(const PoolStringArray &files);
+ void _on_filter_selected(int id);
+ void _on_item_collapsed(Object *item);
+ void _on_item_activated();
+ void _on_create_new_entry();
+ void _set_target_value(const String &section, const String &target, Variant file);
+ void _erase_entry(const String &platform, const String &entry);
+ void _move_entry(const String &platform, const String &entry, int dir);
+ void _translate_to_config_file();
+
+public:
+ void edit(Ref<GDNativeLibrary> p_library);
+
+ GDNativeLibraryEditor();
+};
+
+class GDNativeLibraryEditorPlugin : public EditorPlugin {
+
+ GDCLASS(GDNativeLibraryEditorPlugin, EditorPlugin);
+
+ GDNativeLibraryEditor *library_editor;
+ EditorNode *editor;
+ Button *button;
+
+public:
+ virtual String get_name() const { return "GDNativeLibrary"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_node);
+ virtual bool handles(Object *p_node) const;
+ virtual void make_visible(bool p_visible);
+
+ GDNativeLibraryEditorPlugin(EditorNode *p_node);
+};
+#endif
+#endif // GDNATIVE_LIBRARY_EDITOR_PLUGIN_H
diff --git a/modules/gdnative/gd_native_library_editor.cpp b/modules/gdnative/gdnative_library_singleton_editor.cpp
index fda5dcdcad..2ad497fcad 100644
--- a/modules/gdnative/gd_native_library_editor.cpp
+++ b/modules/gdnative/gdnative_library_singleton_editor.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gd_native_library_editor.cpp */
+/* gdnative_library_singleton_editor.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,11 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef TOOLS_ENABLED
-#include "gd_native_library_editor.h"
-
+#include "gdnative_library_singleton_editor.h"
#include "gdnative.h"
-void GDNativeLibraryEditor::_find_gdnative_singletons(EditorFileSystemDirectory *p_dir, const Set<String> &enabled_list) {
+void GDNativeLibrarySingletonEditor::_find_gdnative_singletons(EditorFileSystemDirectory *p_dir, const Set<String> &enabled_list) {
// check children
@@ -65,7 +64,7 @@ void GDNativeLibraryEditor::_find_gdnative_singletons(EditorFileSystemDirectory
}
}
-void GDNativeLibraryEditor::_update_libraries() {
+void GDNativeLibrarySingletonEditor::_update_libraries() {
updating = true;
libraries->clear();
@@ -88,7 +87,7 @@ void GDNativeLibraryEditor::_update_libraries() {
updating = false;
}
-void GDNativeLibraryEditor::_item_edited() {
+void GDNativeLibrarySingletonEditor::_item_edited() {
if (updating)
return;
@@ -119,7 +118,7 @@ void GDNativeLibraryEditor::_item_edited() {
}
}
-void GDNativeLibraryEditor::_notification(int p_what) {
+void GDNativeLibrarySingletonEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
if (is_visible_in_tree()) {
@@ -128,12 +127,12 @@ void GDNativeLibraryEditor::_notification(int p_what) {
}
}
-void GDNativeLibraryEditor::_bind_methods() {
+void GDNativeLibrarySingletonEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_item_edited"), &GDNativeLibraryEditor::_item_edited);
+ ClassDB::bind_method(D_METHOD("_item_edited"), &GDNativeLibrarySingletonEditor::_item_edited);
}
-GDNativeLibraryEditor::GDNativeLibraryEditor() {
+GDNativeLibrarySingletonEditor::GDNativeLibrarySingletonEditor() {
libraries = memnew(Tree);
libraries->set_columns(2);
libraries->set_column_titles_visible(true);
diff --git a/modules/gdnative/gd_native_library_editor.h b/modules/gdnative/gdnative_library_singleton_editor.h
index a11c4620dd..ee1a32c5a5 100644
--- a/modules/gdnative/gd_native_library_editor.h
+++ b/modules/gdnative/gdnative_library_singleton_editor.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gd_native_library_editor.h */
+/* gdnative_library_singleton_editor.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -34,7 +34,7 @@
#include "editor/editor_file_system.h"
#include "editor/project_settings_editor.h"
-class GDNativeLibraryEditor : public VBoxContainer {
+class GDNativeLibrarySingletonEditor : public VBoxContainer {
Tree *libraries;
bool updating;
@@ -48,7 +48,7 @@ protected:
static void _bind_methods();
public:
- GDNativeLibraryEditor();
+ GDNativeLibrarySingletonEditor();
};
#endif
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 1cb35ec006..bd9bae5294 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -45,7 +45,8 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
-#include "gd_native_library_editor.h"
+#include "gdnative_library_editor_plugin.h"
+#include "gdnative_library_singleton_editor.h"
// Class used to discover singleton gdnative files
static void actual_discoverer_handler();
@@ -267,7 +268,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty
static void editor_init_callback() {
- GDNativeLibraryEditor *library_editor = memnew(GDNativeLibraryEditor);
+ GDNativeLibrarySingletonEditor *library_editor = memnew(GDNativeLibrarySingletonEditor);
library_editor->set_name(TTR("GDNative"));
ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(library_editor);
@@ -278,6 +279,8 @@ static void editor_init_callback() {
export_plugin.instance();
EditorExport::get_singleton()->add_export_plugin(export_plugin);
+
+ EditorNode::get_singleton()->add_editor_plugin(memnew(GDNativeLibraryEditorPlugin(EditorNode::get_singleton())));
}
#endif
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 8c862b52e8..e9bb90631d 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -21,6 +21,26 @@
Clear all cells.
</description>
</method>
+ <method name="clear_baked_meshes">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_bake_mesh_instance">
+ <return type="RID">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bake_meshes">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_cell_item" qualifiers="const">
<return type="int">
</return>
@@ -103,6 +123,16 @@
Array of [Vector3] with the non empty cell coordinates in the grid map.
</description>
</method>
+ <method name="make_baked_meshes">
+ <return type="void">
+ </return>
+ <argument index="0" name="gen_lightmap_uv" type="bool" default="false">
+ </argument>
+ <argument index="1" name="lightmap_uv_texel_size" type="float" default="0.1">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="map_to_world" qualifiers="const">
<return type="Vector3">
</return>
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index bebf8bcf8f..060d9848ba 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -101,6 +101,27 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
}
}
_recreate_octant_data();
+ } else if (name == "baked_meshes") {
+
+ clear_baked_meshes();
+
+ Array meshes = p_value;
+
+ for (int i = 0; i < meshes.size(); i++) {
+ BakedMesh bm;
+ bm.mesh = meshes[i];
+ ERR_CONTINUE(!bm.mesh.is_valid());
+ bm.instance = VS::get_singleton()->instance_create();
+ VS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
+ VS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
+ if (is_inside_tree()) {
+ VS::get_singleton()->instance_set_scenario(bm.instance, get_world()->get_scenario());
+ VS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
+ }
+ baked_meshes.push_back(bm);
+ }
+
+ _recreate_octant_data();
} else
return false;
@@ -145,6 +166,15 @@ bool GridMap::_get(const StringName &p_name, Variant &r_ret) const {
d["cells"] = cells;
r_ret = d;
+ } else if (name == "baked_meshes") {
+
+ Array ret;
+ ret.resize(baked_meshes.size());
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ ret.push_back(baked_meshes[i].mesh);
+ }
+ r_ret = ret;
+
} else
return false;
@@ -161,6 +191,9 @@ void GridMap::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "cell_center_y"));
p_list->push_back(PropertyInfo(Variant::BOOL, "cell_center_z"));
p_list->push_back(PropertyInfo(Variant::REAL, "cell_scale"));
+ if (baked_meshes.size()) {
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "baked_meshes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
}
@@ -235,6 +268,12 @@ bool GridMap::get_center_z() const {
void GridMap::set_cell_item(int p_x, int p_y, int p_z, int p_item, int p_rot) {
+ if (baked_meshes.size() && !recreating_octants) {
+ //if you set a cell item, baked meshes go good bye
+ clear_baked_meshes();
+ _recreate_octant_data();
+ }
+
ERR_FAIL_INDEX(ABS(p_x), 1 << 20);
ERR_FAIL_INDEX(ABS(p_y), 1 << 20);
ERR_FAIL_INDEX(ABS(p_z), 1 << 20);
@@ -436,16 +475,17 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
xform.basis.set_orthogonal_index(c.rot);
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
+ if (baked_meshes.size()) {
+ if (theme->get_item_mesh(c.item).is_valid()) {
+ if (!multimesh_items.has(c.item)) {
+ multimesh_items[c.item] = List<Pair<Transform, IndexKey> >();
+ }
- if (theme->get_item_mesh(c.item).is_valid()) {
- if (!multimesh_items.has(c.item)) {
- multimesh_items[c.item] = List<Pair<Transform, IndexKey> >();
+ Pair<Transform, IndexKey> p;
+ p.first = xform;
+ p.second = E->get();
+ multimesh_items[c.item].push_back(p);
}
-
- Pair<Transform, IndexKey> p;
- p.first = xform;
- p.second = E->get();
- multimesh_items[c.item].push_back(p);
}
Vector<MeshLibrary::ShapeData> shapes = theme->get_item_shapes(c.item);
@@ -477,41 +517,44 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
}
- //update multimeshes
- for (Map<int, List<Pair<Transform, IndexKey> > >::Element *E = multimesh_items.front(); E; E = E->next()) {
- Octant::MultimeshInstance mmi;
+ //update multimeshes, only if not baked
+ if (baked_meshes.size() == 0) {
+
+ for (Map<int, List<Pair<Transform, IndexKey> > >::Element *E = multimesh_items.front(); E; E = E->next()) {
+ Octant::MultimeshInstance mmi;
- RID mm = VS::get_singleton()->multimesh_create();
- VS::get_singleton()->multimesh_allocate(mm, E->get().size(), VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_NONE);
- VS::get_singleton()->multimesh_set_mesh(mm, theme->get_item_mesh(E->key())->get_rid());
+ RID mm = VS::get_singleton()->multimesh_create();
+ VS::get_singleton()->multimesh_allocate(mm, E->get().size(), VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_NONE);
+ VS::get_singleton()->multimesh_set_mesh(mm, theme->get_item_mesh(E->key())->get_rid());
- int idx = 0;
- for (List<Pair<Transform, IndexKey> >::Element *F = E->get().front(); F; F = F->next()) {
- VS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first);
+ int idx = 0;
+ for (List<Pair<Transform, IndexKey> >::Element *F = E->get().front(); F; F = F->next()) {
+ VS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first);
#ifdef TOOLS_ENABLED
- Octant::MultimeshInstance::Item it;
- it.index = idx;
- it.transform = F->get().first;
- it.key = F->get().second;
- mmi.items.push_back(it);
+ Octant::MultimeshInstance::Item it;
+ it.index = idx;
+ it.transform = F->get().first;
+ it.key = F->get().second;
+ mmi.items.push_back(it);
#endif
- idx++;
- }
+ idx++;
+ }
- RID instance = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(instance, mm);
+ RID instance = VS::get_singleton()->instance_create();
+ VS::get_singleton()->instance_set_base(instance, mm);
- if (is_inside_tree()) {
- VS::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(instance, get_global_transform());
- }
+ if (is_inside_tree()) {
+ VS::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
+ VS::get_singleton()->instance_set_transform(instance, get_global_transform());
+ }
- mmi.multimesh = mm;
- mmi.instance = instance;
+ mmi.multimesh = mm;
+ mmi.instance = instance;
- g.multimesh_instances.push_back(mmi);
+ g.multimesh_instances.push_back(mmi);
+ }
}
if (col_debug.size()) {
@@ -642,6 +685,11 @@ void GridMap::_notification(int p_what) {
_octant_enter_world(E->key());
}
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ VS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, get_world()->get_scenario());
+ VS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
+ }
+
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -655,6 +703,10 @@ void GridMap::_notification(int p_what) {
last_transform = new_xform;
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ VS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
+ }
+
} break;
case NOTIFICATION_EXIT_WORLD: {
@@ -667,6 +719,9 @@ void GridMap::_notification(int p_what) {
//_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
//_update_octants_callback();
//_update_area_instances();
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ VS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID());
+ }
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -701,12 +756,14 @@ void GridMap::_queue_octants_dirty() {
void GridMap::_recreate_octant_data() {
+ recreating_octants = true;
Map<IndexKey, Cell> cell_copy = cell_map;
_clear_internal();
for (Map<IndexKey, Cell>::Element *E = cell_copy.front(); E; E = E->next()) {
set_cell_item(E->key().x, E->key().y, E->key().z, E->get().item, E->get().rot);
}
+ recreating_octants = false;
}
void GridMap::_clear_internal() {
@@ -726,6 +783,7 @@ void GridMap::_clear_internal() {
void GridMap::clear() {
_clear_internal();
+ clear_baked_meshes();
}
void GridMap::resource_changed(const RES &p_res) {
@@ -791,6 +849,11 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_used_cells"), &GridMap::get_used_cells);
ClassDB::bind_method(D_METHOD("get_meshes"), &GridMap::get_meshes);
+ ClassDB::bind_method(D_METHOD("get_bake_meshes"), &GridMap::get_bake_meshes);
+ ClassDB::bind_method(D_METHOD("get_bake_mesh_instance", "idx"), &GridMap::get_bake_mesh_instance);
+
+ ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
+ ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
BIND_CONSTANT(INVALID_CELL_ITEM);
}
@@ -883,10 +946,129 @@ Vector3 GridMap::_get_offset() const {
cell_size.z * 0.5 * int(center_z));
}
+void GridMap::clear_baked_meshes() {
+
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ VS::get_singleton()->free(baked_meshes[i].instance);
+ }
+ baked_meshes.clear();
+
+ _recreate_octant_data();
+}
+
+void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texel_size) {
+
+ if (!theme.is_valid())
+ return;
+
+ //generate
+ Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool> > > surface_map;
+
+ for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
+
+ IndexKey key = E->key();
+
+ int item = E->get().item;
+ if (!theme->has_item(item))
+ continue;
+
+ Ref<Mesh> mesh = theme->get_item_mesh(item);
+ if (!mesh.is_valid())
+ continue;
+
+ Vector3 cellpos = Vector3(key.x, key.y, key.z);
+ Vector3 ofs = _get_offset();
+
+ Transform xform;
+
+ xform.basis.set_orthogonal_index(E->get().rot);
+ xform.set_origin(cellpos * cell_size + ofs);
+ xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
+
+ OctantKey ok;
+ ok.x = key.x / octant_size;
+ ok.y = key.y / octant_size;
+ ok.z = key.z / octant_size;
+
+ if (!surface_map.has(ok)) {
+ surface_map[ok] = Map<Ref<Material>, Ref<SurfaceTool> >();
+ }
+
+ Map<Ref<Material>, Ref<SurfaceTool> > &mat_map = surface_map[ok];
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
+ continue;
+
+ Ref<Material> surf_mat = mesh->surface_get_material(i);
+ if (!mat_map.has(surf_mat)) {
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->begin(Mesh::PRIMITIVE_TRIANGLES);
+ st->set_material(surf_mat);
+ mat_map[surf_mat] = st;
+ }
+
+ mat_map[surf_mat]->append_from(mesh, i, xform);
+ }
+ }
+
+ int ofs = 0;
+
+ for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool> > >::Element *E = surface_map.front(); E; E = E->next()) {
+
+ print_line("generating mesh " + itos(ofs++) + "/" + itos(surface_map.size()));
+ Ref<ArrayMesh> mesh;
+ mesh.instance();
+ for (Map<Ref<Material>, Ref<SurfaceTool> >::Element *F = E->get().front(); F; F = F->next()) {
+ F->get()->commit(mesh);
+ }
+
+ BakedMesh bm;
+ bm.mesh = mesh;
+ bm.instance = VS::get_singleton()->instance_create();
+ VS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
+ VS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
+ if (is_inside_tree()) {
+ VS::get_singleton()->instance_set_scenario(bm.instance, get_world()->get_scenario());
+ VS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
+ }
+
+ if (p_gen_lightmap_uv) {
+ mesh->lightmap_unwrap(get_global_transform(), p_lightmap_uv_texel_size);
+ }
+ baked_meshes.push_back(bm);
+ }
+
+ _recreate_octant_data();
+}
+
+Array GridMap::get_bake_meshes() {
+
+ if (!baked_meshes.size()) {
+ make_baked_meshes(true);
+ }
+
+ Array arr;
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ arr.push_back(baked_meshes[i].mesh);
+ arr.push_back(Transform());
+ }
+
+ return arr;
+}
+
+RID GridMap::get_bake_mesh_instance(int p_idx) {
+
+ ERR_FAIL_INDEX_V(p_idx, baked_meshes.size(), RID());
+ return baked_meshes[p_idx].instance;
+}
+
GridMap::GridMap() {
cell_size = Vector3(2, 2, 2);
- octant_size = 4;
+ octant_size = 8;
awaiting_update = false;
_in_tree = false;
center_x = true;
@@ -901,6 +1083,7 @@ GridMap::GridMap() {
navigation = NULL;
set_notify_transform(true);
+ recreating_octants = false;
}
GridMap::~GridMap() {
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index ab66bf123e..241ac7a434 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -148,6 +148,9 @@ class GridMap : public Spatial {
bool clip;
bool clip_above;
int clip_floor;
+
+ bool recreating_octants;
+
Vector3::Axis clip_axis;
Ref<MeshLibrary> theme;
@@ -188,9 +191,11 @@ class GridMap : public Spatial {
struct BakedMesh {
Ref<Mesh> mesh;
- Transform transform;
+ RID instance;
};
+ Vector<BakedMesh> baked_meshes;
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -237,8 +242,14 @@ public:
Array get_meshes();
+ void clear_baked_meshes();
+ void make_baked_meshes(bool p_gen_lightmap_uv = false, float p_lightmap_uv_texel_size = 0.1);
+
void clear();
+ Array get_bake_meshes();
+ RID get_bake_mesh_instance(int p_idx);
+
GridMap();
~GridMap();
};
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index e473348897..e8aea8624d 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -70,7 +70,9 @@ void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const
}
if (fatal) {
- ERR_PRINTS("Mono: FALTAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
+ ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
+ // If we were to abort without flushing, the log wouldn't get written.
+ f->flush();
abort();
}
}
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 5c252bda86..6f5bbba8d1 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -42,12 +42,17 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra
int todo = p_frames;
- while (todo && active) {
+ int start_buffer = 0;
- int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, (float *)p_buffer, todo * 2);
+ while (todo && active) {
+ float *buffer = (float *)p_buffer;
+ if (start_buffer > 0) {
+ buffer = (buffer + start_buffer * 2);
+ }
+ int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, buffer, todo * 2);
if (vorbis_stream->channels == 1 && mixed > 0) {
//mix mono to stereo
- for (int i = 0; i < mixed; i++) {
+ for (int i = start_buffer; i < mixed; i++) {
p_buffer[i].r = p_buffer[i].l;
}
}
@@ -60,11 +65,14 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra
//loop
seek(vorbis_stream->loop_offset);
loops++;
+ // we still have buffer to fill, start from this element in the next iteration.
+ start_buffer = p_frames - todo;
} else {
- for (int i = mixed; i < p_frames; i++) {
+ for (int i = p_frames - todo; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0, 0);
}
active = false;
+ todo = 0;
}
}
}
diff --git a/modules/thekla_unwrap/register_types.cpp b/modules/thekla_unwrap/register_types.cpp
index ab3203068f..da6c1bab2a 100644
--- a/modules/thekla_unwrap/register_types.cpp
+++ b/modules/thekla_unwrap/register_types.cpp
@@ -65,7 +65,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
Thekla::atlas_set_default_options(&options);
options.packer_options.witness.packing_quality = 1;
options.packer_options.witness.texel_area = 1.0 / p_texel_size;
- options.packer_options.witness.conservative = true;
+ options.packer_options.witness.conservative = false;
//generate
Thekla::Atlas_Error err;
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 6c58de8a5a..faf3aecbd4 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -228,7 +228,7 @@ protected:
if (String(p_name) == "type") {
- Dictionary dc = d.copy();
+ Dictionary dc = d.duplicate();
dc["type"] = p_value;
undo_redo->create_action(TTR("Set Variable Type"));
undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
@@ -241,7 +241,7 @@ protected:
if (String(p_name) == "hint") {
- Dictionary dc = d.copy();
+ Dictionary dc = d.duplicate();
dc["hint"] = p_value;
undo_redo->create_action(TTR("Set Variable Type"));
undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
@@ -254,7 +254,7 @@ protected:
if (String(p_name) == "hint_string") {
- Dictionary dc = d.copy();
+ Dictionary dc = d.duplicate();
dc["hint_string"] = p_value;
undo_redo->create_action(TTR("Set Variable Type"));
undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
@@ -480,33 +480,33 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
select_func_text->hide();
Ref<Texture> type_icons[Variant::VARIANT_MAX] = {
- Control::get_icon("MiniVariant", "EditorIcons"),
- Control::get_icon("MiniBoolean", "EditorIcons"),
- Control::get_icon("MiniInteger", "EditorIcons"),
- Control::get_icon("MiniFloat", "EditorIcons"),
- Control::get_icon("MiniString", "EditorIcons"),
- Control::get_icon("MiniVector2", "EditorIcons"),
- Control::get_icon("MiniRect2", "EditorIcons"),
- Control::get_icon("MiniVector3", "EditorIcons"),
- Control::get_icon("MiniTransform2D", "EditorIcons"),
- Control::get_icon("MiniPlane", "EditorIcons"),
- Control::get_icon("MiniQuat", "EditorIcons"),
- Control::get_icon("MiniAabb", "EditorIcons"),
- Control::get_icon("MiniBasis", "EditorIcons"),
- Control::get_icon("MiniTransform", "EditorIcons"),
- Control::get_icon("MiniColor", "EditorIcons"),
- Control::get_icon("MiniPath", "EditorIcons"),
- Control::get_icon("MiniRid", "EditorIcons"),
+ Control::get_icon("Variant", "EditorIcons"),
+ Control::get_icon("bool", "EditorIcons"),
+ Control::get_icon("int", "EditorIcons"),
+ Control::get_icon("float", "EditorIcons"),
+ Control::get_icon("String", "EditorIcons"),
+ Control::get_icon("Vector2", "EditorIcons"),
+ Control::get_icon("Rect2", "EditorIcons"),
+ Control::get_icon("Vector3", "EditorIcons"),
+ Control::get_icon("Transform2D", "EditorIcons"),
+ Control::get_icon("Plane", "EditorIcons"),
+ Control::get_icon("Quat", "EditorIcons"),
+ Control::get_icon("AABB", "EditorIcons"),
+ Control::get_icon("Basis", "EditorIcons"),
+ Control::get_icon("Transform", "EditorIcons"),
+ Control::get_icon("Color", "EditorIcons"),
+ Control::get_icon("NodePath", "EditorIcons"),
+ Control::get_icon("RID", "EditorIcons"),
Control::get_icon("MiniObject", "EditorIcons"),
- Control::get_icon("MiniDictionary", "EditorIcons"),
- Control::get_icon("MiniArray", "EditorIcons"),
- Control::get_icon("MiniRawArray", "EditorIcons"),
- Control::get_icon("MiniIntArray", "EditorIcons"),
- Control::get_icon("MiniFloatArray", "EditorIcons"),
- Control::get_icon("MiniStringArray", "EditorIcons"),
- Control::get_icon("MiniVector2Array", "EditorIcons"),
- Control::get_icon("MiniVector3Array", "EditorIcons"),
- Control::get_icon("MiniColorArray", "EditorIcons")
+ Control::get_icon("Dictionary", "EditorIcons"),
+ Control::get_icon("Array", "EditorIcons"),
+ Control::get_icon("PoolByteArray", "EditorIcons"),
+ Control::get_icon("PoolIntArray", "EditorIcons"),
+ Control::get_icon("PoolRealArray", "EditorIcons"),
+ Control::get_icon("PoolStringArray", "EditorIcons"),
+ Control::get_icon("PoolVector2Array", "EditorIcons"),
+ Control::get_icon("PoolVector3Array", "EditorIcons"),
+ Control::get_icon("PoolColorArray", "EditorIcons")
};
Ref<Texture> seq_port = Control::get_icon("VisualShaderPort", "EditorIcons");
@@ -774,33 +774,33 @@ void VisualScriptEditor::_update_members() {
variables->set_custom_color(0, Control::get_color("mono_color", "Editor"));
Ref<Texture> type_icons[Variant::VARIANT_MAX] = {
- Control::get_icon("MiniVariant", "EditorIcons"),
- Control::get_icon("MiniBoolean", "EditorIcons"),
- Control::get_icon("MiniInteger", "EditorIcons"),
- Control::get_icon("MiniFloat", "EditorIcons"),
- Control::get_icon("MiniString", "EditorIcons"),
- Control::get_icon("MiniVector2", "EditorIcons"),
- Control::get_icon("MiniRect2", "EditorIcons"),
- Control::get_icon("MiniVector3", "EditorIcons"),
- Control::get_icon("MiniMatrix32", "EditorIcons"),
- Control::get_icon("MiniPlane", "EditorIcons"),
- Control::get_icon("MiniQuat", "EditorIcons"),
- Control::get_icon("MiniAabb", "EditorIcons"),
- Control::get_icon("MiniMatrix3", "EditorIcons"),
- Control::get_icon("MiniTransform", "EditorIcons"),
- Control::get_icon("MiniColor", "EditorIcons"),
- Control::get_icon("MiniPath", "EditorIcons"),
- Control::get_icon("MiniRid", "EditorIcons"),
+ Control::get_icon("Variant", "EditorIcons"),
+ Control::get_icon("bool", "EditorIcons"),
+ Control::get_icon("int", "EditorIcons"),
+ Control::get_icon("float", "EditorIcons"),
+ Control::get_icon("String", "EditorIcons"),
+ Control::get_icon("Vector2", "EditorIcons"),
+ Control::get_icon("Rect2", "EditorIcons"),
+ Control::get_icon("Vector3", "EditorIcons"),
+ Control::get_icon("Transform2D", "EditorIcons"),
+ Control::get_icon("Plane", "EditorIcons"),
+ Control::get_icon("Quat", "EditorIcons"),
+ Control::get_icon("AABB", "EditorIcons"),
+ Control::get_icon("Basis", "EditorIcons"),
+ Control::get_icon("Transform", "EditorIcons"),
+ Control::get_icon("Color", "EditorIcons"),
+ Control::get_icon("NodePath", "EditorIcons"),
+ Control::get_icon("RID", "EditorIcons"),
Control::get_icon("MiniObject", "EditorIcons"),
- Control::get_icon("MiniDictionary", "EditorIcons"),
- Control::get_icon("MiniArray", "EditorIcons"),
- Control::get_icon("MiniRawArray", "EditorIcons"),
- Control::get_icon("MiniIntArray", "EditorIcons"),
- Control::get_icon("MiniFloatArray", "EditorIcons"),
- Control::get_icon("MiniStringArray", "EditorIcons"),
- Control::get_icon("MiniVector2Array", "EditorIcons"),
- Control::get_icon("MiniVector3Array", "EditorIcons"),
- Control::get_icon("MiniColorArray", "EditorIcons")
+ Control::get_icon("Dictionary", "EditorIcons"),
+ Control::get_icon("Array", "EditorIcons"),
+ Control::get_icon("PoolByteArray", "EditorIcons"),
+ Control::get_icon("PoolIntArray", "EditorIcons"),
+ Control::get_icon("PoolRealArray", "EditorIcons"),
+ Control::get_icon("PoolStringArray", "EditorIcons"),
+ Control::get_icon("PoolVector2Array", "EditorIcons"),
+ Control::get_icon("PoolVector3Array", "EditorIcons"),
+ Control::get_icon("PoolColorArray", "EditorIcons")
};
List<StringName> var_names;
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
index f9bcbadc24..8c4a4726ae 100644
--- a/platform/android/godot_android.cpp
+++ b/platform/android/godot_android.cpp
@@ -927,7 +927,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *e
int stringCount = env->GetArrayLength(args);
- print_line("Singl: " + singname + " Method: " + mname + " RetVal: " + retval);
for (int i = 0; i < stringCount; i++) {
jstring string = (jstring)env->GetObjectArrayElement(args, i);
@@ -939,7 +938,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *e
cs += ")";
cs += get_jni_sig(retval);
jclass cls = env->GetObjectClass(s->get_instance());
- print_line("METHOD: " + mname + " sig: " + cs);
jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
if (!mid) {
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index c4d0cf5181..1e28ef4c6a 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -241,7 +241,6 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
String name = _get_class_name(env, c, &array);
//print_line("name is " + name + ", array "+Variant(array));
- print_line("ARGNAME: " + name);
if (name == "java.lang.String") {
return String::utf8(env->GetStringUTFChars((jstring)obj, NULL));
@@ -1513,7 +1512,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j
int stringCount = env->GetArrayLength(args);
- print_line("Singl: " + singname + " Method: " + mname + " RetVal: " + retval);
for (int i = 0; i < stringCount; i++) {
jstring string = (jstring)env->GetObjectArrayElement(args, i);
@@ -1525,7 +1523,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j
cs += ")";
cs += get_jni_sig(retval);
jclass cls = env->GetObjectClass(s->get_instance());
- print_line("METHOD: " + mname + " sig: " + cs);
jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
if (!mid) {
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 7afac94e71..754dcd9a6c 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -55,12 +55,13 @@ float BakedLightmapData::get_energy() const {
return energy;
}
-void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap) {
+void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance) {
ERR_FAIL_COND(p_lightmap.is_null());
User user;
user.path = p_path;
user.lightmap = p_lightmap;
+ user.instance_index = p_instance;
users.push_back(user);
}
@@ -79,16 +80,22 @@ Ref<Texture> BakedLightmapData::get_user_lightmap(int p_user) const {
return users[p_user].lightmap;
}
+int BakedLightmapData::get_user_instance(int p_user) const {
+
+ ERR_FAIL_INDEX_V(p_user, users.size(), -1);
+ return users[p_user].instance_index;
+}
+
void BakedLightmapData::clear_users() {
users.clear();
}
void BakedLightmapData::_set_user_data(const Array &p_data) {
- ERR_FAIL_COND(p_data.size() & 1);
+ ERR_FAIL_COND((p_data.size() % 3) != 0);
- for (int i = 0; i < p_data.size(); i += 2) {
- add_user(p_data[i], p_data[i + 1]);
+ for (int i = 0; i < p_data.size(); i += 3) {
+ add_user(p_data[i], p_data[i + 1], p_data[i + 2]);
}
}
@@ -98,6 +105,7 @@ Array BakedLightmapData::_get_user_data() const {
for (int i = 0; i < users.size(); i++) {
ret.push_back(users[i].path);
ret.push_back(users[i].lightmap);
+ ret.push_back(users[i].instance_index);
}
return ret;
}
@@ -125,7 +133,7 @@ void BakedLightmapData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy);
ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy);
- ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap"), &BakedLightmapData::add_user);
+ ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "instance"), &BakedLightmapData::add_user);
ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
ClassDB::bind_method(D_METHOD("get_user_lightmap", "user_idx"), &BakedLightmapData::get_user_lightmap);
@@ -209,6 +217,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo
pm.local_xform = xf;
pm.mesh = mesh;
pm.path = get_path_to(mi);
+ pm.instance_idx = -1;
for (int i = 0; i < mesh->get_surface_count(); i++) {
pm.instance_materials.push_back(mi->get_surface_material(i));
}
@@ -219,6 +228,26 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo
}
}
+ Spatial *s = Object::cast_to<Spatial>(p_at_node);
+
+ if (!mi && s) {
+ Array meshes = p_at_node->call("get_bake_meshes");
+ if (meshes.size() && (meshes.size() & 1) == 0) {
+ Transform xf = get_global_transform().affine_inverse() * s->get_global_transform();
+ for (int i = 0; i < meshes.size(); i += 2) {
+ PlotMesh pm;
+ Transform mesh_xf = meshes[i + 1];
+ pm.local_xform = xf * mesh_xf;
+ pm.mesh = meshes[i];
+ pm.instance_idx = i / 2;
+ if (!pm.mesh.is_valid())
+ continue;
+ pm.path = get_path_to(s);
+ plot_meshes.push_back(pm);
+ }
+ }
+ }
+
Light *light = Object::cast_to<Light>(p_at_node);
if (light && light->get_bake_mode() != Light::BAKE_DISABLED) {
@@ -477,7 +506,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
if (set_path) {
tex->set_path(image_path);
}
- new_light_data->add_user(E->get().path, tex);
+ new_light_data->add_user(E->get().path, tex, E->get().instance_idx);
}
}
@@ -547,12 +576,21 @@ void BakedLightmap::_assign_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
- Node *node = get_node(light_data->get_user_path(i));
- VisualInstance *vi = Object::cast_to<VisualInstance>(node);
- ERR_CONTINUE(!vi);
Ref<Texture> lightmap = light_data->get_user_lightmap(i);
ERR_CONTINUE(!lightmap.is_valid());
- VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
+
+ Node *node = get_node(light_data->get_user_path(i));
+ int instance_idx = light_data->get_user_instance(i);
+ if (instance_idx >= 0) {
+ RID instance = node->call("get_bake_mesh_instance", instance_idx);
+ if (instance.is_valid()) {
+ VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), lightmap->get_rid());
+ }
+ } else {
+ VisualInstance *vi = Object::cast_to<VisualInstance>(node);
+ ERR_CONTINUE(!vi);
+ VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
+ }
}
}
@@ -560,9 +598,17 @@ void BakedLightmap::_clear_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
Node *node = get_node(light_data->get_user_path(i));
- VisualInstance *vi = Object::cast_to<VisualInstance>(node);
- ERR_CONTINUE(!vi);
- VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), RID(), RID());
+ int instance_idx = light_data->get_user_instance(i);
+ if (instance_idx >= 0) {
+ RID instance = node->call("get_bake_mesh_instance", instance_idx);
+ if (instance.is_valid()) {
+ VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), RID());
+ }
+ } else {
+ VisualInstance *vi = Object::cast_to<VisualInstance>(node);
+ ERR_CONTINUE(!vi);
+ VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), RID());
+ }
}
}
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h
index f63749a0b4..9e15f1bb10 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/baked_lightmap.h
@@ -18,6 +18,7 @@ class BakedLightmapData : public Resource {
NodePath path;
Ref<Texture> lightmap;
+ int instance_index;
};
Vector<User> users;
@@ -44,10 +45,11 @@ public:
void set_energy(float p_energy);
float get_energy() const;
- void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap);
+ void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance = -1);
int get_user_count() const;
NodePath get_user_path(int p_user) const;
Ref<Texture> get_user_lightmap(int p_user) const;
+ int get_user_instance(int p_user) const;
void clear_users();
virtual RID get_rid() const;
@@ -111,6 +113,7 @@ private:
Ref<Mesh> mesh;
Transform local_xform;
NodePath path;
+ int instance_idx;
};
struct PlotLight {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 18ebc22c8b..2ecc445663 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -294,6 +294,7 @@ SpriteBase3D::SpriteBase3D() {
for (int i = 0; i < FLAG_MAX; i++)
flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
+ alpha_cut = ALPHA_CUT_DISABLED;
axis = Vector3::AXIS_Z;
pixel_size = 0.01;
modulate = Color(1, 1, 1, 1);
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 39ff6fa35e..edb9b9efd6 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -183,14 +183,23 @@ static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalf
return true; /* box and triangle overlaps */
}
-static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv) {
+static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) {
- if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2)
- return p_uv[0];
- if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2)
- return p_uv[1];
- if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2)
- return p_uv[2];
+ if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) {
+ r_uv = p_uv[0];
+ r_normal = p_normal[0];
+ return;
+ }
+ if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) {
+ r_uv = p_uv[1];
+ r_normal = p_normal[1];
+ return;
+ }
+ if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) {
+ r_uv = p_uv[2];
+ r_normal = p_normal[2];
+ return;
+ }
Vector3 v0 = p_vtx[1] - p_vtx[0];
Vector3 v1 = p_vtx[2] - p_vtx[0];
@@ -202,16 +211,20 @@ static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx,
float d20 = v2.dot(v0);
float d21 = v2.dot(v1);
float denom = (d00 * d11 - d01 * d01);
- if (denom == 0)
- return p_uv[0];
+ if (denom == 0) {
+ r_uv = p_uv[0];
+ r_normal = p_normal[0];
+ return;
+ }
float v = (d11 * d20 - d01 * d21) / denom;
float w = (d00 * d21 - d01 * d20) / denom;
float u = 1.0f - v - w;
- return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
+ r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
+ r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized();
}
-void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
+void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
if (p_level == cell_subdiv - 1) {
//plot the face by guessing it's albedo and emission value
@@ -289,7 +302,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection);
- Vector2 uv = get_uv(intersection, p_vtx, p_uv);
+ Vector2 uv;
+ Vector3 lnormal;
+ get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal);
+ if (lnormal == Vector3()) //just in case normal as nor provided
+ lnormal = normal;
int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
@@ -304,7 +321,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
emission_accum.g += p_material.emission[ofs].g;
emission_accum.b += p_material.emission[ofs].b;
- normal_accum += normal;
+ normal_accum += lnormal;
alpha += 1.0;
}
@@ -316,7 +333,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
- Vector2 uv = get_uv(inters, p_vtx, p_uv);
+ Vector3 lnormal;
+ Vector2 uv;
+ get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal);
+ if (lnormal == Vector3()) //just in case normal as nor provided
+ lnormal = normal;
int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
@@ -334,7 +355,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
emission_accum.g = p_material.emission[ofs].g * alpha;
emission_accum.b = p_material.emission[ofs].b * alpha;
- normal_accum *= alpha;
+ normal_accum = lnormal * alpha;
} else {
@@ -415,7 +436,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
bake_cells[child_idx].level = p_level + 1;
}
- _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_uv, p_material, aabb);
+ _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb);
}
}
}
@@ -539,9 +560,12 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
PoolVector<Vector3>::Read vr = vertices.read();
PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
PoolVector<Vector2>::Read uvr;
+ PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL];
+ PoolVector<Vector3>::Read nr;
PoolVector<int> index = a[Mesh::ARRAY_INDEX];
bool read_uv = false;
+ bool read_normals = false;
if (uv.size()) {
@@ -549,6 +573,11 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
read_uv = true;
}
+ if (normals.size()) {
+ read_normals = true;
+ nr = normals.read();
+ }
+
if (index.size()) {
int facecount = index.size() / 3;
@@ -558,6 +587,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
Vector3 vtxs[3];
Vector2 uvs[3];
+ Vector3 normal[3];
for (int k = 0; k < 3; k++) {
vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
@@ -569,11 +599,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
}
}
+ if (read_normals) {
+ for (int k = 0; k < 3; k++) {
+ normal[k] = nr[ir[j * 3 + k]];
+ }
+ }
+
//test against original bounds
if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
continue;
//plot
- _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds);
+ _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
}
} else {
@@ -584,6 +620,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
Vector3 vtxs[3];
Vector2 uvs[3];
+ Vector3 normal[3];
for (int k = 0; k < 3; k++) {
vtxs[k] = p_xform.xform(vr[j * 3 + k]);
@@ -595,11 +632,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
}
}
+ if (read_normals) {
+ for (int k = 0; k < 3; k++) {
+ normal[k] = nr[j * 3 + k];
+ }
+ }
+
//test against original bounds
if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
continue;
//plot face
- _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds);
+ _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
}
}
}
@@ -833,11 +876,13 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
}
}
- for (int i = 0; i < 6; i++) {
- float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
- light->direct_accum[i][0] += light_energy.x * s;
- light->direct_accum[i][1] += light_energy.y * s;
- light->direct_accum[i][2] += light_energy.z * s;
+ if (p_direct) {
+ for (int i = 0; i < 6; i++) {
+ float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
+ light->direct_accum[i][0] += light_energy.x * s;
+ light->direct_accum[i][1] += light_energy.y * s;
+ light->direct_accum[i][2] += light_energy.z * s;
+ }
}
success_count++;
}
@@ -962,11 +1007,13 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
}
}
- for (int i = 0; i < 6; i++) {
- float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
- light->direct_accum[i][0] += light_energy.x * s * att;
- light->direct_accum[i][1] += light_energy.y * s * att;
- light->direct_accum[i][2] += light_energy.z * s * att;
+ if (p_direct) {
+ for (int i = 0; i < 6; i++) {
+ float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
+ light->direct_accum[i][0] += light_energy.x * s * att;
+ light->direct_accum[i][1] += light_energy.y * s * att;
+ light->direct_accum[i][2] += light_energy.z * s * att;
+ }
}
}
@@ -1095,11 +1142,13 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
}
}
- for (int i = 0; i < 6; i++) {
- float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
- light->direct_accum[i][0] += light_energy.x * s * att;
- light->direct_accum[i][1] += light_energy.y * s * att;
- light->direct_accum[i][2] += light_energy.z * s * att;
+ if (p_direct) {
+ for (int i = 0; i < 6; i++) {
+ float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
+ light->direct_accum[i][0] += light_energy.x * s * att;
+ light->direct_accum[i][1] += light_energy.y * s * att;
+ light->direct_accum[i][2] += light_energy.z * s * att;
+ }
}
}
@@ -1638,10 +1687,10 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
Vector3 direction = normal_xform.xform(axis).normalized();
- Vector3 pos = p_pos + Vector3(0.5, 0.5, 0.5) + direction * bias;
-
Vector3 advance = direction * _get_normal_advance(direction);
+ Vector3 pos = p_pos /*+ Vector3(0.5, 0.5, 0.5)*/ + advance * bias;
+
uint32_t cell = CHILD_EMPTY;
while (cell == CHILD_EMPTY) {
@@ -1703,6 +1752,9 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
accum.y += light[cell].accum[i][1] * amount;
accum.z += light[cell].accum[i][2] * amount;
}
+ accum.x += cells[cell].emission[0];
+ accum.y += cells[cell].emission[1];
+ accum.z += cells[cell].emission[2];
}
}
@@ -1752,6 +1804,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
Vector3 vertex[3];
Vector3 normal[3];
Vector2 uv[3];
+
for (int j = 0; j < 3; j++) {
int idx = ic ? ir[i * 3 + j] : i * 3 + j;
vertex[j] = xform.xform(vr[idx]);
diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h
index 6dee2ee69b..a9b0e65e59 100644
--- a/scene/3d/voxel_light_baker.h
+++ b/scene/3d/voxel_light_baker.h
@@ -99,7 +99,8 @@ private:
Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add);
MaterialCache _get_material_cache(Ref<Material> p_material);
- void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb);
+
+ void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb);
void _fixup_plot(int p_idx, int p_level);
void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode);
void _check_init_light();
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index e1f77594da..51a25c60a1 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -207,7 +207,7 @@ void Label::_notification(int p_what) {
} break;
}
- int y_ofs = style->get_offset().y;
+ float y_ofs = style->get_offset().y;
y_ofs += (line - lines_skipped) * font_h + font->get_ascent();
y_ofs += vbegin + line * vsep;
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 698676cc39..d598104cf5 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -202,7 +202,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
case KEY_DOWN: {
- for (int i = mouse_over + 1; i < items.size(); i++) {
+ int search_from = mouse_over + 1;
+ if (search_from >= items.size())
+ search_from = 0;
+
+ for (int i = search_from; i < items.size(); i++) {
if (i < 0 || i >= items.size())
continue;
@@ -211,18 +215,17 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
update();
-
- if (items[i].submenu != "" && submenu_over != i) {
- submenu_over = i;
- submenu_timer->start();
- }
break;
}
}
} break;
case KEY_UP: {
- for (int i = mouse_over - 1; i >= 0; i--) {
+ int search_from = mouse_over - 1;
+ if (search_from < 0)
+ search_from = items.size() - 1;
+
+ for (int i = search_from; i >= 0; i--) {
if (i < 0 || i >= items.size())
continue;
@@ -231,20 +234,40 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
update();
-
- if (items[i].submenu != "" && submenu_over != i) {
- submenu_over = i;
- submenu_timer->start();
- }
break;
}
}
} break;
+
+ case KEY_LEFT: {
+
+ Node *n = get_parent();
+ if (!n)
+ break;
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(n);
+ if (!pm)
+ break;
+
+ hide();
+ } break;
+
+ case KEY_RIGHT: {
+
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over)
+ _activate_submenu(mouse_over);
+ } break;
+
case KEY_ENTER:
case KEY_KP_ENTER: {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
+ if (items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+ _activate_submenu(mouse_over);
+ break;
+ }
+
activate_item(mouse_over);
}
} break;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index af7a6bddd9..de1ab9959a 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2162,7 +2162,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
Variant value = N->get()->get(name);
// Duplicate dictionaries and arrays, mainly needed for __meta__
if (value.get_type() == Variant::DICTIONARY) {
- value = Dictionary(value).copy();
+ value = Dictionary(value).duplicate();
} else if (value.get_type() == Variant::ARRAY) {
value = Array(value).duplicate();
}
@@ -2303,7 +2303,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
Variant value = get(name);
// Duplicate dictionaries and arrays, mainly needed for __meta__
if (value.get_type() == Variant::DICTIONARY) {
- value = Dictionary(value).copy();
+ value = Dictionary(value).duplicate();
} else if (value.get_type() == Variant::ARRAY) {
value = Array(value).duplicate();
}
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index deb40800bc..467332b4e3 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -38,6 +38,7 @@
#include "os/os.h"
#include "print_string.h"
#include "project_settings.h"
+#include "scene/resources/dynamic_font.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
@@ -495,6 +496,10 @@ bool SceneTree::idle(float p_time) {
Size2 win_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height);
if (win_size != last_screen_size) {
+ if (use_font_oversampling) {
+ DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width;
+ }
+
last_screen_size = win_size;
_update_root_rect();
@@ -2195,6 +2200,9 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("_connection_failed"), &SceneTree::_connection_failed);
ClassDB::bind_method(D_METHOD("_server_disconnected"), &SceneTree::_server_disconnected);
+ ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling);
+ ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling);
+
ADD_SIGNAL(MethodInfo("tree_changed"));
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node")));
@@ -2244,6 +2252,20 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
idle_callbacks[idle_callback_count++] = p_callback;
}
+void SceneTree::set_use_font_oversampling(bool p_oversampling) {
+
+ use_font_oversampling = p_oversampling;
+ if (use_font_oversampling) {
+ DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width;
+ } else {
+ DynamicFontAtSize::font_oversampling = 1.0;
+ }
+}
+
+bool SceneTree::is_using_font_oversampling() const {
+ return use_font_oversampling;
+}
+
SceneTree::SceneTree() {
singleton = this;
@@ -2380,6 +2402,8 @@ SceneTree::SceneTree() {
last_send_cache_id = 1;
#endif
+
+ use_font_oversampling = false;
}
SceneTree::~SceneTree() {
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 244fc8da62..9c5b0f69cb 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -122,11 +122,13 @@ private:
bool _quit;
bool initialized;
bool input_handled;
+
Size2 last_screen_size;
StringName tree_changed_name;
StringName node_added_name;
StringName node_removed_name;
+ bool use_font_oversampling;
int64_t current_frame;
int node_count;
@@ -420,6 +422,9 @@ public:
void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize, real_t p_shrink = 1);
+ void set_use_font_oversampling(bool p_oversampling);
+ bool is_using_font_oversampling() const;
+
//void change_scene(const String& p_path);
//Node *get_loaded_scene();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index f5d7043a40..ae855e803c 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1659,6 +1659,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//cancel event, sorry, modal exclusive EATS UP ALL
//alternative, you can't pop out a window the same frame it was made modal (fixes many issues)
get_tree()->set_input_as_handled();
+
return; // no one gets the event if exclusive NO ONE
}
@@ -2348,7 +2349,6 @@ void Viewport::_gui_control_grab_focus(Control *p_control) {
//no need for change
if (gui.key_focus && gui.key_focus == p_control)
return;
-
get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus");
gui.key_focus = p_control;
p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
@@ -2370,6 +2370,11 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
else
p_control->_modal_set_prev_focus_owner(0);
+ if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus)) {
+ gui.mouse_focus->notification(Control::NOTIFICATION_MOUSE_EXIT);
+ gui.mouse_focus = NULL;
+ }
+
return gui.modal_stack.back();
}
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9715e1d6a0..246283edcc 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -268,11 +268,11 @@ void register_scene_types() {
ClassDB::register_class<Control>();
ClassDB::register_class<Button>();
ClassDB::register_class<Label>();
- ClassDB::register_class<ScrollBar>();
+ ClassDB::register_virtual_class<ScrollBar>();
ClassDB::register_class<HScrollBar>();
ClassDB::register_class<VScrollBar>();
ClassDB::register_class<ProgressBar>();
- ClassDB::register_class<Slider>();
+ ClassDB::register_virtual_class<Slider>();
ClassDB::register_class<HSlider>();
ClassDB::register_class<VSlider>();
ClassDB::register_class<Popup>();
@@ -283,7 +283,7 @@ void register_scene_types() {
ClassDB::register_class<ToolButton>();
ClassDB::register_class<LinkButton>();
ClassDB::register_class<Panel>();
- ClassDB::register_class<Range>();
+ ClassDB::register_virtual_class<Range>();
OS::get_singleton()->yield(); //may take time to init
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index a40417f24d..e6bff8f2ac 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -191,10 +191,10 @@ Error DynamicFontAtSize::_load() {
ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER );
}*/
- error = FT_Set_Pixel_Sizes(face, 0, id.size);
+ error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
- ascent = face->size->metrics.ascender >> 6;
- descent = -face->size->metrics.descender >> 6;
+ ascent = (face->size->metrics.ascender >> 6) / oversampling;
+ descent = (-face->size->metrics.descender >> 6) / oversampling;
linegap = 0;
texture_flags = 0;
if (id.mipmaps)
@@ -208,6 +208,8 @@ Error DynamicFontAtSize::_load() {
return OK;
}
+float DynamicFontAtSize::font_oversampling = 1.0;
+
float DynamicFontAtSize::get_height() const {
return ascent + descent;
@@ -282,11 +284,11 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V
if (delta.x == 0)
continue;
- ret.x += delta.x >> 6;
+ ret.x += (delta.x >> 6) / oversampling;
break;
}
} else {
- ret.x += delta.x >> 6;
+ ret.x += (delta.x >> 6) / oversampling;
}
}
@@ -338,7 +340,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
cpos.y += ch->v_align;
ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= fb->textures.size(), 0);
if (ch->texture_idx != -1)
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect, p_modulate, false, RID(), false);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect_uv, p_modulate, false, RID(), false);
advance = ch->advance;
used_fallback = true;
break;
@@ -360,7 +362,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
cpos.y += c->v_align;
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
if (c->texture_idx != -1)
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate, false, RID(), false);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect_uv, p_modulate, false, RID(), false);
advance = c->advance;
//textures[c->texture_idx].texture->draw(p_canvas_item,Vector2());
}
@@ -382,11 +384,11 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
if (delta.x == 0)
continue;
- advance += delta.x >> 6;
+ advance += (delta.x >> 6) / oversampling;
break;
}
} else {
- advance += delta.x >> 6;
+ advance += (delta.x >> 6) / oversampling;
}
}
@@ -602,13 +604,16 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
}
Character chr;
- chr.h_align = xofs;
- chr.v_align = ascent - yofs; // + ascent - descent;
- chr.advance = advance;
+ chr.h_align = xofs / oversampling;
+ chr.v_align = ascent - (yofs / oversampling); // + ascent - descent;
+ chr.advance = advance / oversampling;
chr.texture_idx = tex_index;
chr.found = true;
- chr.rect = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h);
+ chr.rect_uv = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h);
+ chr.rect = chr.rect_uv;
+ chr.rect.position /= oversampling;
+ chr.rect.size /= oversampling;
//print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs));
@@ -623,6 +628,7 @@ DynamicFontAtSize::DynamicFontAtSize() {
descent = 1;
linegap = 1;
texture_flags = 0;
+ oversampling = font_oversampling;
}
DynamicFontAtSize::~DynamicFontAtSize() {
diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h
index 52c3f30590..536b8925d0 100644
--- a/scene/resources/dynamic_font.h
+++ b/scene/resources/dynamic_font.h
@@ -97,10 +97,11 @@ class DynamicFontAtSize : public Reference {
FT_Face face; /* handle to face object */
FT_StreamRec stream;
- int ascent;
- int descent;
- int linegap;
- int rect_margin;
+ float ascent;
+ float descent;
+ float linegap;
+ float rect_margin;
+ float oversampling;
uint32_t texture_flags;
@@ -121,6 +122,7 @@ class DynamicFontAtSize : public Reference {
bool found;
int texture_idx;
Rect2 rect;
+ Rect2 rect_uv;
float v_align;
float h_align;
float advance;
@@ -145,8 +147,9 @@ class DynamicFontAtSize : public Reference {
static HashMap<String, Vector<uint8_t> > _fontdata;
Error _load();
-protected:
public:
+ static float font_oversampling;
+
float get_height() const;
float get_ascent() const;
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 2b44ea4554..8510669d6c 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -257,8 +257,8 @@ Error BitmapFont::create_from_fnt(const String &p_file) {
if (keys.has("file")) {
- String file = keys["file"];
- file = p_file.get_base_dir() + "/" + file;
+ String base_dir = p_file.get_base_dir();
+ String file = base_dir.plus_file(keys["file"]);
Ref<Texture> tex = ResourceLoader::load(file);
if (tex.is_null()) {
ERR_PRINT("Can't load font texture!");
diff --git a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp
index 5ce452cb9e..eeed519fe5 100644
--- a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp
+++ b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp
@@ -3,19 +3,19 @@
#include "nvmesh.h" // pch
#include "AtlasPacker.h"
-#include "nvmesh/halfedge/Vertex.h"
#include "nvmesh/halfedge/Face.h"
+#include "nvmesh/halfedge/Vertex.h"
#include "nvmesh/param/Atlas.h"
#include "nvmesh/param/Util.h"
#include "nvmesh/raster/Raster.h"
-#include "nvmath/Vector.inl"
-#include "nvmath/ConvexHull.h"
#include "nvmath/Color.h"
+#include "nvmath/ConvexHull.h"
+#include "nvmath/Vector.inl"
#include "nvmath/ftoi.h"
-#include "nvcore/StrLib.h" // debug
#include "nvcore/StdStream.h" // fileOpen
+#include "nvcore/StrLib.h" // debug
#include <float.h> // FLT_MAX
#include <limits.h> // UINT_MAX
@@ -28,147 +28,142 @@ using namespace nv;
#include "nvimage/ImageIO.h"
-namespace
-{
- const uint TGA_TYPE_GREY = 3;
- const uint TGA_TYPE_RGB = 2;
- const uint TGA_ORIGIN_UPPER = 0x20;
+namespace {
+const uint TGA_TYPE_GREY = 3;
+const uint TGA_TYPE_RGB = 2;
+const uint TGA_ORIGIN_UPPER = 0x20;
#pragma pack(push, 1)
- struct TgaHeader {
- uint8 id_length;
- uint8 colormap_type;
- uint8 image_type;
- uint16 colormap_index;
- uint16 colormap_length;
- uint8 colormap_size;
- uint16 x_origin;
- uint16 y_origin;
- uint16 width;
- uint16 height;
- uint8 pixel_size;
- uint8 flags;
-
- enum { Size = 18 }; //const static int SIZE = 18;
- };
+struct TgaHeader {
+ uint8 id_length;
+ uint8 colormap_type;
+ uint8 image_type;
+ uint16 colormap_index;
+ uint16 colormap_length;
+ uint8 colormap_size;
+ uint16 x_origin;
+ uint16 y_origin;
+ uint16 width;
+ uint16 height;
+ uint8 pixel_size;
+ uint8 flags;
+
+ enum { Size = 18 }; //const static int SIZE = 18;
+};
#pragma pack(pop)
- static void outputDebugBitmap(const char * fileName, const BitMap & bitmap, int w, int h)
- {
- FILE * fp = fileOpen(fileName, "wb");
- if (fp == NULL) return;
-
- nvStaticCheck(sizeof(TgaHeader) == TgaHeader::Size);
- TgaHeader tga;
- tga.id_length = 0;
- tga.colormap_type = 0;
- tga.image_type = TGA_TYPE_GREY;
-
- tga.colormap_index = 0;
- tga.colormap_length = 0;
- tga.colormap_size = 0;
-
- tga.x_origin = 0;
- tga.y_origin = 0;
- tga.width = w;
- tga.height = h;
- tga.pixel_size = 8;
- tga.flags = TGA_ORIGIN_UPPER;
-
- fwrite(&tga, sizeof(TgaHeader), 1, fp);
-
- for (int j = 0; j < h; j++) {
- for (int i = 0; i < w; i++) {
- uint8 color = bitmap.bitAt(i, j) ? 0xFF : 0x0;
- fwrite(&color, 1, 1, fp);
- }
+static void outputDebugBitmap(const char *fileName, const BitMap &bitmap, int w, int h) {
+ FILE *fp = fileOpen(fileName, "wb");
+ if (fp == NULL) return;
+
+ nvStaticCheck(sizeof(TgaHeader) == TgaHeader::Size);
+ TgaHeader tga;
+ tga.id_length = 0;
+ tga.colormap_type = 0;
+ tga.image_type = TGA_TYPE_GREY;
+
+ tga.colormap_index = 0;
+ tga.colormap_length = 0;
+ tga.colormap_size = 0;
+
+ tga.x_origin = 0;
+ tga.y_origin = 0;
+ tga.width = w;
+ tga.height = h;
+ tga.pixel_size = 8;
+ tga.flags = TGA_ORIGIN_UPPER;
+
+ fwrite(&tga, sizeof(TgaHeader), 1, fp);
+
+ for (int j = 0; j < h; j++) {
+ for (int i = 0; i < w; i++) {
+ uint8 color = bitmap.bitAt(i, j) ? 0xFF : 0x0;
+ fwrite(&color, 1, 1, fp);
}
+ }
- fclose(fp);
- }
+ fclose(fp);
+}
- static void outputDebugImage(const char * fileName, const Image & bitmap, int w, int h)
- {
- FILE * fp = fileOpen(fileName, "wb");
- if (fp == NULL) return;
-
- nvStaticCheck(sizeof(TgaHeader) == TgaHeader::Size);
- TgaHeader tga;
- tga.id_length = 0;
- tga.colormap_type = 0;
- tga.image_type = TGA_TYPE_RGB;
-
- tga.colormap_index = 0;
- tga.colormap_length = 0;
- tga.colormap_size = 0;
-
- tga.x_origin = 0;
- tga.y_origin = 0;
- tga.width = w;
- tga.height = h;
- tga.pixel_size = 24;
- tga.flags = TGA_ORIGIN_UPPER;
-
- fwrite(&tga, sizeof(TgaHeader), 1, fp);
-
- for (int j = 0; j < h; j++) {
- for (int i = 0; i < w; i++) {
- Color32 color = bitmap.pixel(i, j);
- fwrite(&color.r, 1, 1, fp);
- fwrite(&color.g, 1, 1, fp);
- fwrite(&color.b, 1, 1, fp);
- }
+static void outputDebugImage(const char *fileName, const Image &bitmap, int w, int h) {
+ FILE *fp = fileOpen(fileName, "wb");
+ if (fp == NULL) return;
+
+ nvStaticCheck(sizeof(TgaHeader) == TgaHeader::Size);
+ TgaHeader tga;
+ tga.id_length = 0;
+ tga.colormap_type = 0;
+ tga.image_type = TGA_TYPE_RGB;
+
+ tga.colormap_index = 0;
+ tga.colormap_length = 0;
+ tga.colormap_size = 0;
+
+ tga.x_origin = 0;
+ tga.y_origin = 0;
+ tga.width = w;
+ tga.height = h;
+ tga.pixel_size = 24;
+ tga.flags = TGA_ORIGIN_UPPER;
+
+ fwrite(&tga, sizeof(TgaHeader), 1, fp);
+
+ for (int j = 0; j < h; j++) {
+ for (int i = 0; i < w; i++) {
+ Color32 color = bitmap.pixel(i, j);
+ fwrite(&color.r, 1, 1, fp);
+ fwrite(&color.g, 1, 1, fp);
+ fwrite(&color.b, 1, 1, fp);
}
+ }
- fclose(fp);
- }
+ fclose(fp);
}
+} // namespace
#endif // DEBUG_OUTPUT
inline int align(int x, int a) {
- //return a * ((x + a - 1) / a);
- //return (x + a - 1) & -a;
- return (x + a - 1) & ~(a - 1);
+ //return a * ((x + a - 1) / a);
+ //return (x + a - 1) & -a;
+ return (x + a - 1) & ~(a - 1);
}
inline bool isAligned(int x, int a) {
- return (x & (a - 1)) == 0;
+ return (x & (a - 1)) == 0;
}
-
-
-AtlasPacker::AtlasPacker(Atlas * atlas) : m_atlas(atlas), m_bitmap(256, 256)
-{
- m_width = 0;
- m_height = 0;
-
+AtlasPacker::AtlasPacker(Atlas *atlas) :
+ m_atlas(atlas),
+ m_bitmap(256, 256) {
+ m_width = 0;
+ m_height = 0;
+#if 0
m_debug_bitmap.allocate(256, 256);
m_debug_bitmap.fill(Color32(0,0,0,0));
+#endif
}
-AtlasPacker::~AtlasPacker()
-{
+AtlasPacker::~AtlasPacker() {
}
// This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method.
-static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * minorAxis, Vector2 * minCorner, Vector2 * maxCorner)
-{
- // Compute list of boundary points.
- Array<Vector2> points(16);
+static bool computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorAxis, Vector2 *minCorner, Vector2 *maxCorner) {
+ // Compute list of boundary points.
+ Array<Vector2> points(16);
- HalfEdge::Mesh * mesh = chart->chartMesh();
- const uint vertexCount = mesh->vertexCount();
+ HalfEdge::Mesh *mesh = chart->chartMesh();
+ const uint vertexCount = mesh->vertexCount();
- for (uint i = 0; i < vertexCount; i++) {
- HalfEdge::Vertex * vertex = mesh->vertexAt(i);
- if (vertex->isBoundary()) {
- points.append(vertex->tex);
- }
- }
+ for (uint i = 0; i < vertexCount; i++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(i);
+ if (vertex->isBoundary()) {
+ points.append(vertex->tex);
+ }
+ }
- // This is not valid anymore. The chart mesh may have multiple boundaries!
- /*const HalfEdge::Vertex * vertex = findBoundaryVertex(chart->chartMesh());
+ // This is not valid anymore. The chart mesh may have multiple boundaries!
+ /*const HalfEdge::Vertex * vertex = findBoundaryVertex(chart->chartMesh());
// Traverse boundary.
const HalfEdge::Edge * const firstEdge = vertex->edge();
@@ -183,60 +178,60 @@ static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min
} while (edge != firstEdge);*/
#if 1
- Array<Vector2> hull;
- if (points.size()==0) {
- return false;
- }
-
- convexHull(points, hull, 0.00001f);
+ Array<Vector2> hull;
+ if (points.size() == 0) {
+ return false;
+ }
- // @@ Ideally I should use rotating calipers to find the best box. Using brute force for now.
+ convexHull(points, hull, 0.00001f);
- float best_area = FLT_MAX;
- Vector2 best_min;
- Vector2 best_max;
- Vector2 best_axis;
+ // @@ Ideally I should use rotating calipers to find the best box. Using brute force for now.
- const uint hullCount = hull.count();
- for (uint i = 0, j = hullCount-1; i < hullCount; j = i, i++) {
+ float best_area = FLT_MAX;
+ Vector2 best_min;
+ Vector2 best_max;
+ Vector2 best_axis;
- if (equal(hull[i], hull[j])) {
- continue;
- }
+ const uint hullCount = hull.count();
+ for (uint i = 0, j = hullCount - 1; i < hullCount; j = i, i++) {
- Vector2 axis = normalize(hull[i] - hull[j], 0.0f);
- nvDebugCheck(isFinite(axis));
+ if (equal(hull[i], hull[j])) {
+ continue;
+ }
- // Compute bounding box.
- Vector2 box_min(FLT_MAX, FLT_MAX);
- Vector2 box_max(-FLT_MAX, -FLT_MAX);
+ Vector2 axis = normalize(hull[i] - hull[j], 0.0f);
+ nvDebugCheck(isFinite(axis));
- for (uint v = 0; v < hullCount; v++) {
+ // Compute bounding box.
+ Vector2 box_min(FLT_MAX, FLT_MAX);
+ Vector2 box_max(-FLT_MAX, -FLT_MAX);
- Vector2 point = hull[v];
+ for (uint v = 0; v < hullCount; v++) {
- float x = dot(axis, point);
- if (x < box_min.x) box_min.x = x;
- if (x > box_max.x) box_max.x = x;
+ Vector2 point = hull[v];
- float y = dot(Vector2(-axis.y, axis.x), point);
- if (y < box_min.y) box_min.y = y;
- if (y > box_max.y) box_max.y = y;
- }
-
- // Compute box area.
- float area = (box_max.x - box_min.x) * (box_max.y - box_min.y);
-
- if (area < best_area) {
- best_area = area;
- best_min = box_min;
- best_max = box_max;
- best_axis = axis;
- }
- }
+ float x = dot(axis, point);
+ if (x < box_min.x) box_min.x = x;
+ if (x > box_max.x) box_max.x = x;
+
+ float y = dot(Vector2(-axis.y, axis.x), point);
+ if (y < box_min.y) box_min.y = y;
+ if (y > box_max.y) box_max.y = y;
+ }
+
+ // Compute box area.
+ float area = (box_max.x - box_min.x) * (box_max.y - box_min.y);
+
+ if (area < best_area) {
+ best_area = area;
+ best_min = box_min;
+ best_max = box_max;
+ best_axis = axis;
+ }
+ }
- // Make sure the box contains all the input points since the convex hull is not 100% accurate.
- /*const uint pointCount = points.count();
+ // Make sure the box contains all the input points since the convex hull is not 100% accurate.
+ /*const uint pointCount = points.count();
for (uint v = 0; v < pointCount; v++) {
Vector2 point = points[v];
@@ -248,124 +243,114 @@ static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min
if (y < best_min.y) best_min.y = y;
}*/
- // Consider all points, not only boundary points, in case the input chart is malformed.
- for (uint i = 0; i < vertexCount; i++) {
- HalfEdge::Vertex * vertex = mesh->vertexAt(i);
- Vector2 point = vertex->tex;
+ // Consider all points, not only boundary points, in case the input chart is malformed.
+ for (uint i = 0; i < vertexCount; i++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(i);
+ Vector2 point = vertex->tex;
- float x = dot(best_axis, point);
- if (x < best_min.x) best_min.x = x;
- if (x > best_max.x) best_max.x = x;
+ float x = dot(best_axis, point);
+ if (x < best_min.x) best_min.x = x;
+ if (x > best_max.x) best_max.x = x;
- float y = dot(Vector2(-best_axis.y, best_axis.x), point);
- if (y < best_min.y) best_min.y = y;
- if (y > best_max.y) best_max.y = y;
- }
+ float y = dot(Vector2(-best_axis.y, best_axis.x), point);
+ if (y < best_min.y) best_min.y = y;
+ if (y > best_max.y) best_max.y = y;
+ }
- *majorAxis = best_axis;
- *minorAxis = Vector2(-best_axis.y, best_axis.x);
- *minCorner = best_min;
- *maxCorner = best_max;
+ *majorAxis = best_axis;
+ *minorAxis = Vector2(-best_axis.y, best_axis.x);
+ *minCorner = best_min;
+ *maxCorner = best_max;
#else
- // Approximate implementation: try 16 different directions and keep the best.
-
- const uint N = 16;
- Vector2 axis[N];
-
- float minAngle = 0;
- float maxAngle = PI / 2;
-
- int best;
- Vector2 mins[N];
- Vector2 maxs[N];
-
- const int iterationCount = 1;
- for (int j = 0; j < iterationCount; j++)
- {
- // Init predefined directions.
- for (int i = 0; i < N; i++)
- {
- float angle = lerp(minAngle, maxAngle, float(i)/N);
- axis[i].set(cosf(angle), sinf(angle));
- }
+ // Approximate implementation: try 16 different directions and keep the best.
- // Compute box for each direction.
- for (int i = 0; i < N; i++)
- {
- mins[i].set(FLT_MAX, FLT_MAX);
- maxs[i].set(-FLT_MAX, -FLT_MAX);
- }
+ const uint N = 16;
+ Vector2 axis[N];
- for (uint p = 0; p < points.count(); p++)
- {
- Vector2 point = points[p];
+ float minAngle = 0;
+ float maxAngle = PI / 2;
- for (int i = 0; i < N; i++)
- {
- float x = dot(axis[i], point);
- if (x < mins[i].x) mins[i].x = x;
- if (x > maxs[i].x) maxs[i].x = x;
+ int best;
+ Vector2 mins[N];
+ Vector2 maxs[N];
- float y = dot(Vector2(-axis[i].y, axis[i].x), point);
- if (y < mins[i].y) mins[i].y = y;
- if (y > maxs[i].y) maxs[i].y = y;
- }
- }
+ const int iterationCount = 1;
+ for (int j = 0; j < iterationCount; j++) {
+ // Init predefined directions.
+ for (int i = 0; i < N; i++) {
+ float angle = lerp(minAngle, maxAngle, float(i) / N);
+ axis[i].set(cosf(angle), sinf(angle));
+ }
- // Find box with minimum area.
- best = -1;
- int second_best = -1;
- float best_area = FLT_MAX;
- float second_best_area = FLT_MAX;
-
- for (int i = 0; i < N; i++)
- {
- float area = (maxs[i].x - mins[i].x) * (maxs[i].y - mins[i].y);
+ // Compute box for each direction.
+ for (int i = 0; i < N; i++) {
+ mins[i].set(FLT_MAX, FLT_MAX);
+ maxs[i].set(-FLT_MAX, -FLT_MAX);
+ }
- if (area < best_area)
- {
- second_best_area = best_area;
- second_best = best;
+ for (uint p = 0; p < points.count(); p++) {
+ Vector2 point = points[p];
- best_area = area;
- best = i;
- }
- else if (area < second_best_area)
- {
- second_best_area = area;
- second_best = i;
- }
- }
- nvDebugCheck(best != -1);
- nvDebugCheck(second_best != -1);
- nvDebugCheck(best != second_best);
+ for (int i = 0; i < N; i++) {
+ float x = dot(axis[i], point);
+ if (x < mins[i].x) mins[i].x = x;
+ if (x > maxs[i].x) maxs[i].x = x;
- if (j != iterationCount-1)
- {
- // Handle wrap-around during the first iteration.
- if (j == 0) {
- if (best == 0 && second_best == N-1) best = N;
- if (best == N-1 && second_best == 0) second_best = N;
- }
-
- if (best < second_best) swap(best, second_best);
+ float y = dot(Vector2(-axis[i].y, axis[i].x), point);
+ if (y < mins[i].y) mins[i].y = y;
+ if (y > maxs[i].y) maxs[i].y = y;
+ }
+ }
- // Update angles.
- float deltaAngle = (maxAngle - minAngle) / N;
- maxAngle = minAngle + (best - 0.5f) * deltaAngle;
- minAngle = minAngle + (second_best + 0.5f) * deltaAngle;
- }
- }
+ // Find box with minimum area.
+ best = -1;
+ int second_best = -1;
+ float best_area = FLT_MAX;
+ float second_best_area = FLT_MAX;
+
+ for (int i = 0; i < N; i++) {
+ float area = (maxs[i].x - mins[i].x) * (maxs[i].y - mins[i].y);
+
+ if (area < best_area) {
+ second_best_area = best_area;
+ second_best = best;
+
+ best_area = area;
+ best = i;
+ } else if (area < second_best_area) {
+ second_best_area = area;
+ second_best = i;
+ }
+ }
+ nvDebugCheck(best != -1);
+ nvDebugCheck(second_best != -1);
+ nvDebugCheck(best != second_best);
+
+ if (j != iterationCount - 1) {
+ // Handle wrap-around during the first iteration.
+ if (j == 0) {
+ if (best == 0 && second_best == N - 1) best = N;
+ if (best == N - 1 && second_best == 0) second_best = N;
+ }
+
+ if (best < second_best) swap(best, second_best);
+
+ // Update angles.
+ float deltaAngle = (maxAngle - minAngle) / N;
+ maxAngle = minAngle + (best - 0.5f) * deltaAngle;
+ minAngle = minAngle + (second_best + 0.5f) * deltaAngle;
+ }
+ }
- // Compute major and minor axis, and origin.
- *majorAxis = axis[best];
- *minorAxis = Vector2(-axis[best].y, axis[best].x);
- *origin = mins[best];
+ // Compute major and minor axis, and origin.
+ *majorAxis = axis[best];
+ *minorAxis = Vector2(-axis[best].y, axis[best].x);
+ *origin = mins[best];
- // @@ If the parameterization is invalid, we could have an interior vertex outside the boundary.
- // @@ In that case the returned bounding box would be incorrect. Compute updated bounds here.
- /*for (uint p = 0; p < points.count(); p++)
+ // @@ If the parameterization is invalid, we could have an interior vertex outside the boundary.
+ // @@ In that case the returned bounding box would be incorrect. Compute updated bounds here.
+ /*for (uint p = 0; p < points.count(); p++)
{
Vector2 point = points[p];
@@ -377,208 +362,199 @@ static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min
}*/
#endif
- return true;
+ return true;
}
+void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned, bool conservative) {
+ const uint chartCount = m_atlas->chartCount();
+ if (chartCount == 0) return;
-void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned, bool conservative)
-{
- const uint chartCount = m_atlas->chartCount();
- if (chartCount == 0) return;
+ Array<float> chartOrderArray;
+ chartOrderArray.resize(chartCount);
- Array<float> chartOrderArray;
- chartOrderArray.resize(chartCount);
+ Array<Vector2> chartExtents;
+ chartExtents.resize(chartCount);
- Array<Vector2> chartExtents;
- chartExtents.resize(chartCount);
-
- float meshArea = 0;
- for (uint c = 0; c < chartCount; c++)
- {
- Chart * chart = m_atlas->chartAt(c);
-
- if (!chart->isVertexMapped() && !chart->isDisk()) {
- chartOrderArray[c] = 0;
-
- // Skip non-disks.
- continue;
- }
-
- Vector2 extents(0.0f);
-
- if (chart->isVertexMapped()) {
- // Let's assume vertex maps are arranged in a rectangle.
- //HalfEdge::Mesh * mesh = chart->chartMesh();
-
- // Arrange vertices in a rectangle.
- extents.x = float(chart->vertexMapWidth);
- extents.y = float(chart->vertexMapHeight);
- }
- else {
- // Compute surface area to sort charts.
- float chartArea = chart->computeSurfaceArea();
- meshArea += chartArea;
- //chartOrderArray[c] = chartArea;
-
- // Compute chart scale
- float parametricArea = fabs(chart->computeParametricArea()); // @@ There doesn't seem to be anything preventing parametric area to be negative.
- if (parametricArea < NV_EPSILON) {
- // When the parametric area is too small we use a rough approximation to prevent divisions by very small numbers.
- Vector2 bounds = chart->computeParametricBounds();
- parametricArea = bounds.x * bounds.y;
- }
- float scale = (chartArea / parametricArea) * texelsPerUnit;
- if (parametricArea == 0) // < NV_EPSILON)
- {
- scale = 0;
- }
- nvCheck(isFinite(scale));
+ float meshArea = 0;
+ for (uint c = 0; c < chartCount; c++) {
+ Chart *chart = m_atlas->chartAt(c);
- // Compute bounding box of chart.
- Vector2 majorAxis, minorAxis, origin, end;
- if (!computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end)) {
- m_atlas->setFailed();
- return;
- }
+ if (!chart->isVertexMapped() && !chart->isDisk()) {
+ chartOrderArray[c] = 0;
- nvCheck(isFinite(majorAxis) && isFinite(minorAxis) && isFinite(origin));
-
- // Sort charts by perimeter. @@ This is sometimes producing somewhat unexpected results. Is this right?
- //chartOrderArray[c] = ((end.x - origin.x) + (end.y - origin.y)) * scale;
+ // Skip non-disks.
+ continue;
+ }
- // Translate, rotate and scale vertices. Compute extents.
- HalfEdge::Mesh * mesh = chart->chartMesh();
- const uint vertexCount = mesh->vertexCount();
- for (uint i = 0; i < vertexCount; i++)
- {
- HalfEdge::Vertex * vertex = mesh->vertexAt(i);
-
- //Vector2 t = vertex->tex - origin;
- Vector2 tmp;
- tmp.x = dot(vertex->tex, majorAxis);
- tmp.y = dot(vertex->tex, minorAxis);
- tmp -= origin;
- tmp *= scale;
- if (tmp.x < 0 || tmp.y < 0) {
- nvDebug("tmp: %f %f\n", tmp.x, tmp.y);
- nvDebug("scale: %f\n", scale);
- nvDebug("origin: %f %f\n", origin.x, origin.y);
- nvDebug("majorAxis: %f %f\n", majorAxis.x, majorAxis.y);
- nvDebug("minorAxis: %f %f\n", minorAxis.x, minorAxis.y);
- nvDebugBreak();
- }
- //nvCheck(tmp.x >= 0 && tmp.y >= 0);
-
- vertex->tex = tmp;
+ Vector2 extents(0.0f);
+
+ if (chart->isVertexMapped()) {
+ // Let's assume vertex maps are arranged in a rectangle.
+ //HalfEdge::Mesh * mesh = chart->chartMesh();
+
+ // Arrange vertices in a rectangle.
+ extents.x = float(chart->vertexMapWidth);
+ extents.y = float(chart->vertexMapHeight);
+ } else {
+ // Compute surface area to sort charts.
+ float chartArea = chart->computeSurfaceArea();
+ meshArea += chartArea;
+ //chartOrderArray[c] = chartArea;
+
+ // Compute chart scale
+ float parametricArea = fabs(chart->computeParametricArea()); // @@ There doesn't seem to be anything preventing parametric area to be negative.
+ if (parametricArea < NV_EPSILON) {
+ // When the parametric area is too small we use a rough approximation to prevent divisions by very small numbers.
+ Vector2 bounds = chart->computeParametricBounds();
+ parametricArea = bounds.x * bounds.y;
+ }
+ float scale = (chartArea / parametricArea) * texelsPerUnit;
+ if (parametricArea == 0) // < NV_EPSILON)
+ {
+ scale = 0;
+ }
+ nvCheck(isFinite(scale));
+
+ // Compute bounding box of chart.
+ Vector2 majorAxis, minorAxis, origin, end;
+ if (!computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end)) {
+ m_atlas->setFailed();
+ return;
+ }
+
+ nvCheck(isFinite(majorAxis) && isFinite(minorAxis) && isFinite(origin));
+
+ // Sort charts by perimeter. @@ This is sometimes producing somewhat unexpected results. Is this right?
+ //chartOrderArray[c] = ((end.x - origin.x) + (end.y - origin.y)) * scale;
+
+ // Translate, rotate and scale vertices. Compute extents.
+ HalfEdge::Mesh *mesh = chart->chartMesh();
+ const uint vertexCount = mesh->vertexCount();
+ for (uint i = 0; i < vertexCount; i++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(i);
+
+ //Vector2 t = vertex->tex - origin;
+ Vector2 tmp;
+ tmp.x = dot(vertex->tex, majorAxis);
+ tmp.y = dot(vertex->tex, minorAxis);
+ tmp -= origin;
+ tmp *= scale;
+ if (tmp.x < 0 || tmp.y < 0) {
+ nvDebug("tmp: %f %f\n", tmp.x, tmp.y);
+ nvDebug("scale: %f\n", scale);
+ nvDebug("origin: %f %f\n", origin.x, origin.y);
+ nvDebug("majorAxis: %f %f\n", majorAxis.x, majorAxis.y);
+ nvDebug("minorAxis: %f %f\n", minorAxis.x, minorAxis.y);
+ nvDebugBreak();
+ }
+ //nvCheck(tmp.x >= 0 && tmp.y >= 0);
+
+ vertex->tex = tmp;
nvCheck(isFinite(vertex->tex.x) && isFinite(vertex->tex.y));
- extents = max(extents, tmp);
- }
- nvDebugCheck(extents.x >= 0 && extents.y >= 0);
+ extents = max(extents, tmp);
+ }
+ nvDebugCheck(extents.x >= 0 && extents.y >= 0);
- // Limit chart size.
- if (extents.x > 1024 || extents.y > 1024) {
- float limit = max(extents.x, extents.y);
+ // Limit chart size.
+ if (extents.x > 1024 || extents.y > 1024) {
+ float limit = max(extents.x, extents.y);
- scale = 1024 / (limit + 1);
+ scale = 1024 / (limit + 1);
- for (uint i = 0; i < vertexCount; i++)
- {
- HalfEdge::Vertex * vertex = mesh->vertexAt(i);
- vertex->tex *= scale;
- }
+ for (uint i = 0; i < vertexCount; i++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(i);
+ vertex->tex *= scale;
+ }
- extents *= scale;
+ extents *= scale;
- nvDebugCheck(extents.x <= 1024 && extents.y <= 1024);
- }
+ nvDebugCheck(extents.x <= 1024 && extents.y <= 1024);
+ }
+ // Scale the charts to use the entire texel area available. So, if the width is 0.1 we could scale it to 1 without increasing the lightmap usage and making a better
+ // use of it. In many cases this also improves the look of the seams, since vertices on the chart boundaries have more chances of being aligned with the texel centers.
- // Scale the charts to use the entire texel area available. So, if the width is 0.1 we could scale it to 1 without increasing the lightmap usage and making a better
- // use of it. In many cases this also improves the look of the seams, since vertices on the chart boundaries have more chances of being aligned with the texel centers.
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
- float scale_x = 1.0f;
- float scale_y = 1.0f;
+ float divide_x = 1.0f;
+ float divide_y = 1.0f;
- float divide_x = 1.0f;
- float divide_y = 1.0f;
+ if (extents.x > 0) {
+ int cw = ftoi_ceil(extents.x);
- if (extents.x > 0) {
- int cw = ftoi_ceil(extents.x);
+ if (blockAligned) {
+ // Align all chart extents to 4x4 blocks, but taking padding into account.
+ if (conservative) {
+ cw = align(cw + 2, 4) - 2;
+ } else {
+ cw = align(cw + 1, 4) - 1;
+ }
+ }
- if (blockAligned) {
- // Align all chart extents to 4x4 blocks, but taking padding into account.
- if (conservative) {
- cw = align(cw + 2, 4) - 2;
- }
- else {
- cw = align(cw + 1, 4) - 1;
- }
- }
+ scale_x = (float(cw) - NV_EPSILON);
+ divide_x = extents.x;
+ extents.x = float(cw);
+ }
- scale_x = (float(cw) - NV_EPSILON);
- divide_x = extents.x;
- extents.x = float(cw);
- }
+ if (extents.y > 0) {
+ int ch = ftoi_ceil(extents.y);
- if (extents.y > 0) {
- int ch = ftoi_ceil(extents.y);
-
- if (blockAligned) {
- // Align all chart extents to 4x4 blocks, but taking padding into account.
- if (conservative) {
- ch = align(ch + 2, 4) - 2;
- }
- else {
- ch = align(ch + 1, 4) - 1;
- }
- }
-
- scale_y = (float(ch) - NV_EPSILON);
- divide_y = extents.y;
- extents.y = float(ch);
- }
+ if (blockAligned) {
+ // Align all chart extents to 4x4 blocks, but taking padding into account.
+ if (conservative) {
+ ch = align(ch + 2, 4) - 2;
+ } else {
+ ch = align(ch + 1, 4) - 1;
+ }
+ }
+
+ scale_y = (float(ch) - NV_EPSILON);
+ divide_y = extents.y;
+ extents.y = float(ch);
+ }
- for (uint v = 0; v < vertexCount; v++) {
- HalfEdge::Vertex * vertex = mesh->vertexAt(v);
+ for (uint v = 0; v < vertexCount; v++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(v);
- vertex->tex.x /= divide_x;
- vertex->tex.y /= divide_y;
- vertex->tex.x *= scale_x;
- vertex->tex.y *= scale_y;
+ vertex->tex.x /= divide_x;
+ vertex->tex.y /= divide_y;
+ vertex->tex.x *= scale_x;
+ vertex->tex.y *= scale_y;
nvCheck(isFinite(vertex->tex.x) && isFinite(vertex->tex.y));
- }
- }
+ }
+ }
- chartExtents[c] = extents;
+ chartExtents[c] = extents;
- // Sort charts by perimeter.
- chartOrderArray[c] = extents.x + extents.y;
- }
+ // Sort charts by perimeter.
+ chartOrderArray[c] = extents.x + extents.y;
+ }
- // @@ We can try to improve compression of small charts by sorting them by proximity like we do with vertex samples.
- // @@ How to do that? One idea: compute chart centroid, insert into grid, compute morton index of the cell, sort based on morton index.
- // @@ We would sort by morton index, first, then quantize the chart sizes, so that all small charts have the same size, and sort by size preserving the morton order.
+ // @@ We can try to improve compression of small charts by sorting them by proximity like we do with vertex samples.
+ // @@ How to do that? One idea: compute chart centroid, insert into grid, compute morton index of the cell, sort based on morton index.
+ // @@ We would sort by morton index, first, then quantize the chart sizes, so that all small charts have the same size, and sort by size preserving the morton order.
- //nvDebug("Sorting charts.\n");
+ //nvDebug("Sorting charts.\n");
- // Sort charts by area.
- m_radix.sort(chartOrderArray);
- const uint32 * ranks = m_radix.ranks();
+ // Sort charts by area.
+ m_radix.sort(chartOrderArray);
+ const uint32 *ranks = m_radix.ranks();
- // Estimate size of the map based on the mesh surface area and given texel scale.
- float texelCount = meshArea * square(texelsPerUnit) / 0.75f; // Assume 75% utilization.
- if (texelCount < 1) texelCount = 1;
- uint approximateExtent = nextPowerOfTwo(uint(sqrtf(texelCount)));
+ // Estimate size of the map based on the mesh surface area and given texel scale.
+ float texelCount = meshArea * square(texelsPerUnit) / 0.75f; // Assume 75% utilization.
+ if (texelCount < 1) texelCount = 1;
+ uint approximateExtent = nextPowerOfTwo(uint(sqrtf(texelCount)));
- //nvDebug("Init bitmap.\n");
+ //nvDebug("Init bitmap.\n");
- // @@ Pack all charts smaller than a texel into a compact rectangle.
- // @@ Start considering only 1x1 charts. Extend to 1xn charts later.
+ // @@ Pack all charts smaller than a texel into a compact rectangle.
+ // @@ Start considering only 1x1 charts. Extend to 1xn charts later.
- /*for (uint i = 0; i < chartCount; i++)
+ /*for (uint i = 0; i < chartCount; i++)
{
uint c = ranks[chartCount - i - 1]; // largest chart first
@@ -591,206 +567,201 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
}
}*/
-
-
- // Init bit map.
- m_bitmap.clearAll();
- if (approximateExtent > m_bitmap.width()) {
- m_bitmap.resize(approximateExtent, approximateExtent, false);
+ // Init bit map.
+ m_bitmap.clearAll();
+ if (approximateExtent > m_bitmap.width()) {
+ m_bitmap.resize(approximateExtent, approximateExtent, false);
+#if 0
m_debug_bitmap.resize(approximateExtent, approximateExtent);
m_debug_bitmap.fill(Color32(0,0,0,0));
- }
+#endif
+ }
-
- int w = 0;
- int h = 0;
+ int w = 0;
+ int h = 0;
#if 1
- // Add sorted charts to bitmap.
- for (uint i = 0; i < chartCount; i++)
- {
- uint c = ranks[chartCount - i - 1]; // largest chart first
+ // Add sorted charts to bitmap.
+ for (uint i = 0; i < chartCount; i++) {
+ uint c = ranks[chartCount - i - 1]; // largest chart first
- Chart * chart = m_atlas->chartAt(c);
+ Chart *chart = m_atlas->chartAt(c);
- if (!chart->isVertexMapped() && !chart->isDisk()) continue;
+ if (!chart->isVertexMapped() && !chart->isDisk()) continue;
- //float scale_x = 1;
- //float scale_y = 1;
+ //float scale_x = 1;
+ //float scale_y = 1;
- BitMap chart_bitmap;
+ BitMap chart_bitmap;
- if (chart->isVertexMapped()) {
- // Init all bits to 1.
- chart_bitmap.resize(ftoi_ceil(chartExtents[c].x), ftoi_ceil(chartExtents[c].y), /*initValue=*/true);
+ if (chart->isVertexMapped()) {
+ // Init all bits to 1.
+ chart_bitmap.resize(ftoi_ceil(chartExtents[c].x), ftoi_ceil(chartExtents[c].y), /*initValue=*/true);
- // @@ Another alternative would be to try to map each vertex to a different texel trying to fill all the available unused texels.
- }
- else {
- // @@ Add special cases for dot and line charts. @@ Lightmap rasterizer also needs to handle these special cases.
- // @@ We could also have a special case for chart quads. If the quad surface <= 4 texels, align vertices with texel centers and do not add padding. May be very useful for foliage.
-
- // @@ In general we could reduce the padding of all charts by one texel by using a rasterizer that takes into account the 2-texel footprint of the tent bilinear filter. For example,
- // if we have a chart that is less than 1 texel wide currently we add one texel to the left and one texel to the right creating a 3-texel-wide bitmap. However, if we know that the
- // chart is only 1 texel wide we could align it so that it only touches the footprint of two texels:
-
- // | | <- Touches texels 0, 1 and 2.
- // | | <- Only touches texels 0 and 1.
- // \ \ / \ / /
- // \ X X /
- // \ / \ / \ /
- // V V V
- // 0 1 2
-
- if (conservative) {
- // Init all bits to 0.
- chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 2, ftoi_ceil(chartExtents[c].y) + 2, /*initValue=*/false); // + 2 to add padding on both sides.
-
- // Rasterize chart and dilate.
- drawChartBitmapDilate(chart, &chart_bitmap, /*padding=*/1);
- }
- else {
- // Init all bits to 0.
- chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 1, ftoi_ceil(chartExtents[c].y) + 1, /*initValue=*/false); // Add half a texels on each side.
+ // @@ Another alternative would be to try to map each vertex to a different texel trying to fill all the available unused texels.
+ } else {
+ // @@ Add special cases for dot and line charts. @@ Lightmap rasterizer also needs to handle these special cases.
+ // @@ We could also have a special case for chart quads. If the quad surface <= 4 texels, align vertices with texel centers and do not add padding. May be very useful for foliage.
- // Rasterize chart and dilate.
- drawChartBitmap(chart, &chart_bitmap, Vector2(1), Vector2(0.5));
- }
- }
+ // @@ In general we could reduce the padding of all charts by one texel by using a rasterizer that takes into account the 2-texel footprint of the tent bilinear filter. For example,
+ // if we have a chart that is less than 1 texel wide currently we add one texel to the left and one texel to the right creating a 3-texel-wide bitmap. However, if we know that the
+ // chart is only 1 texel wide we could align it so that it only touches the footprint of two texels:
- int best_x, best_y;
- int best_cw, best_ch; // Includes padding now.
- int best_r;
- findChartLocation(quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r);
-
- /*if (w < best_x + best_cw || h < best_y + best_ch)
+ // | | <- Touches texels 0, 1 and 2.
+ // | | <- Only touches texels 0 and 1.
+ // \ \ / \ / /
+ // \ X X /
+ // \ / \ / \ /
+ // V V V
+ // 0 1 2
+
+ if (conservative) {
+ // Init all bits to 0.
+ chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 2, ftoi_ceil(chartExtents[c].y) + 2, /*initValue=*/false); // + 2 to add padding on both sides.
+
+ // Rasterize chart and dilate.
+ drawChartBitmapDilate(chart, &chart_bitmap, /*padding=*/1);
+ } else {
+ // Init all bits to 0.
+ chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 1, ftoi_ceil(chartExtents[c].y) + 1, /*initValue=*/false); // Add half a texels on each side.
+
+ // Rasterize chart and dilate.
+ drawChartBitmap(chart, &chart_bitmap, Vector2(1), Vector2(0.5));
+ }
+ }
+
+ int best_x, best_y;
+ int best_cw, best_ch; // Includes padding now.
+ int best_r;
+ findChartLocation(quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r);
+
+ /*if (w < best_x + best_cw || h < best_y + best_ch)
{
nvDebug("Resize extents to (%d, %d).\n", best_x + best_cw, best_y + best_ch);
}*/
- // Update parametric extents.
- w = max(w, best_x + best_cw);
- h = max(h, best_y + best_ch);
-
- w = align(w, 4);
- h = align(h, 4);
+ // Update parametric extents.
+ w = max(w, best_x + best_cw);
+ h = max(h, best_y + best_ch);
- // Resize bitmap if necessary.
- if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height())
- {
- //nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
- m_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h)), false);
+ w = align(w, 4);
+ h = align(h, 4);
+
+ // Resize bitmap if necessary.
+ if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height()) {
+ //nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
+ m_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h)), false);
+#if 0
m_debug_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h)));
- }
+#endif
+ }
- //nvDebug("Add chart at (%d, %d).\n", best_x, best_y);
+ //nvDebug("Add chart at (%d, %d).\n", best_x, best_y);
- addChart(&chart_bitmap, w, h, best_x, best_y, best_r, /*debugOutput=*/NULL);
+ addChart(&chart_bitmap, w, h, best_x, best_y, best_r, /*debugOutput=*/NULL);
- // IC: Output chart again to debug bitmap.
+ // IC: Output chart again to debug bitmap.
+#if 0
if (chart->isVertexMapped()) {
addChart(&chart_bitmap, w, h, best_x, best_y, best_r, &m_debug_bitmap);
}
else {
addChart(chart, w, h, best_x, best_y, best_r, &m_debug_bitmap);
}
+#endif
+ //float best_angle = 2 * PI * best_r;
- //float best_angle = 2 * PI * best_r;
-
- // Translate and rotate chart texture coordinates.
- HalfEdge::Mesh * mesh = chart->chartMesh();
- const uint vertexCount = mesh->vertexCount();
- for (uint v = 0; v < vertexCount; v++)
- {
- HalfEdge::Vertex * vertex = mesh->vertexAt(v);
+ // Translate and rotate chart texture coordinates.
+ HalfEdge::Mesh *mesh = chart->chartMesh();
+ const uint vertexCount = mesh->vertexCount();
+ for (uint v = 0; v < vertexCount; v++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(v);
- Vector2 t = vertex->tex;
- if (best_r) swap(t.x, t.y);
- //vertex->tex.x = best_x + t.x * cosf(best_angle) - t.y * sinf(best_angle);
- //vertex->tex.y = best_y + t.x * sinf(best_angle) + t.y * cosf(best_angle);
+ Vector2 t = vertex->tex;
+ if (best_r) swap(t.x, t.y);
+ //vertex->tex.x = best_x + t.x * cosf(best_angle) - t.y * sinf(best_angle);
+ //vertex->tex.y = best_y + t.x * sinf(best_angle) + t.y * cosf(best_angle);
- vertex->tex.x = best_x + t.x + 0.5f;
- vertex->tex.y = best_y + t.y + 0.5f;
+ vertex->tex.x = best_x + t.x + 0.5f;
+ vertex->tex.y = best_y + t.y + 0.5f;
- nvCheck(vertex->tex.x >= 0 && vertex->tex.y >= 0);
+ nvCheck(vertex->tex.x >= 0 && vertex->tex.y >= 0);
nvCheck(isFinite(vertex->tex.x) && isFinite(vertex->tex.y));
- }
+ }
#if DEBUG_OUTPUT && 0
- StringBuilder fileName;
- fileName.format("debug_packer_%d.tga", i);
- //outputDebugBitmap(fileName.str(), m_bitmap, w, h);
- outputDebugImage(fileName.str(), m_debug_bitmap, w, h);
+ StringBuilder fileName;
+ fileName.format("debug_packer_%d.tga", i);
+ //outputDebugBitmap(fileName.str(), m_bitmap, w, h);
+ outputDebugImage(fileName.str(), m_debug_bitmap, w, h);
#endif
- }
+ }
#else // 0
- // Add sorted charts to bitmap.
- for (uint i = 0; i < chartCount; i++)
- {
- uint c = ranks[chartCount - i - 1]; // largest chart first
+ // Add sorted charts to bitmap.
+ for (uint i = 0; i < chartCount; i++) {
+ uint c = ranks[chartCount - i - 1]; // largest chart first
- Chart * chart = m_atlas->chartAt(c);
+ Chart *chart = m_atlas->chartAt(c);
- if (!chart->isDisk()) continue;
+ if (!chart->isDisk()) continue;
- Vector2 scale(1, 1);
+ Vector2 scale(1, 1);
-#if 0 // old method.
- //m_padding_x = 2*padding;
- //m_padding_y = 2*padding;
+#if 0 // old method. \
+ //m_padding_x = 2*padding; \
+ //m_padding_y = 2*padding;
#else
- //m_padding_x = 0; //padding;
- //m_padding_y = 0; //padding;
+ //m_padding_x = 0; //padding;
+ //m_padding_y = 0; //padding;
#endif
- int bw = ftoi_ceil(chartExtents[c].x + 1);
- int bh = ftoi_ceil(chartExtents[c].y + 1);
+ int bw = ftoi_ceil(chartExtents[c].x + 1);
+ int bh = ftoi_ceil(chartExtents[c].y + 1);
- if (chartExtents[c].x < 1.0f) {
- scale.x = 0.01f; // @@ Ideally we would like to scale it to 0, but then our rasterizer would not touch any pixels.
- bw = 1;
- }
- if (chartExtents[c].y < 1.0f) {
- scale.y = 0.01f;
- bh = 1;
- }
+ if (chartExtents[c].x < 1.0f) {
+ scale.x = 0.01f; // @@ Ideally we would like to scale it to 0, but then our rasterizer would not touch any pixels.
+ bw = 1;
+ }
+ if (chartExtents[c].y < 1.0f) {
+ scale.y = 0.01f;
+ bh = 1;
+ }
- //BitMap chart_bitmap(iceil(chartExtents[c].x) + 1 + m_padding_x * 2, iceil(chartExtents[c].y) + 1 + m_padding_y * 2);
- //BitMap chart_bitmap(ftoi_ceil(chartExtents[c].x/2)*2, ftoi_ceil(chartExtents[c].y/2)*2);
- BitMap chart_bitmap(bw, bh);
- chart_bitmap.clearAll();
-
- Vector2 offset;
- offset.x = 0; // (chart_bitmap.width() - chartExtents[c].x) * 0.5f;
- offset.y = 0; // (chart_bitmap.height() - chartExtents[c].y) * 0.5f;
+ //BitMap chart_bitmap(iceil(chartExtents[c].x) + 1 + m_padding_x * 2, iceil(chartExtents[c].y) + 1 + m_padding_y * 2);
+ //BitMap chart_bitmap(ftoi_ceil(chartExtents[c].x/2)*2, ftoi_ceil(chartExtents[c].y/2)*2);
+ BitMap chart_bitmap(bw, bh);
+ chart_bitmap.clearAll();
- drawChartBitmap(chart, &chart_bitmap, scale, offset);
+ Vector2 offset;
+ offset.x = 0; // (chart_bitmap.width() - chartExtents[c].x) * 0.5f;
+ offset.y = 0; // (chart_bitmap.height() - chartExtents[c].y) * 0.5f;
- int best_x, best_y;
- int best_cw, best_ch;
- int best_r;
- findChartLocation(quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r);
+ drawChartBitmap(chart, &chart_bitmap, scale, offset);
- /*if (w < best_x + best_cw || h < best_y + best_ch)
+ int best_x, best_y;
+ int best_cw, best_ch;
+ int best_r;
+ findChartLocation(quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r);
+
+ /*if (w < best_x + best_cw || h < best_y + best_ch)
{
nvDebug("Resize extents to (%d, %d).\n", best_x + best_cw, best_y + best_ch);
}*/
- // Update parametric extents.
- w = max(w, best_x + best_cw);
- h = max(h, best_y + best_ch);
+ // Update parametric extents.
+ w = max(w, best_x + best_cw);
+ h = max(h, best_y + best_ch);
- // Resize bitmap if necessary.
- if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height())
- {
- //nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
- m_bitmap.resize(nextPowerOfTwo(w), nextPowerOfTwo(h), false);
- m_debug_bitmap.resize(nextPowerOfTwo(w), nextPowerOfTwo(h));
- }
+ // Resize bitmap if necessary.
+ if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height()) {
+ //nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
+ m_bitmap.resize(nextPowerOfTwo(w), nextPowerOfTwo(h), false);
+ m_debug_bitmap.resize(nextPowerOfTwo(w), nextPowerOfTwo(h));
+ }
- //nvDebug("Add chart at (%d, %d).\n", best_x, best_y);
+ //nvDebug("Add chart at (%d, %d).\n", best_x, best_y);
#if 0 // old method.
#if _DEBUG
@@ -800,387 +771,354 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Add chart.
addChart(chart, w, h, best_x, best_y, best_r);
#else
- // Add chart reusing its bitmap.
- addChart(&chart_bitmap, w, h, best_x, best_y, best_r);
+ // Add chart reusing its bitmap.
+ addChart(&chart_bitmap, w, h, best_x, best_y, best_r);
#endif
- //float best_angle = 2 * PI * best_r;
+ //float best_angle = 2 * PI * best_r;
- // Translate and rotate chart texture coordinates.
- HalfEdge::Mesh * mesh = chart->chartMesh();
- const uint vertexCount = mesh->vertexCount();
- for (uint v = 0; v < vertexCount; v++)
- {
- HalfEdge::Vertex * vertex = mesh->vertexAt(v);
+ // Translate and rotate chart texture coordinates.
+ HalfEdge::Mesh *mesh = chart->chartMesh();
+ const uint vertexCount = mesh->vertexCount();
+ for (uint v = 0; v < vertexCount; v++) {
+ HalfEdge::Vertex *vertex = mesh->vertexAt(v);
- Vector2 t = vertex->tex * scale + offset;
- if (best_r) swap(t.x, t.y);
- //vertex->tex.x = best_x + t.x * cosf(best_angle) - t.y * sinf(best_angle);
- //vertex->tex.y = best_y + t.x * sinf(best_angle) + t.y * cosf(best_angle);
- vertex->tex.x = best_x + t.x + 0.5f;
- vertex->tex.y = best_y + t.y + 0.5f;
+ Vector2 t = vertex->tex * scale + offset;
+ if (best_r) swap(t.x, t.y);
+ //vertex->tex.x = best_x + t.x * cosf(best_angle) - t.y * sinf(best_angle);
+ //vertex->tex.y = best_y + t.x * sinf(best_angle) + t.y * cosf(best_angle);
+ vertex->tex.x = best_x + t.x + 0.5f;
+ vertex->tex.y = best_y + t.y + 0.5f;
- nvCheck(vertex->tex.x >= 0 && vertex->tex.y >= 0);
- }
+ nvCheck(vertex->tex.x >= 0 && vertex->tex.y >= 0);
+ }
#if DEBUG_OUTPUT && 0
- StringBuilder fileName;
- fileName.format("debug_packer_%d.tga", i);
- //outputDebugBitmap(fileName.str(), m_bitmap, w, h);
- outputDebugImage(fileName.str(), m_debug_bitmap, w, h);
+ StringBuilder fileName;
+ fileName.format("debug_packer_%d.tga", i);
+ //outputDebugBitmap(fileName.str(), m_bitmap, w, h);
+ outputDebugImage(fileName.str(), m_debug_bitmap, w, h);
#endif
- }
+ }
#endif // 0
- //w -= padding - 1; // Leave one pixel border!
- //h -= padding - 1;
-
- m_width = max(0, w);
- m_height = max(0, h);
+ //w -= padding - 1; // Leave one pixel border!
+ //h -= padding - 1;
- nvCheck(isAligned(m_width, 4));
- nvCheck(isAligned(m_height, 4));
+ m_width = max(0, w);
+ m_height = max(0, h);
+ nvCheck(isAligned(m_width, 4));
+ nvCheck(isAligned(m_height, 4));
+#if 0
m_debug_bitmap.resize(m_width, m_height);
m_debug_bitmap.setFormat(Image::Format_ARGB);
-
+#endif
#if DEBUG_OUTPUT
- //outputDebugBitmap("debug_packer_final.tga", m_bitmap, w, h);
- //outputDebugImage("debug_packer_final.tga", m_debug_bitmap, w, h);
- ImageIO::save("debug_packer_final.tga", &m_debug_bitmap);
+ //outputDebugBitmap("debug_packer_final.tga", m_bitmap, w, h);
+ //outputDebugImage("debug_packer_final.tga", m_debug_bitmap, w, h);
+ ImageIO::save("debug_packer_final.tga", &m_debug_bitmap);
#endif
}
-
-// IC: Brute force is slow, and random may take too much time to converge. We start inserting large charts in a small atlas. Using brute force is lame, because most of the space
-// is occupied at this point. At the end we have many small charts and a large atlas with sparse holes. Finding those holes randomly is slow. A better approach would be to
-// start stacking large charts as if they were tetris pieces. Once charts get small try to place them randomly. It may be interesting to try a intermediate strategy, first try
+// IC: Brute force is slow, and random may take too much time to converge. We start inserting large charts in a small atlas. Using brute force is lame, because most of the space
+// is occupied at this point. At the end we have many small charts and a large atlas with sparse holes. Finding those holes randomly is slow. A better approach would be to
+// start stacking large charts as if they were tetris pieces. Once charts get small try to place them randomly. It may be interesting to try a intermediate strategy, first try
// along one axis and then try exhaustively along that axis.
-void AtlasPacker::findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r)
-{
- int attempts = 256;
- if (quality == 1) attempts = 4096;
- if (quality == 2) attempts = 2048;
- if (quality == 3) attempts = 1024;
- if (quality == 4) attempts = 512;
-
- if (quality == 0 || w*h < attempts)
- {
- findChartLocation_bruteForce(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r);
- }
- else
- {
- findChartLocation_random(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, attempts);
- }
+void AtlasPacker::findChartLocation(int quality, const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r) {
+ int attempts = 256;
+ if (quality == 1) attempts = 4096;
+ if (quality == 2) attempts = 2048;
+ if (quality == 3) attempts = 1024;
+ if (quality == 4) attempts = 512;
+
+ if (quality == 0 || w * h < attempts) {
+ findChartLocation_bruteForce(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r);
+ } else {
+ findChartLocation_random(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, attempts);
+ }
}
#define BLOCK_SIZE 4
-void AtlasPacker::findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r)
-{
- int best_metric = INT_MAX;
-
- // Try two different orientations.
- for (int r = 0; r < 2; r++)
- {
- int cw = bitmap->width();
- int ch = bitmap->height();
- if (r & 1) swap(cw, ch);
-
- for (int y = 0; y <= h + 1; y += BLOCK_SIZE) // + 1 to extend atlas in case atlas full.
- {
- for (int x = 0; x <= w + 1; x += BLOCK_SIZE) // + 1 not really necessary here.
- {
- // Early out.
- int area = max(w, x+cw) * max(h, y+ch);
- //int perimeter = max(w, x+cw) + max(h, y+ch);
- int extents = max(max(w, x+cw), max(h, y+ch));
-
- int metric = extents*extents + area;
-
- if (metric > best_metric) {
- continue;
- }
- if (metric == best_metric && max(x, y) >= max(*best_x, *best_y)) {
- // If metric is the same, pick the one closest to the origin.
- continue;
- }
-
- if (canAddChart(bitmap, w, h, x, y, r))
- {
- best_metric = metric;
- *best_x = x;
- *best_y = y;
- *best_w = cw;
- *best_h = ch;
- *best_r = r;
-
- if (area == w*h)
- {
- // Chart is completely inside, do not look at any other location.
- goto done;
- }
- }
- }
- }
- }
+void AtlasPacker::findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r) {
+ int best_metric = INT_MAX;
+
+ // Try two different orientations.
+ for (int r = 0; r < 2; r++) {
+ int cw = bitmap->width();
+ int ch = bitmap->height();
+ if (r & 1) swap(cw, ch);
+
+ for (int y = 0; y <= h + 1; y += BLOCK_SIZE) // + 1 to extend atlas in case atlas full.
+ {
+ for (int x = 0; x <= w + 1; x += BLOCK_SIZE) // + 1 not really necessary here.
+ {
+ // Early out.
+ int area = max(w, x + cw) * max(h, y + ch);
+ //int perimeter = max(w, x+cw) + max(h, y+ch);
+ int extents = max(max(w, x + cw), max(h, y + ch));
+
+ int metric = extents * extents + area;
+
+ if (metric > best_metric) {
+ continue;
+ }
+ if (metric == best_metric && max(x, y) >= max(*best_x, *best_y)) {
+ // If metric is the same, pick the one closest to the origin.
+ continue;
+ }
+
+ if (canAddChart(bitmap, w, h, x, y, r)) {
+ best_metric = metric;
+ *best_x = x;
+ *best_y = y;
+ *best_w = cw;
+ *best_h = ch;
+ *best_r = r;
+
+ if (area == w * h) {
+ // Chart is completely inside, do not look at any other location.
+ goto done;
+ }
+ }
+ }
+ }
+ }
done:
- nvDebugCheck (best_metric != INT_MAX);
+ nvDebugCheck(best_metric != INT_MAX);
}
+void AtlasPacker::findChartLocation_random(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int minTrialCount) {
+ int best_metric = INT_MAX;
-void AtlasPacker::findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount)
-{
- int best_metric = INT_MAX;
-
- for (int i = 0; i < minTrialCount || best_metric == INT_MAX; i++)
- {
- int r = m_rand.getRange(1);
- int x = m_rand.getRange(w + 1); // + 1 to extend atlas in case atlas full. We may want to use a higher number to increase probability of extending atlas.
- int y = m_rand.getRange(h + 1); // + 1 to extend atlas in case atlas full.
+ for (int i = 0; i < minTrialCount || best_metric == INT_MAX; i++) {
+ int r = m_rand.getRange(1);
+ int x = m_rand.getRange(w + 1); // + 1 to extend atlas in case atlas full. We may want to use a higher number to increase probability of extending atlas.
+ int y = m_rand.getRange(h + 1); // + 1 to extend atlas in case atlas full.
- x = align(x, BLOCK_SIZE);
- y = align(y, BLOCK_SIZE);
+ x = align(x, BLOCK_SIZE);
+ y = align(y, BLOCK_SIZE);
- int cw = bitmap->width();
- int ch = bitmap->height();
- if (r & 1) swap(cw, ch);
+ int cw = bitmap->width();
+ int ch = bitmap->height();
+ if (r & 1) swap(cw, ch);
- // Early out.
- int area = max(w, x+cw) * max(h, y+ch);
- //int perimeter = max(w, x+cw) + max(h, y+ch);
- int extents = max(max(w, x+cw), max(h, y+ch));
+ // Early out.
+ int area = max(w, x + cw) * max(h, y + ch);
+ //int perimeter = max(w, x+cw) + max(h, y+ch);
+ int extents = max(max(w, x + cw), max(h, y + ch));
- int metric = extents*extents + area;
+ int metric = extents * extents + area;
- if (metric > best_metric) {
- continue;
- }
- if (metric == best_metric && min(x, y) > min(*best_x, *best_y)) {
- // If metric is the same, pick the one closest to the origin.
- continue;
- }
+ if (metric > best_metric) {
+ continue;
+ }
+ if (metric == best_metric && min(x, y) > min(*best_x, *best_y)) {
+ // If metric is the same, pick the one closest to the origin.
+ continue;
+ }
- if (canAddChart(bitmap, w, h, x, y, r))
- {
- best_metric = metric;
- *best_x = x;
- *best_y = y;
- *best_w = cw;
- *best_h = ch;
- *best_r = r;
-
- if (area == w*h)
- {
- // Chart is completely inside, do not look at any other location.
- break;
- }
- }
- }
+ if (canAddChart(bitmap, w, h, x, y, r)) {
+ best_metric = metric;
+ *best_x = x;
+ *best_y = y;
+ *best_w = cw;
+ *best_h = ch;
+ *best_r = r;
+
+ if (area == w * h) {
+ // Chart is completely inside, do not look at any other location.
+ break;
+ }
+ }
+ }
}
+void AtlasPacker::drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int padding) {
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+ const Vector2 extents = Vector2(float(w), float(h));
-void AtlasPacker::drawChartBitmapDilate(const Chart * chart, BitMap * bitmap, int padding)
-{
- const int w = bitmap->width();
- const int h = bitmap->height();
- const Vector2 extents = Vector2(float(w), float(h));
-
- // Rasterize chart faces, check that all bits are not set.
- const uint faceCount = chart->faceCount();
- for (uint f = 0; f < faceCount; f++)
- {
- const HalfEdge::Face * face = chart->chartMesh()->faceAt(f);
-
- Vector2 vertices[4];
+ // Rasterize chart faces, check that all bits are not set.
+ const uint faceCount = chart->faceCount();
+ for (uint f = 0; f < faceCount; f++) {
+ const HalfEdge::Face *face = chart->chartMesh()->faceAt(f);
- uint edgeCount = 0;
- for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance())
- {
- if (edgeCount < 4)
- {
- vertices[edgeCount] = it.vertex()->tex + Vector2(0.5) + Vector2(float(padding), float(padding));
- }
- edgeCount++;
- }
+ Vector2 vertices[4];
- if (edgeCount == 3)
- {
- Raster::drawTriangle(Raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
- }
- else
- {
- Raster::drawQuad(Raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
- }
- }
+ uint edgeCount = 0;
+ for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ if (edgeCount < 4) {
+ vertices[edgeCount] = it.vertex()->tex + Vector2(0.5) + Vector2(float(padding), float(padding));
+ }
+ edgeCount++;
+ }
- // Expand chart by padding pixels. (dilation)
- BitMap tmp(w, h);
- for (int i = 0; i < padding; i++) {
- tmp.clearAll();
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- bool b = bitmap->bitAt(x, y);
- if (!b) {
- if (x > 0) {
- b |= bitmap->bitAt(x - 1, y);
- if (y > 0) b |= bitmap->bitAt(x - 1, y - 1);
- if (y < h-1) b |= bitmap->bitAt(x - 1, y + 1);
- }
- if (y > 0) b |= bitmap->bitAt(x, y - 1);
- if (y < h-1) b |= bitmap->bitAt(x, y + 1);
- if (x < w-1) {
- b |= bitmap->bitAt(x + 1, y);
- if (y > 0) b |= bitmap->bitAt(x + 1, y - 1);
- if (y < h-1) b |= bitmap->bitAt(x + 1, y + 1);
- }
- }
- if (b) tmp.setBitAt(x, y);
- }
- }
+ if (edgeCount == 3) {
+ Raster::drawTriangle(Raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ } else {
+ Raster::drawQuad(Raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ }
+ }
+
+ // Expand chart by padding pixels. (dilation)
+ BitMap tmp(w, h);
+ for (int i = 0; i < padding; i++) {
+ tmp.clearAll();
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ bool b = bitmap->bitAt(x, y);
+ if (!b) {
+ if (x > 0) {
+ b |= bitmap->bitAt(x - 1, y);
+ if (y > 0) b |= bitmap->bitAt(x - 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x - 1, y + 1);
+ }
+ if (y > 0) b |= bitmap->bitAt(x, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x, y + 1);
+ if (x < w - 1) {
+ b |= bitmap->bitAt(x + 1, y);
+ if (y > 0) b |= bitmap->bitAt(x + 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x + 1, y + 1);
+ }
+ }
+ if (b) tmp.setBitAt(x, y);
+ }
+ }
- swap(tmp, *bitmap);
- }
+ swap(tmp, *bitmap);
+ }
}
-
-void AtlasPacker::drawChartBitmap(const Chart * chart, BitMap * bitmap, const Vector2 & scale, const Vector2 & offset)
-{
- const int w = bitmap->width();
- const int h = bitmap->height();
- const Vector2 extents = Vector2(float(w), float(h));
-
- static const Vector2 pad[4] = {
- Vector2(-0.5, -0.5),
- Vector2(0.5, -0.5),
- Vector2(-0.5, 0.5),
- Vector2(0.5, 0.5)
- };
- /*static const Vector2 pad[4] = {
+void AtlasPacker::drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vector2 &scale, const Vector2 &offset) {
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+ const Vector2 extents = Vector2(float(w), float(h));
+
+ static const Vector2 pad[4] = {
+ Vector2(-0.5, -0.5),
+ Vector2(0.5, -0.5),
+ Vector2(-0.5, 0.5),
+ Vector2(0.5, 0.5)
+ };
+ /*static const Vector2 pad[4] = {
Vector2(-1, -1),
Vector2(1, -1),
Vector2(-1, 1),
Vector2(1, 1)
};*/
- // Rasterize 4 times to add proper padding.
- for (int i = 0; i < 4; i++) {
-
- // Rasterize chart faces, check that all bits are not set.
- const uint faceCount = chart->chartMesh()->faceCount();
- for (uint f = 0; f < faceCount; f++)
- {
- const HalfEdge::Face * face = chart->chartMesh()->faceAt(f);
-
- Vector2 vertices[4];
-
- uint edgeCount = 0;
- for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance())
- {
- if (edgeCount < 4)
- {
- vertices[edgeCount] = it.vertex()->tex * scale + offset + pad[i];
- nvCheck(ftoi_ceil(vertices[edgeCount].x) >= 0);
- nvCheck(ftoi_ceil(vertices[edgeCount].y) >= 0);
- nvCheck(ftoi_ceil(vertices[edgeCount].x) <= w);
- nvCheck(ftoi_ceil(vertices[edgeCount].y) <= h);
- }
- edgeCount++;
- }
-
- if (edgeCount == 3)
- {
- Raster::drawTriangle(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
- }
- else
- {
- Raster::drawQuad(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
- }
- }
- }
-
- // @@ This only allows us to expand the size in texel intervals.
- /*if (m_padding_x != 0 && m_padding_y != 0)*/ {
-
- // Expand chart by padding pixels. (dilation)
- BitMap tmp(w, h);
- //for (int i = 0; i < 1; i++) {
- tmp.clearAll();
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- bool b = bitmap->bitAt(x, y);
- if (!b) {
- if (x > 0) {
- b |= bitmap->bitAt(x - 1, y);
- if (y > 0) b |= bitmap->bitAt(x - 1, y - 1);
- if (y < h-1) b |= bitmap->bitAt(x - 1, y + 1);
- }
- if (y > 0) b |= bitmap->bitAt(x, y - 1);
- if (y < h-1) b |= bitmap->bitAt(x, y + 1);
- if (x < w-1) {
- b |= bitmap->bitAt(x + 1, y);
- if (y > 0) b |= bitmap->bitAt(x + 1, y - 1);
- if (y < h-1) b |= bitmap->bitAt(x + 1, y + 1);
- }
- }
- if (b) tmp.setBitAt(x, y);
- }
- }
+ // Rasterize 4 times to add proper padding.
+ for (int i = 0; i < 4; i++) {
+
+ // Rasterize chart faces, check that all bits are not set.
+ const uint faceCount = chart->chartMesh()->faceCount();
+ for (uint f = 0; f < faceCount; f++) {
+ const HalfEdge::Face *face = chart->chartMesh()->faceAt(f);
+
+ Vector2 vertices[4];
+
+ uint edgeCount = 0;
+ for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ if (edgeCount < 4) {
+ vertices[edgeCount] = it.vertex()->tex * scale + offset + pad[i];
+ nvCheck(ftoi_ceil(vertices[edgeCount].x) >= 0);
+ nvCheck(ftoi_ceil(vertices[edgeCount].y) >= 0);
+ nvCheck(ftoi_ceil(vertices[edgeCount].x) <= w);
+ nvCheck(ftoi_ceil(vertices[edgeCount].y) <= h);
+ }
+ edgeCount++;
+ }
+
+ if (edgeCount == 3) {
+ Raster::drawTriangle(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ } else {
+ Raster::drawQuad(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ }
+ }
+ }
+
+ // @@ This only allows us to expand the size in texel intervals.
+ /*if (m_padding_x != 0 && m_padding_y != 0)*/ {
+
+ // Expand chart by padding pixels. (dilation)
+ BitMap tmp(w, h);
+ //for (int i = 0; i < 1; i++) {
+ tmp.clearAll();
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ bool b = bitmap->bitAt(x, y);
+ if (!b) {
+ if (x > 0) {
+ b |= bitmap->bitAt(x - 1, y);
+ if (y > 0) b |= bitmap->bitAt(x - 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x - 1, y + 1);
+ }
+ if (y > 0) b |= bitmap->bitAt(x, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x, y + 1);
+ if (x < w - 1) {
+ b |= bitmap->bitAt(x + 1, y);
+ if (y > 0) b |= bitmap->bitAt(x + 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x + 1, y + 1);
+ }
+ }
+ if (b) tmp.setBitAt(x, y);
+ }
+ }
- swap(tmp, *bitmap);
- //}
- }
+ swap(tmp, *bitmap);
+ //}
+ }
}
-bool AtlasPacker::canAddChart(const BitMap * bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r)
-{
- nvDebugCheck(r == 0 || r == 1);
+bool AtlasPacker::canAddChart(const BitMap *bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r) {
+ nvDebugCheck(r == 0 || r == 1);
+
+ // Check whether the two bitmaps overlap.
+
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+
+ if (r == 0) {
+ for (int y = 0; y < h; y++) {
+ int yy = y + offset_y;
+ if (yy >= 0) {
+ for (int x = 0; x < w; x++) {
+ int xx = x + offset_x;
+ if (xx >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ if (m_bitmap.bitAt(xx, yy)) return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (r == 1) {
+ for (int y = 0; y < h; y++) {
+ int xx = y + offset_x;
+ if (xx >= 0) {
+ for (int x = 0; x < w; x++) {
+ int yy = x + offset_y;
+ if (yy >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ if (m_bitmap.bitAt(xx, yy)) return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
- // Check whether the two bitmaps overlap.
-
- const int w = bitmap->width();
- const int h = bitmap->height();
-
- if (r == 0) {
- for (int y = 0; y < h; y++) {
- int yy = y + offset_y;
- if (yy >= 0) {
- for (int x = 0; x < w; x++) {
- int xx = x + offset_x;
- if (xx >= 0) {
- if (bitmap->bitAt(x, y)) {
- if (xx < atlas_w && yy < atlas_h) {
- if (m_bitmap.bitAt(xx, yy)) return false;
- }
- }
- }
- }
- }
- }
- }
- else if (r == 1) {
- for (int y = 0; y < h; y++) {
- int xx = y + offset_x;
- if (xx >= 0) {
- for (int x = 0; x < w; x++) {
- int yy = x + offset_y;
- if (yy >= 0) {
- if (bitmap->bitAt(x, y)) {
- if (xx < atlas_w && yy < atlas_h) {
- if (m_bitmap.bitAt(xx, yy)) return false;
- }
- }
- }
- }
- }
- }
- }
-
- return true;
+ return true;
}
#if 0
@@ -1222,166 +1160,150 @@ void AtlasPacker::checkCanAddChart(const Chart * chart, int w, int h, int x, int
}
#endif // 0
-
static Color32 chartColor = Color32(0);
-static void selectRandomColor(MTRand & rand) {
- // Pick random color for this chart. @@ Select random hue, but fixed saturation/luminance?
- chartColor.r = 128 + rand.getRange(127);
- chartColor.g = 128 + rand.getRange(127);
- chartColor.b = 128 + rand.getRange(127);
- chartColor.a = 255;
+static void selectRandomColor(MTRand &rand) {
+ // Pick random color for this chart. @@ Select random hue, but fixed saturation/luminance?
+ chartColor.r = 128 + rand.getRange(127);
+ chartColor.g = 128 + rand.getRange(127);
+ chartColor.b = 128 + rand.getRange(127);
+ chartColor.a = 255;
}
-static bool debugDrawCallback(void * param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area)
-{
- Image * image = (Image *)param;
-
- if (area > 0.0) {
- Color32 c = image->pixel(x, y);
- c.r = chartColor.r;
- c.g = chartColor.g;
- c.b = chartColor.b;
- c.a += U8(ftoi_round(0.5f * area * 255));
- image->pixel(x, y) = c;
- }
-
- return true;
+static bool debugDrawCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area) {
+ Image *image = (Image *)param;
+
+ if (area > 0.0) {
+ Color32 c = image->pixel(x, y);
+ c.r = chartColor.r;
+ c.g = chartColor.g;
+ c.b = chartColor.b;
+ c.a += U8(ftoi_round(0.5f * area * 255));
+ image->pixel(x, y) = c;
+ }
+
+ return true;
}
-void AtlasPacker::addChart(const Chart * chart, int w, int h, int x, int y, int r, Image * debugOutput)
-{
- nvDebugCheck(r == 0 || r == 1);
+void AtlasPacker::addChart(const Chart *chart, int w, int h, int x, int y, int r, Image *debugOutput) {
+ nvDebugCheck(r == 0 || r == 1);
- nvDebugCheck(debugOutput != NULL);
- selectRandomColor(m_rand);
+ nvDebugCheck(debugOutput != NULL);
+ selectRandomColor(m_rand);
- Vector2 extents = Vector2(float(w), float(h));
- Vector2 offset = Vector2(float(x), float(y)) + Vector2(0.5);
+ Vector2 extents = Vector2(float(w), float(h));
+ Vector2 offset = Vector2(float(x), float(y)) + Vector2(0.5);
- // Rasterize chart faces, set bits.
- const uint faceCount = chart->faceCount();
- for (uint f = 0; f < faceCount; f++)
- {
- const HalfEdge::Face * face = chart->chartMesh()->faceAt(f);
-
- Vector2 vertices[4];
+ // Rasterize chart faces, set bits.
+ const uint faceCount = chart->faceCount();
+ for (uint f = 0; f < faceCount; f++) {
+ const HalfEdge::Face *face = chart->chartMesh()->faceAt(f);
- uint edgeCount = 0;
- for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance())
- {
- if (edgeCount < 4)
- {
- Vector2 t = it.vertex()->tex;
- if (r == 1) swap(t.x, t.y);
- vertices[edgeCount] = t + offset;
- }
- edgeCount++;
- }
+ Vector2 vertices[4];
- if (edgeCount == 3)
- {
- Raster::drawTriangle(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, debugDrawCallback, debugOutput);
- }
- else
- {
- Raster::drawQuad(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, debugDrawCallback, debugOutput);
- }
- }
-}
-
-
-void AtlasPacker::addChart(const BitMap * bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r, Image * debugOutput)
-{
- nvDebugCheck(r == 0 || r == 1);
-
- // Check whether the two bitmaps overlap.
-
- const int w = bitmap->width();
- const int h = bitmap->height();
-
- if (debugOutput != NULL) {
- selectRandomColor(m_rand);
- }
+ uint edgeCount = 0;
+ for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ if (edgeCount < 4) {
+ Vector2 t = it.vertex()->tex;
+ if (r == 1) swap(t.x, t.y);
+ vertices[edgeCount] = t + offset;
+ }
+ edgeCount++;
+ }
- if (r == 0) {
- for (int y = 0; y < h; y++) {
- int yy = y + offset_y;
- if (yy >= 0) {
- for (int x = 0; x < w; x++) {
- int xx = x + offset_x;
- if (xx >= 0) {
- if (bitmap->bitAt(x, y)) {
- if (xx < atlas_w && yy < atlas_h) {
- if (debugOutput) debugOutput->pixel(xx, yy) = chartColor;
- else {
- nvDebugCheck(m_bitmap.bitAt(xx, yy) == false);
- m_bitmap.setBitAt(xx, yy);
- }
- }
- }
- }
- }
- }
- }
- }
- else if (r == 1) {
- for (int y = 0; y < h; y++) {
- int xx = y + offset_x;
- if (xx >= 0) {
- for (int x = 0; x < w; x++) {
- int yy = x + offset_y;
- if (yy >= 0) {
- if (bitmap->bitAt(x, y)) {
- if (xx < atlas_w && yy < atlas_h) {
- if (debugOutput) debugOutput->pixel(xx, yy) = chartColor;
- else {
- nvDebugCheck(m_bitmap.bitAt(xx, yy) == false);
- m_bitmap.setBitAt(xx, yy);
- }
- }
- }
- }
- }
- }
- }
- }
+ if (edgeCount == 3) {
+ Raster::drawTriangle(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, debugDrawCallback, debugOutput);
+ } else {
+ Raster::drawQuad(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, debugDrawCallback, debugOutput);
+ }
+ }
}
+void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r, Image *debugOutput) {
+ nvDebugCheck(r == 0 || r == 1);
+
+ // Check whether the two bitmaps overlap.
+
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+
+ if (debugOutput != NULL) {
+ selectRandomColor(m_rand);
+ }
+
+ if (r == 0) {
+ for (int y = 0; y < h; y++) {
+ int yy = y + offset_y;
+ if (yy >= 0) {
+ for (int x = 0; x < w; x++) {
+ int xx = x + offset_x;
+ if (xx >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ if (debugOutput)
+ debugOutput->pixel(xx, yy) = chartColor;
+ else {
+ nvDebugCheck(m_bitmap.bitAt(xx, yy) == false);
+ m_bitmap.setBitAt(xx, yy);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (r == 1) {
+ for (int y = 0; y < h; y++) {
+ int xx = y + offset_x;
+ if (xx >= 0) {
+ for (int x = 0; x < w; x++) {
+ int yy = x + offset_y;
+ if (yy >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ if (debugOutput)
+ debugOutput->pixel(xx, yy) = chartColor;
+ else {
+ nvDebugCheck(m_bitmap.bitAt(xx, yy) == false);
+ m_bitmap.setBitAt(xx, yy);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+/*static*/ bool AtlasPacker::checkBitsCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float) {
+ BitMap *bitmap = (BitMap *)param;
-/*static*/ bool AtlasPacker::checkBitsCallback(void * param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float)
-{
- BitMap * bitmap = (BitMap * )param;
-
- nvDebugCheck(bitmap->bitAt(x, y) == false);
+ nvDebugCheck(bitmap->bitAt(x, y) == false);
- return true;
+ return true;
}
-/*static*/ bool AtlasPacker::setBitsCallback(void * param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area)
-{
- BitMap * bitmap = (BitMap * )param;
+/*static*/ bool AtlasPacker::setBitsCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area) {
+ BitMap *bitmap = (BitMap *)param;
- if (area > 0.0) {
- bitmap->setBitAt(x, y);
- }
+ if (area > 0.0) {
+ bitmap->setBitAt(x, y);
+ }
- return true;
+ return true;
}
-
-
float AtlasPacker::computeAtlasUtilization() const {
- const uint w = m_width;
- const uint h = m_height;
- nvDebugCheck(w <= m_bitmap.width());
- nvDebugCheck(h <= m_bitmap.height());
-
- uint count = 0;
- for (uint y = 0; y < h; y++) {
- for (uint x = 0; x < w; x++) {
- count += m_bitmap.bitAt(x, y);
- }
- }
+ const uint w = m_width;
+ const uint h = m_height;
+ nvDebugCheck(w <= m_bitmap.width());
+ nvDebugCheck(h <= m_bitmap.height());
+
+ uint count = 0;
+ for (uint y = 0; y < h; y++) {
+ for (uint x = 0; x < w; x++) {
+ count += m_bitmap.bitAt(x, y);
+ }
+ }
- return float(count) / (w * h);
+ return float(count) / (w * h);
}
diff --git a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h
index 2d305f38cd..a8d530e826 100644
--- a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h
+++ b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h
@@ -5,59 +5,52 @@
#define NV_MESH_ATLASPACKER_H
#include "nvcore/RadixSort.h"
-#include "nvmath/Vector.h"
-#include "nvmath/Random.h"
#include "nvimage/BitMap.h"
#include "nvimage/Image.h"
+#include "nvmath/Random.h"
+#include "nvmath/Vector.h"
#include "nvmesh/nvmesh.h"
+namespace nv {
+class Atlas;
+class Chart;
-namespace nv
-{
- class Atlas;
- class Chart;
-
- struct AtlasPacker
- {
- AtlasPacker(Atlas * atlas);
- ~AtlasPacker();
+struct AtlasPacker {
+ AtlasPacker(Atlas *atlas);
+ ~AtlasPacker();
- void packCharts(int quality, float texelArea, bool blockAligned, bool conservative);
- float computeAtlasUtilization() const;
+ void packCharts(int quality, float texelArea, bool blockAligned, bool conservative);
+ float computeAtlasUtilization() const;
- private:
+private:
+ void findChartLocation(int quality, const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r);
+ void findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r);
+ void findChartLocation_random(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int minTrialCount);
- void findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
- void findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
- void findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount);
+ void drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int padding);
+ void drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vector2 &scale, const Vector2 &offset);
- void drawChartBitmapDilate(const Chart * chart, BitMap * bitmap, int padding);
- void drawChartBitmap(const Chart * chart, BitMap * bitmap, const Vector2 & scale, const Vector2 & offset);
-
- bool canAddChart(const BitMap * bitmap, int w, int h, int x, int y, int r);
- void addChart(const BitMap * bitmap, int w, int h, int x, int y, int r, Image * debugOutput);
- //void checkCanAddChart(const Chart * chart, int w, int h, int x, int y, int r);
- void addChart(const Chart * chart, int w, int h, int x, int y, int r, Image * debugOutput);
-
+ bool canAddChart(const BitMap *bitmap, int w, int h, int x, int y, int r);
+ void addChart(const BitMap *bitmap, int w, int h, int x, int y, int r, Image *debugOutput);
+ //void checkCanAddChart(const Chart * chart, int w, int h, int x, int y, int r);
+ void addChart(const Chart *chart, int w, int h, int x, int y, int r, Image *debugOutput);
- static bool checkBitsCallback(void * param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
- static bool setBitsCallback(void * param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
+ static bool checkBitsCallback(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
+ static bool setBitsCallback(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
- private:
+private:
+ Atlas *m_atlas;
+ BitMap m_bitmap;
+ //Image m_debug_bitmap;
+ RadixSort m_radix;
- Atlas * m_atlas;
- BitMap m_bitmap;
- Image m_debug_bitmap;
- RadixSort m_radix;
+ uint m_width;
+ uint m_height;
- uint m_width;
- uint m_height;
-
- MTRand m_rand;
-
- };
+ MTRand m_rand;
+};
-} // nv namespace
+} // namespace nv
#endif // NV_MESH_ATLASPACKER_H
diff --git a/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp b/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp
index d6f0accf54..255a6b8f50 100644
--- a/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp
+++ b/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp
@@ -4,8 +4,8 @@
#include <cfloat>
#include "nvmesh/halfedge/Edge.h"
-#include "nvmesh/halfedge/Mesh.h"
#include "nvmesh/halfedge/Face.h"
+#include "nvmesh/halfedge/Mesh.h"
#include "nvmesh/halfedge/Vertex.h"
#include "nvmesh/param/Atlas.h"
@@ -14,258 +14,255 @@
#include "nvcore/Array.inl"
+#include <stdio.h>
using namespace Thekla;
using namespace nv;
-
-inline Atlas_Output_Mesh * set_error(Atlas_Error * error, Atlas_Error code) {
- if (error) *error = code;
- return NULL;
+inline Atlas_Output_Mesh *set_error(Atlas_Error *error, Atlas_Error code) {
+ if (error) *error = code;
+ return NULL;
}
+static void input_to_mesh(const Atlas_Input_Mesh *input, HalfEdge::Mesh *mesh, Atlas_Error *error) {
+ Array<uint> canonicalMap;
+ canonicalMap.reserve(input->vertex_count);
-static void input_to_mesh(const Atlas_Input_Mesh * input, HalfEdge::Mesh * mesh, Atlas_Error * error) {
-
- Array<uint> canonicalMap;
- canonicalMap.reserve(input->vertex_count);
+ for (int i = 0; i < input->vertex_count; i++) {
+ const Atlas_Input_Vertex &input_vertex = input->vertex_array[i];
+ const float *pos = input_vertex.position;
+ const float *nor = input_vertex.normal;
+ const float *tex = input_vertex.uv;
- for (int i = 0; i < input->vertex_count; i++) {
- const Atlas_Input_Vertex & input_vertex = input->vertex_array[i];
- const float * pos = input_vertex.position;
- const float * nor = input_vertex.normal;
- const float * tex = input_vertex.uv;
+ HalfEdge::Vertex *vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2]));
+ vertex->nor.set(nor[0], nor[1], nor[2]);
+ vertex->tex.set(tex[0], tex[1]);
- HalfEdge::Vertex * vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2]));
- vertex->nor.set(nor[0], nor[1], nor[2]);
- vertex->tex.set(tex[0], tex[1]);
+ canonicalMap.append(input_vertex.first_colocal);
+ }
- canonicalMap.append(input_vertex.first_colocal);
- }
+ mesh->linkColocalsWithCanonicalMap(canonicalMap);
- mesh->linkColocalsWithCanonicalMap(canonicalMap);
+ const int face_count = input->face_count;
+ int non_manifold_faces = 0;
+ for (int i = 0; i < face_count; i++) {
+ const Atlas_Input_Face &input_face = input->face_array[i];
- const int face_count = input->face_count;
+ int v0 = input_face.vertex_index[0];
+ int v1 = input_face.vertex_index[1];
+ int v2 = input_face.vertex_index[2];
- int non_manifold_faces = 0;
- for (int i = 0; i < face_count; i++) {
- const Atlas_Input_Face & input_face = input->face_array[i];
+ HalfEdge::Face *face = mesh->addFace(v0, v1, v2);
+ if (face != NULL) {
+ face->material = input_face.material_index;
+ } else {
+ non_manifold_faces++;
+ }
+ }
- int v0 = input_face.vertex_index[0];
- int v1 = input_face.vertex_index[1];
- int v2 = input_face.vertex_index[2];
+ mesh->linkBoundary();
- HalfEdge::Face * face = mesh->addFace(v0, v1, v2);
- if (face != NULL) {
- face->material = input_face.material_index;
- }
- else {
- non_manifold_faces++;
- }
- }
-
- mesh->linkBoundary();
-
- if (non_manifold_faces != 0 && error != NULL) {
- *error = Atlas_Error_Invalid_Mesh_Non_Manifold;
- }
+ if (non_manifold_faces != 0 && error != NULL) {
+ *error = Atlas_Error_Invalid_Mesh_Non_Manifold;
+ }
}
-static Atlas_Output_Mesh * mesh_atlas_to_output(const HalfEdge::Mesh * mesh, const Atlas & atlas, Atlas_Error * error) {
+static Atlas_Output_Mesh *mesh_atlas_to_output(const HalfEdge::Mesh *mesh, const Atlas &atlas, Atlas_Error *error) {
- Atlas_Output_Mesh * output = new Atlas_Output_Mesh;
+ Atlas_Output_Mesh *output = new Atlas_Output_Mesh;
- const MeshCharts * charts = atlas.meshAt(0);
+ const MeshCharts *charts = atlas.meshAt(0);
- // Allocate vertices.
- const int vertex_count = charts->vertexCount();
- output->vertex_count = vertex_count;
- output->vertex_array = new Atlas_Output_Vertex[vertex_count];
+ // Allocate vertices.
+ const int vertex_count = charts->vertexCount();
+ output->vertex_count = vertex_count;
+ output->vertex_array = new Atlas_Output_Vertex[vertex_count];
- int w = 0;
- int h = 0;
+ int w = 0;
+ int h = 0;
- // Output vertices.
- const int chart_count = charts->chartCount();
- for (int i = 0; i < chart_count; i++) {
- const Chart * chart = charts->chartAt(i);
- uint vertexOffset = charts->vertexCountBeforeChartAt(i);
+ // Output vertices.
+ const int chart_count = charts->chartCount();
+ for (int i = 0; i < chart_count; i++) {
+ const Chart *chart = charts->chartAt(i);
+ uint vertexOffset = charts->vertexCountBeforeChartAt(i);
- const uint chart_vertex_count = chart->vertexCount();
- for (uint v = 0; v < chart_vertex_count; v++) {
- Atlas_Output_Vertex & output_vertex = output->vertex_array[vertexOffset + v];
+ const uint chart_vertex_count = chart->vertexCount();
+ for (uint v = 0; v < chart_vertex_count; v++) {
+ Atlas_Output_Vertex &output_vertex = output->vertex_array[vertexOffset + v];
- uint original_vertex = chart->mapChartVertexToOriginalVertex(v);
- output_vertex.xref = original_vertex;
+ uint original_vertex = chart->mapChartVertexToOriginalVertex(v);
+ output_vertex.xref = original_vertex;
- Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
- output_vertex.uv[0] = uv.x;
- output_vertex.uv[1] = uv.y;
- w = max(w, ftoi_ceil(uv.x));
- h = max(h, ftoi_ceil(uv.y));
- }
- }
+ Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
+ output_vertex.uv[0] = uv.x;
+ output_vertex.uv[1] = uv.y;
+ w = max(w, ftoi_ceil(uv.x));
+ h = max(h, ftoi_ceil(uv.y));
+ }
+ }
- const int face_count = mesh->faceCount();
- output->index_count = face_count * 3;
- output->index_array = new int[face_count * 3];
+ const int face_count = mesh->faceCount();
+ output->index_count = face_count * 3;
+ output->index_array = new int[face_count * 3];
- // Set face indices.
- for (int f = 0; f < face_count; f++) {
- uint c = charts->faceChartAt(f);
- uint i = charts->faceIndexWithinChartAt(f);
- uint vertexOffset = charts->vertexCountBeforeChartAt(c);
+ int face_ofs = 0;
+ // Set face indices.
+ for (int f = 0; f < face_count; f++) {
+ uint c = charts->faceChartAt(f);
+ uint i = charts->faceIndexWithinChartAt(f);
+ uint vertexOffset = charts->vertexCountBeforeChartAt(c);
- const Chart * chart = charts->chartAt(c);
- nvDebugCheck(chart->faceAt(i) == f);
+ const Chart *chart = charts->chartAt(c);
+ nvDebugCheck(chart->faceAt(i) == f);
- const HalfEdge::Face * face = chart->chartMesh()->faceAt(i);
- const HalfEdge::Edge * edge = face->edge;
+ if (i >= chart->chartMesh()->faceCount()) {
+ printf("WARNING: Faces may be missing in the final vertex, which could not be packed\n");
- output->index_array[3*f+0] = vertexOffset + edge->vertex->id;
- output->index_array[3*f+1] = vertexOffset + edge->next->vertex->id;
- output->index_array[3*f+2] = vertexOffset + edge->next->next->vertex->id;
- }
+ continue;
+ }
+ const HalfEdge::Face *face = chart->chartMesh()->faceAt(i);
+ const HalfEdge::Edge *edge = face->edge;
- *error = Atlas_Error_Success;
- output->atlas_width = w;
- output->atlas_height = h;
+ output->index_array[3 * face_ofs + 0] = vertexOffset + edge->vertex->id;
+ output->index_array[3 * face_ofs + 1] = vertexOffset + edge->next->vertex->id;
+ output->index_array[3 * face_ofs + 2] = vertexOffset + edge->next->next->vertex->id;
+ face_ofs++;
+ }
- return output;
-}
+ output->index_count = face_ofs * 3;
+ *error = Atlas_Error_Success;
+ output->atlas_width = w;
+ output->atlas_height = h;
-void Thekla::atlas_set_default_options(Atlas_Options * options) {
- if (options != NULL) {
- // These are the default values we use on The Witness.
-
- options->charter = Atlas_Charter_Default;
- options->charter_options.witness.proxy_fit_metric_weight = 2.0f;
- options->charter_options.witness.roundness_metric_weight = 0.01f;
- options->charter_options.witness.straightness_metric_weight = 6.0f;
- options->charter_options.witness.normal_seam_metric_weight = 4.0f;
- options->charter_options.witness.texture_seam_metric_weight = 0.5f;
- options->charter_options.witness.max_chart_area = FLT_MAX;
- options->charter_options.witness.max_boundary_length = FLT_MAX;
-
- options->mapper = Atlas_Mapper_Default;
-
- options->packer = Atlas_Packer_Default;
- options->packer_options.witness.packing_quality = 0;
- options->packer_options.witness.texel_area = 8;
- options->packer_options.witness.block_align = true;
- options->packer_options.witness.conservative = false;
- }
+ return output;
}
-
-Atlas_Output_Mesh * Thekla::atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error) {
- // Validate args.
- if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args);
-
- // Validate options.
- if (options->charter != Atlas_Charter_Witness) {
- return set_error(error, Atlas_Error_Invalid_Options);
- }
- if (options->charter == Atlas_Charter_Witness) {
- // @@ Validate input options!
- }
-
- if (options->mapper != Atlas_Mapper_LSCM) {
- return set_error(error, Atlas_Error_Invalid_Options);
- }
- if (options->mapper == Atlas_Mapper_LSCM) {
- // No options.
- }
-
- if (options->packer != Atlas_Packer_Witness) {
- return set_error(error, Atlas_Error_Invalid_Options);
- }
- if (options->packer == Atlas_Packer_Witness) {
- // @@ Validate input options!
- }
-
- // Validate input mesh.
- for (int i = 0; i < input->face_count; i++) {
- int v0 = input->face_array[i].vertex_index[0];
- int v1 = input->face_array[i].vertex_index[1];
- int v2 = input->face_array[i].vertex_index[2];
-
- if (v0 < 0 || v0 >= input->vertex_count ||
- v1 < 0 || v1 >= input->vertex_count ||
- v2 < 0 || v2 >= input->vertex_count)
- {
- return set_error(error, Atlas_Error_Invalid_Mesh);
- }
- }
-
-
- // Build half edge mesh.
- AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh);
-
- input_to_mesh(input, mesh.ptr(), error);
-
- if (*error == Atlas_Error_Invalid_Mesh) {
- return NULL;
- }
-
- Atlas atlas;
-
- // Charter.
- if (options->charter == Atlas_Charter_Extract) {
- return set_error(error, Atlas_Error_Not_Implemented);
- }
- else if (options->charter == Atlas_Charter_Witness) {
- SegmentationSettings segmentation_settings;
- segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight;
- segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight;
- segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight;
- segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight;
- segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight;
- segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area;
- segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length;
-
- Array<uint> uncharted_materials;
- atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials);
- }
-
- if (atlas.hasFailed())
- return NULL;
-
- // Mapper.
- if (options->mapper == Atlas_Mapper_LSCM) {
- atlas.parameterizeCharts();
- }
-
- if (atlas.hasFailed())
- return NULL;
-
- // Packer.
- if (options->packer == Atlas_Packer_Witness) {
- int packing_quality = options->packer_options.witness.packing_quality;
- float texel_area = options->packer_options.witness.texel_area;
- int block_align = options->packer_options.witness.block_align;
- int conservative = options->packer_options.witness.conservative;
-
- /*float utilization =*/ atlas.packCharts(packing_quality, texel_area, block_align, conservative);
- }
-
- if (atlas.hasFailed())
- return NULL;
-
-
- // Build output mesh.
- return mesh_atlas_to_output(mesh.ptr(), atlas, error);
+void Thekla::atlas_set_default_options(Atlas_Options *options) {
+ if (options != NULL) {
+ // These are the default values we use on The Witness.
+
+ options->charter = Atlas_Charter_Default;
+ options->charter_options.witness.proxy_fit_metric_weight = 2.0f;
+ options->charter_options.witness.roundness_metric_weight = 0.01f;
+ options->charter_options.witness.straightness_metric_weight = 6.0f;
+ options->charter_options.witness.normal_seam_metric_weight = 4.0f;
+ options->charter_options.witness.texture_seam_metric_weight = 0.5f;
+ options->charter_options.witness.max_chart_area = FLT_MAX;
+ options->charter_options.witness.max_boundary_length = FLT_MAX;
+
+ options->mapper = Atlas_Mapper_Default;
+
+ options->packer = Atlas_Packer_Default;
+ options->packer_options.witness.packing_quality = 0;
+ options->packer_options.witness.texel_area = 8;
+ options->packer_options.witness.block_align = true;
+ options->packer_options.witness.conservative = false;
+ }
}
-
-void Thekla::atlas_free(Atlas_Output_Mesh * output) {
- if (output != NULL) {
- delete [] output->vertex_array;
- delete [] output->index_array;
- delete output;
- }
+Atlas_Output_Mesh *Thekla::atlas_generate(const Atlas_Input_Mesh *input, const Atlas_Options *options, Atlas_Error *error) {
+ // Validate args.
+ if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args);
+
+ // Validate options.
+ if (options->charter != Atlas_Charter_Witness) {
+ return set_error(error, Atlas_Error_Invalid_Options);
+ }
+ if (options->charter == Atlas_Charter_Witness) {
+ // @@ Validate input options!
+ }
+
+ if (options->mapper != Atlas_Mapper_LSCM) {
+ return set_error(error, Atlas_Error_Invalid_Options);
+ }
+ if (options->mapper == Atlas_Mapper_LSCM) {
+ // No options.
+ }
+
+ if (options->packer != Atlas_Packer_Witness) {
+ return set_error(error, Atlas_Error_Invalid_Options);
+ }
+ if (options->packer == Atlas_Packer_Witness) {
+ // @@ Validate input options!
+ }
+
+ // Validate input mesh.
+ for (int i = 0; i < input->face_count; i++) {
+ int v0 = input->face_array[i].vertex_index[0];
+ int v1 = input->face_array[i].vertex_index[1];
+ int v2 = input->face_array[i].vertex_index[2];
+
+ if (v0 < 0 || v0 >= input->vertex_count ||
+ v1 < 0 || v1 >= input->vertex_count ||
+ v2 < 0 || v2 >= input->vertex_count) {
+ return set_error(error, Atlas_Error_Invalid_Mesh);
+ }
+ }
+
+ // Build half edge mesh.
+ AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh);
+
+ input_to_mesh(input, mesh.ptr(), error);
+
+ if (*error == Atlas_Error_Invalid_Mesh) {
+ return NULL;
+ }
+
+ Atlas atlas;
+
+ // Charter.
+ if (options->charter == Atlas_Charter_Extract) {
+ return set_error(error, Atlas_Error_Not_Implemented);
+ } else if (options->charter == Atlas_Charter_Witness) {
+ SegmentationSettings segmentation_settings;
+ segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight;
+ segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight;
+ segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight;
+ segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight;
+ segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight;
+ segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area;
+ segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length;
+
+ Array<uint> uncharted_materials;
+ atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials);
+ }
+
+ if (atlas.hasFailed())
+ return NULL;
+
+ // Mapper.
+ if (options->mapper == Atlas_Mapper_LSCM) {
+ atlas.parameterizeCharts();
+ }
+
+ if (atlas.hasFailed())
+ return NULL;
+
+ // Packer.
+ if (options->packer == Atlas_Packer_Witness) {
+ int packing_quality = options->packer_options.witness.packing_quality;
+ float texel_area = options->packer_options.witness.texel_area;
+ int block_align = options->packer_options.witness.block_align;
+ int conservative = options->packer_options.witness.conservative;
+
+ /*float utilization =*/atlas.packCharts(packing_quality, texel_area, block_align, conservative);
+ }
+
+ if (atlas.hasFailed())
+ return NULL;
+
+ // Build output mesh.
+ return mesh_atlas_to_output(mesh.ptr(), atlas, error);
}
+void Thekla::atlas_free(Atlas_Output_Mesh *output) {
+ if (output != NULL) {
+ delete[] output->vertex_array;
+ delete[] output->index_array;
+ delete output;
+ }
+}