From 04847ef5f98d9a20a72286c44cc26302ec82dec5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 19 Apr 2019 15:54:33 -0300 Subject: [PATCH] Added ability for multiple images to be imported as an atlas This adds support for groups in the import system, which point to a single file. Add property hint for saving files in file field --- core/image.cpp | 12 +- core/io/resource_importer.cpp | 11 + core/io/resource_importer.h | 5 + core/io/resource_loader.cpp | 24 + core/io/resource_loader.h | 2 + core/math/transform_2d.cpp | 2 +- core/math/transform_2d.h | 2 +- core/math/vector2.h | 1 + core/object.h | 1 + core/reference.h | 13 + drivers/gles3/rasterizer_canvas_gles3.cpp | 6 +- editor/editor_atlas_packer.cpp | 265 +++++++++++ editor/editor_atlas_packer.h | 45 ++ editor/editor_file_system.cpp | 309 ++++++++++++- editor/editor_file_system.h | 12 + editor/editor_node.cpp | 5 + editor/editor_properties.cpp | 6 +- editor/filesystem_dock.cpp | 14 + editor/import/atlas_import_failed.xpm | 414 ++++++++++++++++++ .../resource_importer_texture_atlas.cpp | 382 ++++++++++++++++ .../import/resource_importer_texture_atlas.h | 42 ++ editor/import_dock.cpp | 17 +- scene/2d/canvas_item.cpp | 6 +- scene/2d/canvas_item.h | 2 +- scene/register_scene_types.cpp | 1 + scene/resources/bit_map.cpp | 58 +++ scene/resources/bit_map.h | 4 + scene/resources/texture.cpp | 133 ++++++ scene/resources/texture.h | 43 ++ servers/visual/rasterizer.h | 2 + servers/visual/visual_server_canvas.cpp | 4 +- servers/visual/visual_server_canvas.h | 2 +- servers/visual/visual_server_raster.h | 2 +- servers/visual/visual_server_wrap_mt.h | 2 +- servers/visual_server.h | 2 +- 35 files changed, 1818 insertions(+), 33 deletions(-) create mode 100644 editor/editor_atlas_packer.cpp create mode 100644 editor/editor_atlas_packer.h create mode 100644 editor/import/atlas_import_failed.xpm create mode 100644 editor/import/resource_importer_texture_atlas.cpp create mode 100644 editor/import/resource_importer_texture_atlas.h diff --git a/core/image.cpp b/core/image.cpp index 90afd9f35a8..99d5eab864c 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1876,7 +1876,7 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const P Rect2 Image::get_used_rect() const { - if (format != FORMAT_LA8 && format != FORMAT_RGBA8) + if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGBA5551) return Rect2(Point2(), Size2(width, height)); int len = data.size(); @@ -1884,17 +1884,13 @@ Rect2 Image::get_used_rect() const { if (len == 0) return Rect2(); - //int data_size = len; - PoolVector::Read r = data.read(); - const unsigned char *rptr = r.ptr(); - - int ps = format == FORMAT_LA8 ? 2 : 4; + const_cast(this)->lock(); int minx = 0xFFFFFF, miny = 0xFFFFFFF; int maxx = -1, maxy = -1; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { - bool opaque = rptr[(j * width + i) * ps + (ps - 1)] > 2; + bool opaque = get_pixel(i, j).a > 0.99; if (!opaque) continue; if (i > maxx) @@ -1908,6 +1904,8 @@ Rect2 Image::get_used_rect() const { } } + const_cast(this)->unlock(); + if (maxx == -1) return Rect2(); else diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index b5fa4125764..038a34ed51e 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -94,6 +94,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy r_path_and_type.type = value; } else if (assign == "importer") { r_path_and_type.importer = value; + } else if (assign == "group_file") { + r_path_and_type.group_file = value; } else if (assign == "metadata") { r_path_and_type.metadata = value; } else if (assign == "valid") { @@ -294,6 +296,15 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat memdelete(f); } +String ResourceFormatImporter::get_import_group_file(const String &p_path) const { + + bool valid = true; + PathAndType pat; + _get_path_and_type(p_path, pat, &valid); + return valid?pat.group_file:String(); + +} + bool ResourceFormatImporter::is_import_valid(const String &p_path) const { bool valid = true; diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 1c146c33d76..bdbdde6df6d 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -43,6 +43,7 @@ class ResourceFormatImporter : public ResourceFormatLoader { String path; String type; String importer; + String group_file; Variant metadata; }; @@ -69,6 +70,7 @@ public: virtual bool is_import_valid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false); virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); } + virtual String get_import_group_file(const String &p_path) const; virtual bool exists(const String &p_path) const; virtual bool can_be_imported(const String &p_path) const; @@ -120,8 +122,11 @@ public: virtual void get_import_options(List *r_options, int p_preset = 0) const = 0; virtual bool get_option_visibility(const String &p_option, const Map &p_options) const = 0; + virtual String get_option_group_file() const { return String(); } virtual Error import(const String &p_source_file, const String &p_save_path, const Map &p_options, List *r_platform_variants, List *r_gen_files = NULL, Variant *r_metadata = NULL) = 0; + + virtual Error import_group_file(const String& p_group_file,const Map >&p_source_file_options, const Map& p_base_paths) { return ERR_UNAVAILABLE; } virtual bool are_import_settings_valid(const String &p_path) const { return true; } virtual String get_import_settings_string() const { return String(); } }; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index e4b694b64f5..56d3b8b1330 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -608,6 +608,30 @@ int ResourceLoader::get_import_order(const String &p_path) { return 0; } +String ResourceLoader::get_import_group_file(const String &p_path) { + String path = _path_remap(p_path); + + String local_path; + if (path.is_rel_path()) + local_path = "res://" + path; + else + local_path = ProjectSettings::get_singleton()->localize_path(path); + + for (int i = 0; i < loader_count; i++) { + + if (!loader[i]->recognize_path(local_path)) + continue; + /* + if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) + continue; + */ + + return loader[i]->get_import_group_file(p_path); + } + + return String(); //not found +} + bool ResourceLoader::is_import_valid(const String &p_path) { String path = _path_remap(p_path); diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index ca7610a0d24..9e7020be7c3 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -81,6 +81,7 @@ public: virtual bool is_import_valid(const String &p_path) const { return true; } virtual bool is_imported(const String &p_path) const { return false; } virtual int get_import_order(const String &p_path) const { return 0; } + virtual String get_import_group_file(const String &p_path) const { return ""; } //no group virtual ~ResourceFormatLoader() {} }; @@ -155,6 +156,7 @@ public: static void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false); static Error rename_dependencies(const String &p_path, const Map &p_map); static bool is_import_valid(const String &p_path); + static String get_import_group_file(const String &p_path); static bool is_imported(const String &p_path); static int get_import_order(const String &p_path); diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 7d00158f3dd..1d0387bd456 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -106,7 +106,7 @@ Size2 Transform2D::get_scale() const { return Size2(elements[0].length(), det_sign * elements[1].length()); } -void Transform2D::set_scale(Size2 &p_scale) { +void Transform2D::set_scale(const Size2 &p_scale) { elements[0].normalize(); elements[1].normalize(); elements[0] *= p_scale.x; diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index b9e7a36fb32..c44678674a7 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -81,7 +81,7 @@ struct Transform2D { real_t basis_determinant() const; Size2 get_scale() const; - void set_scale(Size2 &p_scale); + void set_scale(const Size2 &p_scale); _FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; } _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; } diff --git a/core/math/vector2.h b/core/math/vector2.h index ae2d1ec660e..9a214ef9b55 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -99,6 +99,7 @@ struct Vector2 { Vector2 operator/(const real_t &rvalue) const; void operator/=(const real_t &rvalue); + void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; } Vector2 operator-() const; diff --git a/core/object.h b/core/object.h index e8a6178052c..3730af1ad42 100644 --- a/core/object.h +++ b/core/object.h @@ -88,6 +88,7 @@ enum PropertyHint { PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send PROPERTY_HINT_NODE_PATH_VALID_TYPES, + PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; diff --git a/core/reference.h b/core/reference.h index f3fcc922c7b..9105dbbd58c 100644 --- a/core/reference.h +++ b/core/reference.h @@ -197,6 +197,19 @@ public: r.reference = NULL; } + template + void reference_ptr(T_Other *p_ptr) { + if (reference == p_ptr) { + return; + } + unref(); + + T *r = Object::cast_to(p_ptr); + if (r) { + ref_pointer(r); + } + } + Ref(const Ref &p_from) { reference = NULL; diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index b0f1be47a1a..30aa22732cf 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -826,6 +826,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform); + RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); if (mesh_data) { @@ -834,7 +836,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing glBindVertexArray(s->array_id); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + glVertexAttrib4f(VS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a); if (s->index_array_len) { glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); @@ -845,6 +847,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur glBindVertexArray(0); } } + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); + } break; case Item::Command::TYPE_MULTIMESH: { diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp new file mode 100644 index 00000000000..4e1d98399a0 --- /dev/null +++ b/editor/editor_atlas_packer.cpp @@ -0,0 +1,265 @@ +#include "editor_atlas_packer.h" + +void EditorAtlasPacker::_plot_triangle(Ref p_bitmap, Vector2i *vertices) { + + int width = p_bitmap->get_size().width; + int height = p_bitmap->get_size().height; + int x[3]; + int y[3]; + + for (int j = 0; j < 3; j++) { + + x[j] = vertices[j].x; + y[j] = vertices[j].y; + } + + // sort the points vertically + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + } + if (y[0] > y[1]) { + SWAP(x[0], x[1]); + SWAP(y[0], y[1]); + } + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + } + + double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1); + double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1); + double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1); + double xf = x[0]; + double xt = x[0] + dx_upper; // if y[0] == y[1], special case + for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) { + if (yi >= 0) { + for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) { + //pixels[int(x + y * width)] = color; + + p_bitmap->set_bit(Point2(xi, yi), true); + } + + for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) { + + p_bitmap->set_bit(Point2(xi, yi), true); + } + } + xf += dx_far; + if (yi < y[1]) + xt += dx_upper; + else + xt += dx_low; + } +} +void EditorAtlasPacker::chart_pack(Vector &charts, int &r_width, int &r_height, int p_atlas_max_size, int p_cell_resolution) { + + int divide_by = MIN(64, p_cell_resolution); + Vector bitmaps; + + int max_w = 0; + + for (int i = 0; i < charts.size(); i++) { + + const Chart &chart = charts[i]; + + //generate aabb + + Rect2i aabb; + int vertex_count = chart.vertices.size(); + const Vector2 *vertices = chart.vertices.ptr(); + + for (int j = 0; j < vertex_count; j++) { + + if (j == 0) { + aabb.position = vertices[j]; + } else { + aabb.expand_to(vertices[j]); + } + } + + Ref src_bitmap; + src_bitmap.instance(); + src_bitmap->create(aabb.size / divide_by); + + int w = src_bitmap->get_size().width; + int h = src_bitmap->get_size().height; + + //plot triangles, using divisor + + for (int j = 0; j < chart.faces.size(); j++) { + + Vector2i v[3]; + for (int k = 0; k < 3; k++) { + Vector2 vtx = chart.vertices[chart.faces[j].vertex[k]]; + vtx -= aabb.position; + vtx /= divide_by; + v[k] = vtx; + } + + _plot_triangle(src_bitmap, v); + } + + //src_bitmap->convert_to_image()->save_png("bitmap" + itos(i) + ".png"); + + //grow by 1 for each side + + int bmw = src_bitmap->get_size().width + 2; + int bmh = src_bitmap->get_size().height + 2; + + int heights_size = -1; + bool transpose = false; + if (chart.can_transpose && bmh > bmw) { + heights_size = bmh; + transpose = true; + } else { + heights_size = bmw; + } + + max_w = MAX(max_w, heights_size); + + Vector top_heights; + Vector bottom_heights; + top_heights.resize(heights_size); + bottom_heights.resize(heights_size); + + for (int x = 0; x < heights_size; x++) { + top_heights.write[x] = -1; + bottom_heights.write[x] = 0x7FFFFFFF; + } + + for (int x = 0; x < bmw; x++) { + for (int y = 0; y < bmh; y++) { + bool found_pixel = false; + for (int lx = x - 1; lx < x + 2 && !found_pixel; lx++) { + for (int ly = y - 1; ly < y + 2 && !found_pixel; ly++) { + + int px = lx - 1; + if (px < 0 || px >= w) + continue; + int py = ly - 1; + if (py < 0 || py >= h) + continue; + + if (src_bitmap->get_bit(Vector2(px, py))) { + found_pixel = true; + } + } + } + if (found_pixel) { + + if (transpose) { + if (x > top_heights[y]) { + top_heights.write[y] = x; + } + if (x < bottom_heights[y]) { + bottom_heights.write[y] = x; + } + } else { + if (y > top_heights[x]) { + top_heights.write[x] = y; + } + if (y < bottom_heights[x]) { + bottom_heights.write[x] = y; + } + } + } + } + } + + String row; + for (int j = 0; j < top_heights.size(); j++) { + row += "(" + itos(top_heights[j]) + "-" + itos(bottom_heights[j]) + "),"; + } + + PlottedBitmap plotted_bitmap; + plotted_bitmap.offset = aabb.position; + plotted_bitmap.top_heights = top_heights; + plotted_bitmap.bottom_heights = bottom_heights; + plotted_bitmap.chart_index = i; + plotted_bitmap.transposed = transpose; + plotted_bitmap.area = bmw * bmh; + + bitmaps.push_back(plotted_bitmap); + } + + bitmaps.sort(); + + int atlas_max_width = nearest_power_of_2_templated(p_atlas_max_size) / divide_by; + int atlas_w = nearest_power_of_2_templated(max_w); + int atlas_h; + while (true) { + atlas_h = 0; + + //do a tetris + Vector heights; + heights.resize(atlas_w); + for (int i = 0; i < atlas_w; i++) { + heights.write[i] = 0; + } + + int *atlas_ptr = heights.ptrw(); + + for (int i = 0; i < bitmaps.size(); i++) { + + int best_height = 0x7FFFFFFF; + int best_height_offset = -1; + int w = bitmaps[i].top_heights.size(); + + const int *top_heights = bitmaps[i].top_heights.ptr(); + const int *bottom_heights = bitmaps[i].bottom_heights.ptr(); + + for (int j = 0; j < atlas_w - w; j++) { + + int height = 0; + + for (int k = 0; k < w; k++) { + + int pixmap_h = bottom_heights[k]; + if (pixmap_h == -1) { + continue; //no pixel here, anything is fine + } + + int h = MAX(0, atlas_ptr[j + k] - pixmap_h); + if (h > height) { + height = h; + } + } + + if (height < best_height) { + best_height = height; + best_height_offset = j; + } + } + + for (int j = 0; j < w; j++) { //add + if (top_heights[j] == -1) { //unused + continue; + } + int height = best_height + top_heights[j] + 1; + atlas_ptr[j + best_height_offset] = height; + atlas_h = MAX(atlas_h, height); + } + + // set + Vector2 offset = bitmaps[i].offset; + if (bitmaps[i].transposed) { + SWAP(offset.x, offset.y); + } + + Vector2 final_pos = Vector2(best_height_offset * divide_by, best_height * divide_by) + Vector2(divide_by, divide_by) - offset; + charts.write[bitmaps[i].chart_index].final_offset = final_pos; + charts.write[bitmaps[i].chart_index].transposed = bitmaps[i].transposed; + } + + if (atlas_h <= atlas_w * 2 || atlas_w >= atlas_max_width) { + break; //ok this one is enough + } + + //try again + atlas_w *= 2; + } + + r_width = atlas_w * divide_by; + r_height = atlas_h * divide_by; +} diff --git a/editor/editor_atlas_packer.h b/editor/editor_atlas_packer.h new file mode 100644 index 00000000000..dd9caa340ee --- /dev/null +++ b/editor/editor_atlas_packer.h @@ -0,0 +1,45 @@ +#ifndef EDITOR_ATLAS_PACKER_H +#define EDITOR_ATLAS_PACKER_H + +#include "core/math/vector2.h" + +#include "core/vector.h" +#include "scene/resources/bit_map.h" + +class EditorAtlasPacker { +public: + struct Chart { + Vector vertices; + struct Face { + int vertex[3]; + }; + Vector faces; + bool can_transpose; + + Vector2 final_offset; + bool transposed; + }; + +private: + struct PlottedBitmap { + int chart_index; + Vector2i offset; + int area; + Vector top_heights; + Vector bottom_heights; + bool transposed; + + Vector2 final_pos; + + bool operator<(const PlottedBitmap &p_bm) const { + return area > p_bm.area; + } + }; + + static void _plot_triangle(Ref p_bitmap, Vector2i *vertices); + +public: + static void chart_pack(Vector &charts, int &r_width, int &r_height, int p_atlas_max_size = 2048, int p_cell_resolution = 4); +}; + +#endif // EDITOR_ATLAS_PACKER_H diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 3d9d5e26be4..abd3bea9516 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -43,7 +43,7 @@ EditorFileSystem *EditorFileSystem::singleton = NULL; //the name is the version, to keep compatibility with different versions of Godot -#define CACHE_FILE_NAME "filesystem_cache5" +#define CACHE_FILE_NAME "filesystem_cache6" void EditorFileSystemDirectory::sort_files() { @@ -241,7 +241,7 @@ void EditorFileSystem::_scan_filesystem() { } else { Vector split = l.split("::"); - ERR_CONTINUE(split.size() != 7); + ERR_CONTINUE(split.size() != 8); String name = split[0]; String file; @@ -253,11 +253,12 @@ void EditorFileSystem::_scan_filesystem() { fc.modification_time = split[2].to_int64(); fc.import_modification_time = split[3].to_int64(); fc.import_valid = split[4].to_int64() != 0; - fc.script_class_name = split[5].get_slice("<>", 0); - fc.script_class_extends = split[5].get_slice("<>", 1); - fc.script_class_icon_path = split[5].get_slice("<>", 2); + fc.import_group_file = split[5].strip_edges(); + fc.script_class_name = split[6].get_slice("<>", 0); + fc.script_class_extends = split[6].get_slice("<>", 1); + fc.script_class_icon_path = split[6].get_slice("<>", 2); - String deps = split[6].strip_edges(); + String deps = split[7].strip_edges(); if (deps.length()) { Vector dp = deps.split("<>"); for (int i = 0; i < dp.size(); i++) { @@ -318,6 +319,9 @@ void EditorFileSystem::_scan_filesystem() { } void EditorFileSystem::_save_filesystem_cache() { + + group_file_cache.clear(); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE); @@ -771,6 +775,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess fi->import_valid = fc->import_valid; fi->script_class_name = fc->script_class_name; + fi->import_group_file = fc->import_group_file; fi->script_class_extends = fc->script_class_extends; fi->script_class_icon_path = fc->script_class_icon_path; @@ -784,6 +789,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess if (fc->type == String()) { fi->type = ResourceLoader::get_resource_type(path); + fi->import_group_file = ResourceLoader::get_import_group_file(path); //there is also the chance that file type changed due to reimport, must probably check this somehow here (or kind of note it for next time in another file?) //note: I think this should not happen any longer.. } @@ -791,6 +797,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess } else { fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path); + fi->import_group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(path); fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); fi->modified_time = 0; fi->import_modified_time = 0; @@ -918,6 +925,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const fi->type = ResourceLoader::get_resource_type(path); fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); fi->import_valid = ResourceLoader::is_import_valid(path); + fi->import_group_file = ResourceLoader::get_import_group_file(path); { ItemAction ia; @@ -1187,7 +1195,10 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir, for (int i = 0; i < p_dir->files.size(); i++) { - String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path; + if (p_dir->files[i]->import_group_file != String()) { + group_file_cache.insert(p_dir->files[i]->import_group_file); + } + String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->import_group_file + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path; s += "::"; for (int j = 0; j < p_dir->files[i]->deps.size(); j++) { @@ -1523,6 +1534,7 @@ void EditorFileSystem::update_file(const String &p_file) { fs->files[cpos]->type = type; fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path); + fs->files[cpos]->import_group_file = ResourceLoader::get_import_group_file(p_file); fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file); fs->files[cpos]->deps = _get_dependencies(p_file); fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file); @@ -1534,6 +1546,168 @@ void EditorFileSystem::update_file(const String &p_file) { _queue_update_script_classes(); } +Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector &p_files) { + + String importer_name; + + Map > source_file_options; + Map base_paths; + for (int i = 0; i < p_files.size(); i++) { + + Ref config; + config.instance(); + Error err = config->load(p_files[i] + ".import"); + ERR_CONTINUE(err != OK); + ERR_CONTINUE(!config->has_section_key("remap", "importer")); + String file_importer_name = config->get_value("remap", "importer"); + ERR_CONTINUE(file_importer_name == String()); + + if (importer_name != String() && importer_name != file_importer_name) { + print_line("one importer: " + importer_name + " the other: " + file_importer_name); + EditorNode::get_singleton()->show_warning(vformat(TTR("There are multiple importers for different types pointing to file %s, import aborted"), p_group_file)); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + source_file_options[p_files[i]] = Map(); + importer_name = file_importer_name; + + Ref importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); + ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_CORRUPT); + List options; + importer->get_import_options(&options); + //set default values + for (List::Element *E = options.front(); E; E = E->next()) { + + source_file_options[p_files[i]][E->get().option.name] = E->get().default_value; + } + + if (config->has_section("params")) { + List sk; + config->get_section_keys("params", &sk); + for (List::Element *E = sk.front(); E; E = E->next()) { + String param = E->get(); + Variant value = config->get_value("params", param); + //override with whathever is in file + source_file_options[p_files[i]][param] = value; + } + } + + base_paths[p_files[i]] = ResourceFormatImporter::get_singleton()->get_import_base_path(p_files[i]); + } + + ERR_FAIL_COND_V(importer_name == String(), ERR_UNCONFIGURED); + + Ref importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); + + Error err = importer->import_group_file(p_group_file, source_file_options, base_paths); + + //all went well, overwrite config files with proper remaps and md5s + for (Map >::Element *E = source_file_options.front(); E; E = E->next()) { + + String file = E->key(); + String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(file); + FileAccessRef f = FileAccess::open(file + ".import", FileAccess::WRITE); + ERR_FAIL_COND_V(!f, ERR_FILE_CANT_OPEN); + + //write manually, as order matters ([remap] has to go first for performance). + f->store_line("[remap]"); + f->store_line(""); + f->store_line("importer=\"" + importer->get_importer_name() + "\""); + if (importer->get_resource_type() != "") { + f->store_line("type=\"" + importer->get_resource_type() + "\""); + } + + Vector dest_paths; + + if (err == OK) { + String path = base_path + "." + importer->get_save_extension(); + f->store_line("path=\"" + path + "\""); + dest_paths.push_back(path); + } + + f->store_line("group_file=" + Variant(p_group_file).get_construct_string()); + + if (err == OK) { + f->store_line("valid=true"); + } else { + f->store_line("valid=false"); + } + f->store_line("[deps]\n"); + + f->store_line(""); + + f->store_line("source_file=" + Variant(file).get_construct_string()); + if (dest_paths.size()) { + Array dp; + for (int i = 0; i < dest_paths.size(); i++) { + dp.push_back(dest_paths[i]); + } + f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n"); + } + f->store_line("[params]"); + f->store_line(""); + + //store options in provided order, to avoid file changing. Order is also important because first match is accepted first. + + List options; + importer->get_import_options(&options); + //set default values + for (List::Element *F = options.front(); F; F = F->next()) { + + String base = F->get().option.name; + Variant v = F->get().default_value; + if (source_file_options[file].has(base)) { + v = source_file_options[file][base]; + } + String value; + VariantWriter::write_to_string(v, value); + f->store_line(base + "=" + value); + } + + f->close(); + + // Store the md5's of the various files. These are stored separately so that the .import files can be version controlled. + FileAccessRef md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE); + ERR_FAIL_COND_V(!md5s, ERR_FILE_CANT_OPEN); + + md5s->store_line("source_md5=\"" + FileAccess::get_md5(file) + "\""); + if (dest_paths.size()) { + md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n"); + } + md5s->close(); + + EditorFileSystemDirectory *fs = NULL; + int cpos = -1; + bool found = _find_file(file, &fs, cpos); + ERR_FAIL_COND_V(!found, ERR_UNCONFIGURED); + + //update modified times, to avoid reimport + fs->files[cpos]->modified_time = FileAccess::get_modified_time(file); + fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(file + ".import"); + fs->files[cpos]->deps = _get_dependencies(file); + fs->files[cpos]->type = importer->get_resource_type(); + fs->files[cpos]->import_valid = err == OK; + + //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it + //to reload properly + if (ResourceCache::has(file)) { + + Resource *r = ResourceCache::get(file); + + if (r->get_import_path() != String()) { + + String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(file); + r->set_import_path(dst_path); + r->set_import_last_modified_time(0); + } + } + + EditorResourcePreview::get_singleton()->check_for_invalidation(file); + } + + return err; +} + void EditorFileSystem::_reimport_file(const String &p_file) { EditorFileSystemDirectory *fs = NULL; @@ -1738,6 +1912,24 @@ void EditorFileSystem::_reimport_file(const String &p_file) { EditorResourcePreview::get_singleton()->check_for_invalidation(p_file); } +void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map > &group_files, Set &groups_to_reimport) { + + int fc = efd->files.size(); + const EditorFileSystemDirectory::FileInfo *const *files = efd->files.ptr(); + for (int i = 0; i < fc; i++) { + if (groups_to_reimport.has(files[i]->import_group_file)) { + if (!group_files.has(files[i]->import_group_file)) { + group_files[files[i]->import_group_file] = Vector(); + } + group_files[files[i]->import_group_file].push_back(efd->get_file_path(i)); + } + } + + for (int i = 0; i < efd->get_subdir_count(); i++) { + _find_group_files(efd->get_subdir(i), group_files, groups_to_reimport); + } +} + void EditorFileSystem::reimport_files(const Vector &p_files) { { //check that .import folder exists @@ -1757,22 +1949,58 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); Vector files; + Set groups_to_reimport; for (int i = 0; i < p_files.size(); i++) { - ImportFile ifile; - ifile.path = p_files[i]; - ifile.order = ResourceFormatImporter::get_singleton()->get_import_order(p_files[i]); - files.push_back(ifile); + + String group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(p_files[i]); + + if (group_file_cache.has(p_files[i])) { + //maybe the file itself is a group! + groups_to_reimport.insert(p_files[i]); + //groups do not belong to grups + group_file = String(); + } else if (group_file != String()) { + //it's a group file, add group to import and skip this file + groups_to_reimport.insert(group_file); + } else { + //it's a regular file + ImportFile ifile; + ifile.path = p_files[i]; + ifile.order = ResourceFormatImporter::get_singleton()->get_import_order(p_files[i]); + files.push_back(ifile); + } + + //group may have changed, so also update group reference + EditorFileSystemDirectory *fs = NULL; + int cpos = -1; + if (_find_file(p_files[i], &fs, cpos)) { + + fs->files.write[cpos]->import_group_file = group_file; + } } files.sort(); for (int i = 0; i < files.size(); i++) { pr.step(files[i].path.get_file(), i); - _reimport_file(files[i].path); } + //reimport groups + + if (groups_to_reimport.size()) { + Map > group_files; + _find_group_files(filesystem, group_files, groups_to_reimport); + for (Map >::Element *E = group_files.front(); E; E = E->next()) { + + Error err = _reimport_group(E->key(), E->get()); + if (err == OK) { + _reimport_file(E->key()); + } + } + } + _save_filesystem_cache(); importing = false; if (!is_scanning()) { @@ -1793,6 +2021,63 @@ Error EditorFileSystem::_resource_import(const String &p_path) { return OK; } +bool EditorFileSystem::is_group_file(const String &p_path) const { + return group_file_cache.has(p_path); +} + +void EditorFileSystem::_move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location) { + + int fc = efd->files.size(); + EditorFileSystemDirectory::FileInfo *const *files = efd->files.ptrw(); + for (int i = 0; i < fc; i++) { + + if (files[i]->import_group_file == p_group_file) { + + files[i]->import_group_file = p_new_location; + + Ref config; + config.instance(); + String path = efd->get_file_path(i) + ".import"; + Error err = config->load(path); + if (err != OK) { + continue; + } + if (config->has_section_key("remap", "group_file")) { + + config->set_value("remap", "group_file", p_new_location); + } + + List sk; + config->get_section_keys("params", &sk); + for (List::Element *E = sk.front(); E; E = E->next()) { + //not very clean, but should work + String param = E->get(); + String value = config->get_value("params", param); + if (value == p_group_file) { + config->set_value("params", param, p_new_location); + } + } + + config->save(path); + } + } + + for (int i = 0; i < efd->get_subdir_count(); i++) { + _move_group_files(efd->get_subdir(i), p_group_file, p_new_location); + } +} + +void EditorFileSystem::move_group_file(const String &p_path, const String &p_new_path) { + + if (get_filesystem()) { + _move_group_files(get_filesystem(), p_path, p_new_path); + if (group_file_cache.has(p_path)) { + group_file_cache.erase(p_path); + group_file_cache.insert(p_new_path); + } + } +} + void EditorFileSystem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_filesystem"), &EditorFileSystem::get_filesystem); diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 2a9e3254543..89437062026 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -56,6 +56,7 @@ class EditorFileSystemDirectory : public Object { uint64_t modified_time; uint64_t import_modified_time; bool import_valid; + String import_group_file; Vector deps; bool verified; //used for checking changes String script_class_name; @@ -167,6 +168,7 @@ class EditorFileSystem : public Node { uint64_t import_modification_time; Vector deps; bool import_valid; + String import_group_file; String script_class_name; String script_class_extends; String script_class_icon_path; @@ -211,6 +213,7 @@ class EditorFileSystem : public Node { void _update_extensions(); void _reimport_file(const String &p_file); + Error _reimport_group(const String &p_group_file, const Vector &p_files); bool _test_for_reimport(const String &p_path, bool p_only_imported_files); @@ -236,6 +239,12 @@ class EditorFileSystem : public Node { bool using_fat_32; //workaround for projects in FAT32 filesystem (pendrives, most of the time) + void _find_group_files(EditorFileSystemDirectory *efd, Map > &group_files, Set &groups_to_reimport); + + void _move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location); + + Set group_file_cache; + protected: void _notification(int p_what); static void _bind_methods(); @@ -260,6 +269,9 @@ public: void update_script_classes(); + bool is_group_file(const String &p_path) const; + void move_group_file(const String &p_path, const String &p_new_path); + EditorFileSystem(); ~EditorFileSystem(); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 851d6a0aa68..b729de2e2fc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -65,6 +65,7 @@ #include "editor/import/resource_importer_obj.h" #include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_texture.h" +#include "editor/import/resource_importer_texture_atlas.h" #include "editor/import/resource_importer_wav.h" #include "editor/plugins/animation_blend_space_1d_editor.h" #include "editor/plugins/animation_blend_space_2d_editor.h" @@ -5121,6 +5122,10 @@ EditorNode::EditorNode() { import_image.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_image); + Ref import_texture_atlas; + import_texture_atlas.instance(); + ResourceFormatImporter::get_singleton()->add_importer(import_texture_atlas); + Ref import_csv_translation; import_csv_translation.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 31f53305e2f..9d936d9b99e 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2993,13 +2993,17 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ EditorPropertyClassName *editor = memnew(EditorPropertyClassName); editor->setup("Object", p_hint_text); add_property_editor(p_path, editor); - } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) { + } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_SAVE_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) { Vector extensions = p_hint_text.split(","); bool global = p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE; bool folder = p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_GLOBAL_DIR; + bool save = p_hint == PROPERTY_HINT_SAVE_FILE; EditorPropertyPath *editor = memnew(EditorPropertyPath); editor->setup(extensions, folder, global); + if (save) { + editor->set_save_mode(); + } add_property_editor(p_path, editor); } else if (p_hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE || p_hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE || diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index c32cd1de503..aade6064126 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1257,6 +1257,10 @@ void FileSystemDock::_rename_operation_confirm() { return; } + if (EditorFileSystem::get_singleton()->is_group_file(old_path)) { + EditorFileSystem::get_singleton()->move_group_file(old_path, new_path); + } + //Present a more user friendly warning for name conflict DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); #if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED) @@ -1354,6 +1358,16 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool overw } } + //check groups + for (int i = 0; i < to_move.size(); i++) { + + print_line("is group: " + to_move[i].path + ": " + itos(EditorFileSystem::get_singleton()->is_group_file(to_move[i].path))); + if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) { + print_line("move to: " + p_to_path.plus_file(to_move[i].path.get_file())); + EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.plus_file(to_move[i].path.get_file())); + } + } + Map file_renames; Map folder_renames; bool is_moved = false; diff --git a/editor/import/atlas_import_failed.xpm b/editor/import/atlas_import_failed.xpm new file mode 100644 index 00000000000..52db6b76a65 --- /dev/null +++ b/editor/import/atlas_import_failed.xpm @@ -0,0 +1,414 @@ +/* XPM */ +static const char * atlas_import_failed_xpm[] = { +"128 128 283 2", +" c None", +". c #FFFFFF", +"+ c #FFDADA", +"@ c #FF0000", +"# c #FFD8D8", +"$ c #FFF7F7", +"% c #FF2E2E", +"& c #FFD4D4", +"* c #FFD6D6", +"= c #FFE3E3", +"- c #FFB3B3", +"; c #FFC8C8", +"> c #FF3535", +", c #FF8D8D", +"' c #FF7878", +") c #FF6E6E", +"! c #FFB5B5", +"~ c #FF0D0D", +"{ c #FFF0F0", +"] c #FFE8E8", +"^ c #FFC2C2", +"/ c #FFEDED", +"( c #FFBBBB", +"_ c #FFB9B9", +": c #FFA4A4", +"< c #FFFEFE", +"[ c #FFD9D9", +"} c #FF9393", +"| c #FF5858", +"1 c #FF3232", +"2 c #FF7575", +"3 c #FFC9C9", +"4 c #FFFCFC", +"5 c #FFBDBD", +"6 c #FF3838", +"7 c #FF9494", +"8 c #FFE2E2", +"9 c #FFD1D1", +"0 c #FFDEDE", +"a c #FFCACA", +"b c #FF6969", +"c c #FF8484", +"d c #FFEAEA", +"e c #FFE9E9", +"f c #FF3B3B", +"g c #FFC0C0", +"h c #FF6868", +"i c #FF7373", +"j c #FFF6F6", +"k c #FFADAD", +"l c #FF5D5D", +"m c #FF2626", +"n c #FF5C5C", +"o c #FFABAB", +"p c #FFCECE", +"q c #FF7070", +"r c #FF5555", +"s c #FF1C1C", +"t c #FFF4F4", +"u c #FF8282", +"v c #FF6060", +"w c #FFE7E7", +"x c #FF9D9D", +"y c #FF5656", +"z c #FF4242", +"A c #FF9B9B", +"B c #FFD0D0", +"C c #FFF8F8", +"D c #FF6A6A", +"E c #FF5151", +"F c #FFFBFB", +"G c #FF4949", +"H c #FFCDCD", +"I c #FFDDDD", +"J c #FF9E9E", +"K c #FFF9F9", +"L c #FFDCDC", +"M c #FF8F8F", +"N c #FFCBCB", +"O c #FFF5F5", +"P c #FF4747", +"Q c #FF9C9C", +"R c #FFEEEE", +"S c #FFFAFA", +"T c #FF1616", +"U c #FF8888", +"V c #FFC5C5", +"W c #FF2222", +"X c #FF4B4B", +"Y c #FFB8B8", +"Z c #FF7F7F", +"` c #FFE6E6", +" . c #FF8080", +".. c #FFB4B4", +"+. c #FFC3C3", +"@. c #FFD2D2", +"#. c #FFD7D7", +"$. c #FFDFDF", +"%. c #FFB7B7", +"&. c #FFF1F1", +"*. c #FF6262", +"=. c #FF8A8A", +"-. c #FFA9A9", +";. c #FFAEAE", +">. c #FFAAAA", +",. c #FF8B8B", +"'. c #FF4F4F", +"). c #FFFDFD", +"!. c #FFA3A3", +"~. c #FF2A2A", +"{. c #FFCFCF", +"]. c #FF8585", +"^. c #FF7676", +"/. c #FFD3D3", +"(. c #FFD5D5", +"_. c #FF8181", +":. c #FFC6C6", +"<. c #FFDBDB", +"[. c #FF9090", +"}. c #FFAFAF", +"|. c #FFA1A1", +"1. c #FFBABA", +"2. c #FF6C6C", +"3. c #FF5F5F", +"4. c #FF3D3D", +"5. c #FF9999", +"6. c #FFE0E0", +"7. c #FF8383", +"8. c #FFEFEF", +"9. c #FFF3F3", +"0. c #FFA8A8", +"a. c #FFB6B6", +"b. c #FF9F9F", +"c. c #FF4545", +"d. c #FFE5E5", +"e. c #FFE4E4", +"f. c #FFC7C7", +"g. c #FF6565", +"h. c #FFACAC", +"i. c #FF5A5A", +"j. c #FF7272", +"k. c #FF7C7C", +"l. c #FFBFBF", +"m. c #FF7171", +"n. c #FFECEC", +"o. c #FF8989", +"p. c #FF7777", +"q. c #FFC4C4", +"r. c #FF9898", +"s. c #FF8C8C", +"t. c #FF7A7A", +"u. c #FF8E8E", +"v. c #FFF2F2", +"w. c #FF9797", +"x. c #FFC1C1", +"y. c #FFA6A6", +"z. c #FFEBEB", +"A. c #FF4040", +"B. c #EDEDED", +"C. c #000000", +"D. c #AAAAAA", +"E. c #F6F6F6", +"F. c #1C1C1C", +"G. c #888888", +"H. c #7C7C7C", +"I. c #626262", +"J. c #B3B3B3", +"K. c #2A2A2A", +"L. c #959595", +"M. c #FDFDFD", +"N. c #C5C5C5", +"O. c #666666", +"P. c #353535", +"Q. c #777777", +"R. c #DEDEDE", +"S. c #6C6C6C", +"T. c #F5F5F5", +"U. c #ADADAD", +"V. c #DDDDDD", +"W. c #D8D8D8", +"X. c #B4B4B4", +"Y. c #FAFAFA", +"Z. c #949494", +"`. c #3B3B3B", +" + c #A8A8A8", +".+ c #C8C8C8", +"++ c #D4D4D4", +"@+ c #B9B9B9", +"#+ c #2E2E2E", +"$+ c #FEFEFE", +"%+ c #BABABA", +"&+ c #FCFCFC", +"*+ c #B2B2B2", +"=+ c #CACACA", +"-+ c #696969", +";+ c #222222", +">+ c #F2F2F2", +",+ c #555555", +"'+ c #C4C4C4", +")+ c #EBEBEB", +"!+ c #727272", +"~+ c #585858", +"{+ c #0D0D0D", +"]+ c #B1B1B1", +"^+ c #E5E5E5", +"/+ c #C0C0C0", +"(+ c #8F8F8F", +"_+ c #4D4D4D", +":+ c #F4F4F4", +"<+ c #7D7D7D", +"[+ c #E4E4E4", +"}+ c #F3F3F3", +"|+ c #383838", +"1+ c #A9A9A9", +"2+ c #D6D6D6", +"3+ c #D5D5D5", +"4+ c #5F5F5F", +"5+ c #C6C6C6", +"6+ c #E2E2E2", +"7+ c #FBFBFB", +"8+ c #404040", +"9+ c #909090", +"0+ c #EEEEEE", +"a+ c #878787", +"b+ c #E8E8E8", +"c+ c #494949", +"d+ c #424242", +"e+ c #E6E6E6", +"f+ c #CFCFCF", +"g+ c #DCDCDC", +"h+ c #161616", +"i+ c #BBBBBB", +"j+ c #CCCCCC", +"k+ c #B0B0B0", +"l+ c #C7C7C7", +"m+ c #858585", +"n+ c #F8F8F8", +"o+ c #D7D7D7", +"p+ c #BDBDBD", +"q+ c #ECECEC", +"r+ c #939393", +"s+ c #A1A1A1", +"t+ c #7A7A7A", +"u+ c #4B4B4B", +"v+ c #E9E9E9", +"w+ c #717171", +"x+ c #AFAFAF", +"y+ c #454545", +"z+ c #F9F9F9", +"A+ c #DBDBDB", +"B+ c #C1C1C1", +"C+ c #707070", +"D+ c #323232", +"E+ c #9D9D9D", +"F+ c #D1D1D1", +"G+ c #6D6D6D", +"H+ c #262626", +"I+ c #6E6E6E", +"J+ c #808080", +"K+ c #BFBFBF", +"L+ c #999999", +"M+ c #F1F1F1", +"N+ c #DADADA", +"O+ c #9F9F9F", +"P+ c #8B8B8B", +"Q+ c #7F7F7F", +"R+ c #9E9E9E", +"S+ c #F0F0F0", +"T+ c #A4A4A4", +"U+ c #A5A5A5", +"V+ c #CDCDCD", +"W+ c #CBCBCB", +"X+ c #9B9B9B", +"Y+ c #D9D9D9", +"Z+ c #A0A0A0", +"`+ c #9C9C9C", +" @ c #C2C2C2", +".@ c #636363", +"+@ c #D0D0D0", +"@@ c #6A6A6A", +"#@ c #898989", +"$@ c #C3C3C3", +"%@ c #A7A7A7", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . $ % @ & . . . . . * @ + . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . . . . ; @ > , . . . . . * @ + . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . . . . ' ) ! ~ { . . . . * @ + . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . . . ] @ ^ / @ ( . . . _ @ @ @ @ @ : . + @ # . . < [ } | 1 2 3 . . . . 4 5 ) 6 | 7 8 . . . . . . . . = @ - . . 9 @ 0 a b > c d . e , f | g . . . . 9 @ 0 a h % i & . . . . j k l m n o j . . . 9 @ 0 p q m r @ @ @ @ @ : . . . . . . . . . . ", +". . . . . . . . . . . . k s t . u v < . . _ @ @ @ @ @ : . + @ # . . w @ @ @ @ @ @ 5 . . . k @ @ @ @ @ % . . . . . . . . = @ - . . 9 @ x @ @ @ @ y d z @ @ @ @ * . . . 9 @ A @ @ @ @ @ B . . C D @ @ @ @ @ h C . . 9 @ x @ @ @ E @ @ @ @ @ : . . . . . . . . . . ", +". . . . . . . . . . . F G 7 . . H @ I . . . * @ + . . . . + @ # . . ] J 8 j K 0 h 6 K . . l l = F j L M . . . . . . . . = @ - . . 9 @ % N j O J @ P Q R S & T U . . . 9 @ s ^ O j V W X F . Y @ Z ` S w .@ ... . 9 @ s +.t . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . . @.@ #.. . K 6 x . . . * @ + . . . . + @ # . . . . . . . . # @ $.. . ' M . . . . . . . . . . . . . = @ - . . 9 @ %.. . . &.@ *.4 . . . =.r . . . 9 @ -.. . . . ;.@ 0 . q 6 t . . . t f h . . 9 @ >.. . . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . . ,.'.).. . . !.~.j . . * @ + . . . . + @ # . . . {.].P ~ @ @ @ 9 . . 8 r ^.- /.j . . . . . . . . . = @ - . . 9 @ + . . . . @ A . . . . !.~ . . . 9 @ (.. . . . # @ N . 1 _.. . . . . c s . . 9 @ (.. . . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . { ~ @ @ @ @ @ @ @ :.. . * @ + . . . . + @ # . . ^ @ @ @ @ @ @ @ H . . . F <._ [.> }.. . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ (.. . . . # @ N . 1 u . . . . . c s . . 9 @ 0 . . . . * @ + . . . . . . . . . . . . . ", +". . . . . . . . . . 1.@ @ @ @ @ @ @ @ ^.. . #.@ # . . . . + @ # . . 2.r $.$ < . [ @ H . . . . . . . + @ * . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ -.. . . . ;.@ 0 . q 6 t . . . O f h . . 9 @ 0 . . . . #.@ # . . . . . . . . . . . . . ", +". . . . . . . . . < 3.4.K . . . . . 5.@ w . 6.@ ;.F . . . + @ # . . 2.n ` 4 $ + *.@ H . 4 7.@.8.4 9.k @ ^ . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ s ^ O j V W X F . %.@ u w F ] u @ - . . 9 @ 0 . . . . 6.@ ;.F . . . . . . . . . . . . ", +". . . . . . . . . L @ 0.. . . . . . L @ o . K > @ @ @ : . + @ # . . a.@ @ @ @ @ b.@ H . F @ @ @ @ @ @ > / . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ A @ @ @ @ @ B . . C D @ @ @ @ @ h $ . . 9 @ 0 . . . . K > @ @ @ : . . . . . . . . . . ", +". . . . . . . . . A @ ` . . . . . . < *.c.F . # ^.~.@ : . + @ # . . 4 _ *.% q N d.@ H . . e.: h % l b.e . . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ 0 f.g.~.i /.. . . . j h.n W i.>.O . . . 9 @ 0 . . . . . # ^.~.@ : . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ # . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ @ # . . . . . . . . . . + @ # . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ @ # . . . . . . . . . . . . . . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . < [ } | 1 2 3 . . . . + @ # . . + @ # . . . 4 l.m.% G 5.n.. . . . &.Q z c.x O j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . w @ @ @ @ @ @ 5 . . . + @ # . . + @ # . . ).o.@ @ @ @ @ c./ . . $ v @ @ @ @ p.2.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ U ] J 8 j K 0 h 6 K . . + @ # . . + @ # . . q.@ } w F O q.s r.. . a.@ s.d S 8 ) @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ U . . . . . . # @ $.. . + @ # . . + @ # . . t.| ).. . . . !.> < . q G C . . . d @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . {.].P ~ @ @ @ 9 . . + @ # . . + @ # . . > @ @ @ @ @ @ @ @ O . % u.. . . . . y k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . ^ @ @ @ @ @ @ @ H . . + @ # . . + @ # . . 1 @ @ @ @ @ @ @ @ v.. % u.. . . . . r k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . 2.r $.$ < . [ @ H . . + @ # . . + @ # . . ^.h < . . . . . . . . q G C . . . d @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . 2.n ` 4 $ + *.@ H . . + @ # . . + @ # . . +.@ w.e.C S d x.y.. . a.@ s.z.S 8 ) @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . a.@ @ @ @ @ b.@ H . . + @ # . . + @ # . . ).M @ @ @ @ @ @ s.. . $ v @ @ @ @ ^.2.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . 4 _ *.% q N d.@ H . . + @ # . . + @ # . . . ).f.k.6 z ' Y v.. . . &.A A.z A O j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.B.C.D.B.C.D.. . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.C.C.C.F.. B.C.D.B.C.D.B.C.D.. . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . . . . B.C.D.B.C.D.. . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . I.C.C.C.J.B.C.C.C.K.L.M.. N.O.P.Q.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.C.C.C.H.. B.C.D.B.C.D.B.C.D.. . . . C.G.. . B.C.S.T.U.C.V.W.C.X.Y.Z.`.E.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . . C.G.. . B.C. +. .+C.++@+C.C.C.C.C.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . . #+Q.$+. B.C.D.. .+C.++W.C.%+&+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . . *+`.C.=+B.C.D.. .+C.++. N.-+;+C.C.Y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . B.C.D.B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Y.C.>+,+R.. . '+C.C.)+. . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . E.C.C.C.C.F.. B.C.D.B.C.D.. . . . . . . Y.C.>+,+R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Y.C.>+,+R.. . !+~+{+]+. . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . E.C.H.. . . . . . . B.C.D.. . . . . . . Y.C.>+,+R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Y.C.>+,+R.. ^+C./+(+_+&+. I.C.C.C.J.B.C.D.:+C.C.P.<+[+. }+G.|+C.C.>+. . . E.C.H.. . . . B.C.D.B.C.D.. N.O.P.Q.R.. Y.C.>+,+R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1+;+T.2+C.3+. . C.G.. . B.C.D.. . . T.4+Q.. 5+C.X.6+Y.. . . . E.C.C.C.C.H.. B.C.D.B.C.D.W.C.X.Y.Z.`.E.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7+8+C.C.C.C.9+. . C.G.. . B.C.D.0+a+8+C.C.|+. b+c+C.C.d+e+. . . E.C.H.. . . . B.C.D.B.C.D.@+C.C.C.C.C.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . f+C.g+. . J.h+>+. #+Q.$+. B.C.D.i+C.j+0+,+#+. . &+e+k+C.l+. . . E.C.H.. . . . B.C.D.B.C.D.W.C.%+&+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . m+h+n+. . o+C.p+. *+`.C.=+B.C.D.q+!+{+C.C.#+. =+C.C.8+r+E.. . . E.C.H.. . . . B.C.D.B.C.D.. N.-+;+C.C.Y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . V.4+C.s+C.U.. . . . . . . B.C.D.. . . . N.C.W.. . . B.C.D.. . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . t+u+Y.v+C.U.. . . . . . . B.C.D.. . . . N.C.W.. . . B.C.D.. . . . . . . . . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . u+w+. . . . . . . . . . . B.C.D.. . . . N.C.W.. . . . . . . . . . . . . . . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . H.C.C.C.C.C.U.. N.O.P.Q.R.. B.C.D.. x+d+C.C.C.W.. . . B.C.D.B.C.C.C.K.L.M.. . . I.C.C.C.J.B.C.C.C.K.L.M.. N.O.P.Q.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.W.C.X.Y.Z.`.E.B.C.D.2+C.x+z+(+C.W.. . . B.C.D.B.C.S.T.U.C.V.. . . . C.G.. . B.C.S.T.U.C.V.W.C.X.Y.Z.`.E.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.@+C.C.C.C.C.R.B.C.D.%+C.A+. B+C.W.. . . B.C.D.B.C. +. .+C.++. . . . C.G.. . B.C. +. .+C.++@+C.C.C.C.C.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.W.C.%+&+. . . B.C.D.2+C.k+z+9+C.W.. . . B.C.D.B.C.D.. .+C.++. . . . #+Q.$+. B.C.D.. .+C.++W.C.%+&+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.. N.-+;+C.C.Y.B.C.D.. x+d+C.C.C.W.. . . B.C.D.B.C.D.. .+C.++. . . . *+`.C.=+B.C.D.. .+C.++. N.-+;+C.C.Y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . N.C.W.. . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . N.C.W.. . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.)+C.C.C.K.C+O.K.!+B.B.C.C.C.D+E+7+. '+O.P.C+F+. B.C.C.C.,+I.C.C.C.J.. . . . x+d+C.C.C.W.. '+O.P.C+F+. . .+G+H+C.R.B.C.D.>+I+I.q+. . . :+C.C.P.<+[+. B.C.C.C.K.L.M.. x+d+C.C.C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.)+C.!+T.J+C.=+g+C.]+B.C.I+E.=+C.K+W.C.]+Y.L+h+b+B.C.O.M+. . C.G.. . . . . 2+C.x+z+(+C.W.W.C.]+Y.L+h+b+N+C.O+z+. . B.C.P+4+Q+T.. . . . . . . T.4+Q.. B.C.S.T.U.C.V.2+C.x+z+(+C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.)+C. +. R+C.M+S+C.T+B.C.U+. M+C.E+@+C.V.. =+C.V+B.C. +. . . C.G.. . . . . %+C.A+. B+C.W.@+C.V.. =+C.V+@+C.A+. . . B.C.C.C.R.. . . . . 0+a+8+C.C.|+. B.C. +. .+C.++%+C.A+. B+C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C+E.W+C.K+W.C.*+Y.X+{+b+B.C.D.. . . #+Q.$+. . . . 2+C.k+z+9+C.W.W.C.*+Y.X+{+b+Y+C.s+z+. . B.C.Z+m+|+V.. . . . i+C.j+0+,+#+. B.C.D.. .+C.++2+C.k+z+9+C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C.C.D+`+7+. @.@D+G++@. B.C.D.. . . *+`.C.=+. . . . x+d+C.C.C.W.. @.@D+G++@. . l+@@H+C.R.B.C.D.Y.#@K.2+. . . q+!+{+C.C.#+. B.C.D.. .+C.++. x+d+C.C.C.W.. . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.C.C.,+. N.O.P.Q.R.. . . . . B.C.D.)+C.C.C.K.C+O.K.!+B.B.C.C.C.D+E+7+. '+O.P.C+F+. B.C.C.C.,+I.C.C.C.J.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.O.M+. W.C.X.Y.Z.`.E.$@C.C.%@B.C.D.)+C.!+T.J+C.=+g+C.]+B.C.I+E.=+C.K+W.C.]+Y.L+h+b+B.C.O.M+. . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C. +. . @+C.C.C.C.C.R.. . . . B.C.D.)+C. +. R+C.M+S+C.T+B.C.U+. M+C.E+@+C.V.. =+C.V+B.C. +. . . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . W.C.%+&+. . . . . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C+E.W+C.K+W.C.*+Y.X+{+b+B.C.D.. . . #+Q.$+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . N.-+;+C.C.Y.. . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C.C.D+`+7+. @.@D+G++@. B.C.D.. . . *+`.C.=+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "}; diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp new file mode 100644 index 00000000000..35fdd32e2c0 --- /dev/null +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -0,0 +1,382 @@ +#include "resource_importer_texture_atlas.h" + +#include "atlas_import_failed.xpm" +#include "core/io/image_loader.h" +#include "core/io/resource_saver.h" +#include "core/os/file_access.h" +#include "editor/editor_atlas_packer.h" +#include "scene/resources/mesh.h" +#include "scene/resources/texture.h" + +String ResourceImporterTextureAtlas::get_importer_name() const { + + return "texture_atlas"; +} + +String ResourceImporterTextureAtlas::get_visible_name() const { + + return "TextureAtlas"; +} +void ResourceImporterTextureAtlas::get_recognized_extensions(List *p_extensions) const { + + ImageLoader::get_recognized_extensions(p_extensions); +} + +String ResourceImporterTextureAtlas::get_save_extension() const { + return "res"; +} + +String ResourceImporterTextureAtlas::get_resource_type() const { + + return "Texture"; +} + +bool ResourceImporterTextureAtlas::get_option_visibility(const String &p_option, const Map &p_options) const { + + return true; +} + +int ResourceImporterTextureAtlas::get_preset_count() const { + return 0; +} +String ResourceImporterTextureAtlas::get_preset_name(int p_idx) const { + + return String(); +} + +void ResourceImporterTextureAtlas::get_import_options(List *r_options, int p_preset) const { + + r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "atlas_file", PROPERTY_HINT_SAVE_FILE, "*.png"), "")); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_mode", PROPERTY_HINT_ENUM, "Region,Mesh2D"), 0)); +} + +String ResourceImporterTextureAtlas::get_option_group_file() const { + return "atlas_file"; +} + +Error ResourceImporterTextureAtlas::import(const String &p_source_file, const String &p_save_path, const Map &p_options, List *r_platform_variants, List *r_gen_files, Variant *r_metadata) { + + /* If this happens, it's because the atlas_file field was not filled, so just import a broken texture */ + + //use an xpm because it's size independent, the editor images are vector and size dependent + //it's a simple hack + Ref broken = memnew(Image((const char **)atlas_import_failed_xpm)); + Ref broken_texture; + broken_texture.instance(); + broken_texture->create_from_image(broken); + + String target_file = p_save_path + ".tex"; + + ResourceSaver::save(target_file, broken_texture); + + return OK; +} + +static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_transposed, Ref p_image, const Ref &p_src_image) { + + int width = p_image->get_width(); + int height = p_image->get_height(); + int src_width = p_src_image->get_width(); + int src_height = p_src_image->get_height(); + + int x[3]; + int y[3]; + + for (int j = 0; j < 3; j++) { + + x[j] = vertices[j].x; + y[j] = vertices[j].y; + } + + // sort the points vertically + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + } + if (y[0] > y[1]) { + SWAP(x[0], x[1]); + SWAP(y[0], y[1]); + } + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + } + + double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1); + double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1); + double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1); + double xf = x[0]; + double xt = x[0] + dx_upper; // if y[0] == y[1], special case + for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) { + if (yi >= 0) { + for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) { + + int px = xi, py = yi; + int sx = px, sy = py; + sx = CLAMP(sx, 0, src_width); + sy = CLAMP(sy, 0, src_height); + Color color = p_src_image->get_pixel(sx, sy); + if (p_transposed) { + SWAP(px, py); + } + px += p_offset.x; + py += p_offset.y; + + //may have been cropped, so don't blit what is not visible? + if (px < 0 || px >= width) { + continue; + } + if (py < 0 || py >= height) { + continue; + } + p_image->set_pixel(px, py, color); + } + + for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) { + int px = xi, py = yi; + int sx = px, sy = py; + sx = CLAMP(sx, 0, src_width); + sy = CLAMP(sy, 0, src_height); + Color color = p_src_image->get_pixel(sx, sy); + if (p_transposed) { + SWAP(px, py); + } + px += p_offset.x; + py += p_offset.y; + + //may have been cropped, so don't blit what is not visible? + if (px < 0 || px >= width) { + continue; + } + if (py < 0 || py >= height) { + continue; + } + p_image->set_pixel(px, py, color); + } + } + xf += dx_far; + if (yi < y[1]) + xt += dx_upper; + else + xt += dx_low; + } +} + +Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file, const Map > &p_source_file_options, const Map &p_base_paths) { + + ERR_FAIL_COND_V(p_source_file_options.size() == 0, ERR_BUG); //should never happen + + Vector charts; + Vector pack_data_files; + + pack_data_files.resize(p_source_file_options.size()); + + int idx = 0; + for (const Map >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) { + + PackData &pack_data = pack_data_files.write[idx]; + String source = E->key(); + const Map &options = E->get(); + + Ref image; + image.instance(); + Error err = ImageLoader::load_image(source, image); + ERR_CONTINUE(err != OK); + + pack_data.image = image; + + int mode = options["import_mode"]; + + if (mode == IMPORT_MODE_REGION) { + + pack_data.is_mesh = false; + + EditorAtlasPacker::Chart chart; + + //clip a region from the image + Rect2 used_rect = image->get_used_rect(); + pack_data.region = used_rect; + + chart.vertices.push_back(used_rect.position); + chart.vertices.push_back(used_rect.position + Vector2(used_rect.size.x, 0)); + chart.vertices.push_back(used_rect.position + Vector2(used_rect.size.x, used_rect.size.y)); + chart.vertices.push_back(used_rect.position + Vector2(0, used_rect.size.y)); + EditorAtlasPacker::Chart::Face f; + f.vertex[0] = 0; + f.vertex[1] = 1; + f.vertex[2] = 2; + chart.faces.push_back(f); + f.vertex[0] = 0; + f.vertex[1] = 2; + f.vertex[2] = 3; + chart.faces.push_back(f); + chart.can_transpose = false; + pack_data.chart_vertices.push_back(chart.vertices); + pack_data.chart_pieces.push_back(charts.size()); + charts.push_back(chart); + + } else { + pack_data.is_mesh = true; + + Ref bit_map; + bit_map.instance(); + bit_map->create_from_image_alpha(image); + Vector > polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height())); + + for (int j = 0; j < polygons.size(); j++) { + + EditorAtlasPacker::Chart chart; + chart.vertices = polygons[j]; + chart.can_transpose = true; + + Vector poly = Geometry::triangulate_polygon(polygons[j]); + for (int i = 0; i < poly.size(); i += 3) { + + EditorAtlasPacker::Chart::Face f; + f.vertex[0] = poly[i + 0]; + f.vertex[1] = poly[i + 1]; + f.vertex[2] = poly[i + 2]; + chart.faces.push_back(f); + } + + pack_data.chart_pieces.push_back(charts.size()); + charts.push_back(chart); + + pack_data.chart_vertices.push_back(polygons[j]); + } + } + } + + //pack the charts + int atlas_width, atlas_height; + EditorAtlasPacker::chart_pack(charts, atlas_width, atlas_height); + + //blit the atlas + Ref new_atlas; + new_atlas.instance(); + new_atlas->create(atlas_width, atlas_height, false, Image::FORMAT_RGBA8); + + new_atlas->lock(); + + for (int i = 0; i < pack_data_files.size(); i++) { + + PackData &pack_data = pack_data_files.write[i]; + pack_data.image->lock(); + for (int j = 0; j < pack_data.chart_pieces.size(); j++) { + const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[j]]; + for (int k = 0; k < chart.faces.size(); k++) { + Vector2 positions[3]; + for (int l = 0; l < 3; l++) { + int vertex_idx = chart.faces[k].vertex[l]; + positions[l] = chart.vertices[vertex_idx]; + } + + _plot_triangle(positions, chart.final_offset, chart.transposed, new_atlas, pack_data.image); + } + } + pack_data.image->unlock(); + } + new_atlas->unlock(); + + //save the atlas + + new_atlas->save_png(p_group_file); + + //update cache if existing, else create + Ref cache; + if (ResourceCache::has(p_group_file)) { + Resource *resptr = ResourceCache::get(p_group_file); + cache.reference_ptr(resptr); + } else { + Ref res_cache; + res_cache.instance(); + res_cache->create_from_image(new_atlas); + res_cache->set_path(p_group_file); + cache = res_cache; + } + + //save the images + idx = 0; + for (const Map >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) { + + PackData &pack_data = pack_data_files.write[idx]; + + Ref texture; + + if (!pack_data.is_mesh) { + Vector2 offset = charts[pack_data.chart_pieces[0]].vertices[0] + charts[pack_data.chart_pieces[0]].final_offset; + + //region + Ref atlas_texture; + atlas_texture.instance(); + atlas_texture->set_atlas(cache); + atlas_texture->set_region(Rect2(offset, pack_data.region.size)); + atlas_texture->set_margin(Rect2(pack_data.region.position, Size2(pack_data.image->get_width(), pack_data.image->get_height()) - pack_data.region.size)); + + texture = atlas_texture; + } else { + Ref mesh; + mesh.instance(); + + for (int i = 0; i < pack_data.chart_pieces.size(); i++) { + const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[i]]; + PoolVector vertices; + PoolVector indices; + PoolVector uvs; + int vc = chart.vertices.size(); + int fc = chart.faces.size(); + vertices.resize(vc); + uvs.resize(vc); + indices.resize(fc * 3); + + { + PoolVector::Write vw = vertices.write(); + PoolVector::Write iw = indices.write(); + PoolVector::Write uvw = uvs.write(); + + for (int j = 0; j < vc; j++) { + vw[j] = chart.vertices[j]; + Vector2 uv = chart.vertices[j]; + if (chart.transposed) { + SWAP(uv.x, uv.y); + } + uv += chart.final_offset; + uv /= new_atlas->get_size(); //normalize uv to 0-1 range + uvw[j] = uv; + } + + for (int j = 0; j < fc; j++) { + iw[j * 3 + 0] = chart.faces[j].vertex[0]; + iw[j * 3 + 1] = chart.faces[j].vertex[1]; + iw[j * 3 + 2] = chart.faces[j].vertex[2]; + } + } + + Array arrays; + arrays.resize(Mesh::ARRAY_MAX); + arrays[Mesh::ARRAY_VERTEX] = vertices; + arrays[Mesh::ARRAY_TEX_UV] = uvs; + arrays[Mesh::ARRAY_INDEX] = indices; + + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays); + } + + Ref mesh_texture; + mesh_texture.instance(); + mesh_texture->set_base_texture(cache); + mesh_texture->set_image_size(pack_data.image->get_size()); + mesh_texture->set_mesh(mesh); + + texture = mesh_texture; + //mesh + } + + String save_path = p_base_paths[E->key()] + ".res"; + ResourceSaver::save(save_path, texture); + } + + return OK; +} + +ResourceImporterTextureAtlas::ResourceImporterTextureAtlas() { +} diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h new file mode 100644 index 00000000000..62be570dc65 --- /dev/null +++ b/editor/import/resource_importer_texture_atlas.h @@ -0,0 +1,42 @@ +#ifndef RESOURCE_IMPORTER_TEXTURE_ATLAS_H +#define RESOURCE_IMPORTER_TEXTURE_ATLAS_H + +#include "core/image.h" +#include "core/io/resource_importer.h" +class ResourceImporterTextureAtlas : public ResourceImporter { + GDCLASS(ResourceImporterTextureAtlas, ResourceImporter) + + struct PackData { + Rect2 region; + bool is_mesh; + Vector chart_pieces; //one for region, many for mesh + Vector > chart_vertices; //for mesh + Ref image; + }; + +public: + enum ImportMode { + IMPORT_MODE_REGION, + IMPORT_MODE_2D_MESH + }; + + virtual String get_importer_name() const; + virtual String get_visible_name() const; + virtual void get_recognized_extensions(List *p_extensions) const; + virtual String get_save_extension() const; + virtual String get_resource_type() const; + + virtual int get_preset_count() const; + virtual String get_preset_name(int p_idx) const; + + virtual void get_import_options(List *r_options, int p_preset = 0) const; + virtual bool get_option_visibility(const String &p_option, const Map &p_options) const; + virtual String get_option_group_file() const; + + virtual Error import(const String &p_source_file, const String &p_save_path, const Map &p_options, List *r_platform_variants, List *r_gen_files = NULL, Variant *r_metadata = NULL); + virtual Error import_group_file(const String &p_group_file, const Map > &p_source_file_options, const Map &p_base_paths); + + ResourceImporterTextureAtlas(); +}; + +#endif // RESOURCE_IMPORTER_TEXTURE_ATLAS_H diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 15539ee3db9..b307ec649a3 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -438,6 +438,8 @@ void ImportDock::_reimport() { Error err = config->load(params->paths[i] + ".import"); ERR_CONTINUE(err != OK); + String importer_name = params->importer->get_importer_name(); + if (params->checking) { //update only what edited (checkboxes) for (List::Element *E = params->properties.front(); E; E = E->next()) { @@ -447,7 +449,7 @@ void ImportDock::_reimport() { } } else { //override entirely - config->set_value("remap", "importer", params->importer->get_importer_name()); + config->set_value("remap", "importer", importer_name); config->erase_section("params"); for (List::Element *E = params->properties.front(); E; E = E->next()) { @@ -455,6 +457,19 @@ void ImportDock::_reimport() { } } + //handle group file + Ref importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); + ERR_CONTINUE(!importer.is_valid()); + String group_file_property = importer->get_option_group_file(); + if (group_file_property != String()) { + //can import from a group (as in, atlas) + ERR_CONTINUE(!params->values.has(group_file_property)); + String group_file = params->values[group_file_property]; + config->set_value("remap", "group_file", group_file); + } else { + config->set_value("remap", "group_file", Variant()); //clear group file if unused + } + config->save(params->paths[i] + ".import"); } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 2739f715436..78e98deb93e 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -891,13 +891,13 @@ void CanvasItem::draw_colored_polygon(const Vector &p_points, const Colo VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, p_antialiased); } -void CanvasItem::draw_mesh(const Ref &p_mesh, const Ref &p_texture, const Ref &p_normal_map) { +void CanvasItem::draw_mesh(const Ref &p_mesh, const Ref &p_texture, const Ref &p_normal_map, const Transform2D &p_transform, const Color &p_modulate) { ERR_FAIL_COND(p_mesh.is_null()); RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), texture_rid, normal_map_rid); + VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid); } void CanvasItem::draw_multimesh(const Ref &p_multimesh, const Ref &p_texture, const Ref &p_normal_map) { @@ -1168,7 +1168,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "antialiased"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1))); - ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref())); + ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Ref()), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map"), &CanvasItem::draw_multimesh, DEFVAL(Ref())); ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index bf7cfa8e758..a020ab50292 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -317,7 +317,7 @@ public: void draw_polygon(const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), Ref p_texture = Ref(), const Ref &p_normal_map = Ref(), bool p_antialiased = false); void draw_colored_polygon(const Vector &p_points, const Color &p_color, const Vector &p_uvs = Vector(), Ref p_texture = Ref(), const Ref &p_normal_map = Ref(), bool p_antialiased = false); - void draw_mesh(const Ref &p_mesh, const Ref &p_texture, const Ref &p_normal_map); + void draw_mesh(const Ref &p_mesh, const Ref &p_texture, const Ref &p_normal_map, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1)); void draw_multimesh(const Ref &p_multimesh, const Ref &p_texture, const Ref &p_normal_map); void draw_string(const Ref &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 3148df15ddb..9face3e476d 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -635,6 +635,7 @@ void register_scene_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 55264bcdf9d..a9d85be0dc0 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -595,6 +595,64 @@ Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) con return result_array; } +void BitMap::resize(const Size2& p_new_size) { + + Ref new_bitmap; + new_bitmap.instance(); + new_bitmap->create(p_new_size); + int lw = MIN(width,p_new_size.width); + int lh = MIN(height,p_new_size.height); + for(int x=0;xset_bit(Vector2(x,y),get_bit(Vector2(x,y))); + } + } + + width = new_bitmap->width; + height = new_bitmap->height; + bitmask = new_bitmap->bitmask; +} + +Ref BitMap::convert_to_image() const { + + Ref image; + image.instance(); + image->create(width,height,false,Image::FORMAT_L8); + image->lock(); + for(int i=0;iset_pixel( i,j,get_bit(Point2(i,j)) ? Color(1,1,1) : Color(0,0,0)); + } + } + + image->unlock(); + + return image; +} +void BitMap::blit(const Vector2& p_pos,const Ref& p_bitmap) { + + int x = p_pos.x; + int y = p_pos.y; + int w = p_bitmap->get_size().width; + int h = p_bitmap->get_size().height; + + for(int i=0;i=width) + continue; + if (py<0 || py>=height) + continue; + if (p_bitmap->get_bit(Vector2(i,j))) { + set_bit(Vector2(x,y),true); + } + } + } + +} + + void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index b3c86afd383..6e1171b8a91 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -64,9 +64,13 @@ public: int get_true_bit_count() const; Size2 get_size() const; + void resize(const Size2& p_new_size); void grow_mask(int p_pixels, const Rect2 &p_rect); + void blit(const Vector2& p_pos,const Ref& p_bitmap); + Ref convert_to_image() const; + Vector > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const; BitMap(); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 3ca2b56d081..a5eb950c366 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -34,6 +34,7 @@ #include "core/io/image_loader.h" #include "core/method_bind_ext.gen.inc" #include "core/os/os.h" +#include "mesh.h" #include "scene/resources/bit_map.h" Size2 Texture::get_size() const { @@ -1133,6 +1134,138 @@ AtlasTexture::AtlasTexture() { filter_clip = false; } +///////////////////////////////////////// + +int MeshTexture::get_width() const { + return size.width; +} +int MeshTexture::get_height() const { + return size.height; +} +RID MeshTexture::get_rid() const { + return RID(); +} + +bool MeshTexture::has_alpha() const { + return false; +} + +void MeshTexture::set_flags(uint32_t p_flags) { +} + +uint32_t MeshTexture::get_flags() const { + return 0; +} + +void MeshTexture::set_mesh(const Ref &p_mesh) { + mesh = p_mesh; +} +Ref MeshTexture::get_mesh() const { + return mesh; +} + +void MeshTexture::set_image_size(const Size2 &p_size) { + size = p_size; +} + +Size2 MeshTexture::get_image_size() const { + + return size; +} + +void MeshTexture::set_base_texture(const Ref &p_texture) { + base_texture = p_texture; +} + +Ref MeshTexture::get_base_texture() const { + return base_texture; +} + +void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref &p_normal_map) const { + + if (mesh.is_null() || base_texture.is_null()) { + return; + } + Transform2D xform; + xform.set_origin(p_pos); + if (p_transpose) { + SWAP(xform.elements[0][1], xform.elements[1][0]); + SWAP(xform.elements[0][0], xform.elements[1][1]); + } + RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); + VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid); +} +void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref &p_normal_map) const { + if (mesh.is_null() || base_texture.is_null()) { + return; + } + Transform2D xform; + Vector2 origin = p_rect.position; + if (p_rect.size.x < 0) { + origin.x += size.x; + } + if (p_rect.size.y < 0) { + origin.y += size.y; + } + xform.set_origin(origin); + xform.set_scale(p_rect.size / size); + + if (p_transpose) { + SWAP(xform.elements[0][1], xform.elements[1][0]); + SWAP(xform.elements[0][0], xform.elements[1][1]); + } + RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); + VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid); +} +void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref &p_normal_map, bool p_clip_uv) const { + + if (mesh.is_null() || base_texture.is_null()) { + return; + } + Transform2D xform; + Vector2 origin = p_rect.position; + if (p_rect.size.x < 0) { + origin.x += size.x; + } + if (p_rect.size.y < 0) { + origin.y += size.y; + } + xform.set_origin(origin); + xform.set_scale(p_rect.size / size); + + if (p_transpose) { + SWAP(xform.elements[0][1], xform.elements[1][0]); + SWAP(xform.elements[0][0], xform.elements[1][1]); + } + RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); + VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid); +} +bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { + r_rect = p_rect; + r_src_rect = p_src_rect; + return true; +} + +bool MeshTexture::is_pixel_opaque(int p_x, int p_y) const { + return true; +} + +void MeshTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshTexture::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &MeshTexture::get_mesh); + ClassDB::bind_method(D_METHOD("set_image_size", "size"), &MeshTexture::set_image_size); + ClassDB::bind_method(D_METHOD("get_image_size"), &MeshTexture::get_image_size); + ClassDB::bind_method(D_METHOD("set_base_texture", "texture"), &MeshTexture::set_base_texture); + ClassDB::bind_method(D_METHOD("get_base_texture"), &MeshTexture::get_base_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_base_texture", "get_base_texture"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1"), "set_image_size", "get_image_size"); +} + +MeshTexture::MeshTexture() { +} + ////////////////////////////////////////// int LargeTexture::get_width() const { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 281a33929c2..58287b7593d 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -293,6 +293,49 @@ public: AtlasTexture(); }; +class Mesh; + +class MeshTexture : public Texture { + + GDCLASS(MeshTexture, Texture); + RES_BASE_EXTENSION("meshtex"); + + Ref base_texture; + Ref mesh; + Size2i size; + +protected: + static void _bind_methods(); + +public: + virtual int get_width() const; + virtual int get_height() const; + virtual RID get_rid() const; + + virtual bool has_alpha() const; + + virtual void set_flags(uint32_t p_flags); + virtual uint32_t get_flags() const; + + void set_mesh(const Ref &p_mesh); + Ref get_mesh() const; + + void set_image_size(const Size2 &p_size); + Size2 get_image_size() const; + + void set_base_texture(const Ref &p_texture); + Ref get_base_texture() const; + + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref &p_normal_map = Ref()) const; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref &p_normal_map = Ref()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref &p_normal_map = Ref(), bool p_clip_uv = true) const; + virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const; + + bool is_pixel_opaque(int p_x, int p_y) const; + + MeshTexture(); +}; + class LargeTexture : public Texture { GDCLASS(LargeTexture, Texture); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 39530bbbeec..b22e26f903f 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -789,6 +789,8 @@ public: RID mesh; RID texture; RID normal_map; + Transform2D transform; + Color modulate; CommandMesh() { type = TYPE_MESH; } }; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 15f37dd6d19..95ba89f8a61 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -829,7 +829,7 @@ void VisualServerCanvas::canvas_item_add_set_transform(RID p_item, const Transfo canvas_item->commands.push_back(tr); } -void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture, RID p_normal_map) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -839,6 +839,8 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID m->mesh = p_mesh; m->texture = p_texture; m->normal_map = p_normal_map; + m->transform = p_transform; + m->modulate = p_modulate; canvas_item->commands.push_back(m); } diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 8162085ced1..7691d686397 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -197,7 +197,7 @@ public: void canvas_item_add_primitive(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()); void canvas_item_add_polygon(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false); void canvas_item_add_triangle_array(RID p_item, const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()); - void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); + void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()); void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal); void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 8ce25ba906e..9c7f474f442 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -600,7 +600,7 @@ public: BIND7(canvas_item_add_primitive, RID, const Vector &, const Vector &, const Vector &, RID, float, RID) BIND7(canvas_item_add_polygon, RID, const Vector &, const Vector &, const Vector &, RID, RID, bool) BIND10(canvas_item_add_triangle_array, RID, const Vector &, const Vector &, const Vector &, const Vector &, const Vector &, const Vector &, RID, int, RID) - BIND4(canvas_item_add_mesh, RID, const RID &, RID, RID) + BIND6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID) BIND4(canvas_item_add_multimesh, RID, RID, RID, RID) BIND4(canvas_item_add_particles, RID, RID, RID, RID) BIND2(canvas_item_add_set_transform, RID, const Transform2D &) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index efe251e9de4..9f23ad644e7 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -518,7 +518,7 @@ public: FUNC7(canvas_item_add_primitive, RID, const Vector &, const Vector &, const Vector &, RID, float, RID) FUNC7(canvas_item_add_polygon, RID, const Vector &, const Vector &, const Vector &, RID, RID, bool) FUNC10(canvas_item_add_triangle_array, RID, const Vector &, const Vector &, const Vector &, const Vector &, const Vector &, const Vector &, RID, int, RID) - FUNC4(canvas_item_add_mesh, RID, const RID &, RID, RID) + FUNC6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID) FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID) FUNC4(canvas_item_add_particles, RID, RID, RID, RID) FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) diff --git a/servers/visual_server.h b/servers/visual_server.h index 596b893b69b..c98c5b39a96 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -898,7 +898,7 @@ public: virtual void canvas_item_add_primitive(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()) = 0; virtual void canvas_item_add_polygon(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false) = 0; virtual void canvas_item_add_triangle_array(RID p_item, const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; + virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0; virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;