diff options
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 §ion, 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 §ion, 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; + } +} |