diff options
35 files changed, 1818 insertions, 33 deletions
diff --git a/core/image.cpp b/core/image.cpp index 90afd9f35a..99d5eab864 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<uint8_t>::Read r = data.read(); - const unsigned char *rptr = r.ptr(); - - int ps = format == FORMAT_LA8 ? 2 : 4; + const_cast<Image *>(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<Image *>(this)->unlock(); + if (maxx == -1) return Rect2(); else diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index b5fa412576..038a34ed51 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 1c146c33d7..bdbdde6df6 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<String> *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<ImportOption> *r_options, int p_preset = 0) const = 0; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &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<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL) = 0; + + virtual Error import_group_file(const String& p_group_file,const Map<String,Map<StringName, Variant> >&p_source_file_options, const Map<String,String>& 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 e4b694b64f..56d3b8b133 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 ca7610a0d2..9e7020be7c 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<String> *p_dependencies, bool p_add_types = false); static Error rename_dependencies(const String &p_path, const Map<String, String> &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 7d00158f3d..1d0387bd45 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 b9e7a36fb3..c44678674a 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 ae2d1ec660..9a214ef9b5 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 e8a6178052..3730af1ad4 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 f3fcc922c7..9105dbbd58 100644 --- a/core/reference.h +++ b/core/reference.h @@ -197,6 +197,19 @@ public: r.reference = NULL; } + template <class T_Other> + void reference_ptr(T_Other *p_ptr) { + if (reference == p_ptr) { + return; + } + unref(); + + T *r = Object::cast_to<T>(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 b0f1be47a1..30aa22732c 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 0000000000..4e1d98399a --- /dev/null +++ b/editor/editor_atlas_packer.cpp @@ -0,0 +1,265 @@ +#include "editor_atlas_packer.h" + +void EditorAtlasPacker::_plot_triangle(Ref<BitMap> 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<Chart> &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<PlottedBitmap> 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<BitMap> 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<int> top_heights; + Vector<int> 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<int> 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 0000000000..dd9caa340e --- /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<Vector2> vertices; + struct Face { + int vertex[3]; + }; + Vector<Face> faces; + bool can_transpose; + + Vector2 final_offset; + bool transposed; + }; + +private: + struct PlottedBitmap { + int chart_index; + Vector2i offset; + int area; + Vector<int> top_heights; + Vector<int> bottom_heights; + bool transposed; + + Vector2 final_pos; + + bool operator<(const PlottedBitmap &p_bm) const { + return area > p_bm.area; + } + }; + + static void _plot_triangle(Ref<BitMap> p_bitmap, Vector2i *vertices); + +public: + static void chart_pack(Vector<Chart> &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 3d9d5e26be..abd3bea951 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<String> 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<String> 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<String> &p_files) { + + String importer_name; + + Map<String, Map<StringName, Variant> > source_file_options; + Map<String, String> base_paths; + for (int i = 0; i < p_files.size(); i++) { + + Ref<ConfigFile> 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<StringName, Variant>(); + importer_name = file_importer_name; + + Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); + ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_CORRUPT); + List<ResourceImporter::ImportOption> options; + importer->get_import_options(&options); + //set default values + for (List<ResourceImporter::ImportOption>::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<String> sk; + config->get_section_keys("params", &sk); + for (List<String>::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<ResourceImporter> 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<String, Map<StringName, Variant> >::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<String> 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<ResourceImporter::ImportOption> options; + importer->get_import_options(&options); + //set default values + for (List<ResourceImporter::ImportOption>::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<String, Vector<String> > &group_files, Set<String> &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<String>(); + } + 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<String> &p_files) { { //check that .import folder exists @@ -1757,22 +1949,58 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); Vector<ImportFile> files; + Set<String> 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<String, Vector<String> > group_files; + _find_group_files(filesystem, group_files, groups_to_reimport); + for (Map<String, Vector<String> >::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<ConfigFile> 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<String> sk; + config->get_section_keys("params", &sk); + for (List<String>::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 2a9e325454..8943706202 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<String> 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<String> 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<String> &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<String, Vector<String> > &group_files, Set<String> &groups_to_reimport); + + void _move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location); + + Set<String> 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 851d6a0aa6..b729de2e2f 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<ResourceImporterTextureAtlas> import_texture_atlas; + import_texture_atlas.instance(); + ResourceFormatImporter::get_singleton()->add_importer(import_texture_atlas); + Ref<ResourceImporterCSVTranslation> 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 31f53305e2..9d936d9b99 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<String> 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 c32cd1de50..aade606412 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<String, String> file_renames; Map<String, String> 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 0000000000..52db6b76a6 --- /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 0000000000..35fdd32e2c --- /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<String> *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<StringName, Variant> &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<ImportOption> *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<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *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<Image> broken = memnew(Image((const char **)atlas_import_failed_xpm)); + Ref<ImageTexture> 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<Image> p_image, const Ref<Image> &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<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths) { + + ERR_FAIL_COND_V(p_source_file_options.size() == 0, ERR_BUG); //should never happen + + Vector<EditorAtlasPacker::Chart> charts; + Vector<PackData> pack_data_files; + + pack_data_files.resize(p_source_file_options.size()); + + int idx = 0; + for (const Map<String, Map<StringName, Variant> >::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<StringName, Variant> &options = E->get(); + + Ref<Image> 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<BitMap> bit_map; + bit_map.instance(); + bit_map->create_from_image_alpha(image); + Vector<Vector<Vector2> > 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<int> 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<Image> 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<Texture> cache; + if (ResourceCache::has(p_group_file)) { + Resource *resptr = ResourceCache::get(p_group_file); + cache.reference_ptr(resptr); + } else { + Ref<ImageTexture> 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<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) { + + PackData &pack_data = pack_data_files.write[idx]; + + Ref<Texture> 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<AtlasTexture> 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<ArrayMesh> 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<Vector2> vertices; + PoolVector<int> indices; + PoolVector<Vector2> uvs; + int vc = chart.vertices.size(); + int fc = chart.faces.size(); + vertices.resize(vc); + uvs.resize(vc); + indices.resize(fc * 3); + + { + PoolVector<Vector2>::Write vw = vertices.write(); + PoolVector<int>::Write iw = indices.write(); + PoolVector<Vector2>::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<MeshTexture> 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 0000000000..62be570dc6 --- /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<int> chart_pieces; //one for region, many for mesh + Vector<Vector<Vector2> > chart_vertices; //for mesh + Ref<Image> 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<String> *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<ImportOption> *r_options, int p_preset = 0) const; + virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &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<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL); + virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths); + + ResourceImporterTextureAtlas(); +}; + +#endif // RESOURCE_IMPORTER_TEXTURE_ATLAS_H diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 15539ee3db..b307ec649a 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<PropertyInfo>::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<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) { @@ -455,6 +457,19 @@ void ImportDock::_reimport() { } } + //handle group file + Ref<ResourceImporter> 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 2739f71543..78e98deb93 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -891,13 +891,13 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &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<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) { +void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &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<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &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<Texture>())); + ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture>())); 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 bf7cfa8e75..a020ab5029 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -317,7 +317,7 @@ public: void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false); void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false); - void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map); + void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1)); void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map); void draw_string(const Ref<Font> &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 3148df15dd..9face3e476 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -635,6 +635,7 @@ void register_scene_types() { ClassDB::register_class<StreamTexture>(); ClassDB::register_class<ImageTexture>(); ClassDB::register_class<AtlasTexture>(); + ClassDB::register_class<MeshTexture>(); ClassDB::register_class<LargeTexture>(); ClassDB::register_class<CurveTexture>(); ClassDB::register_class<GradientTexture>(); diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 55264bcdf9..a9d85be0dc 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<BitMap> 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;x<lw;x++) { + for(int y=0;y<lh;y++) { + new_bitmap->set_bit(Vector2(x,y),get_bit(Vector2(x,y))); + } + } + + width = new_bitmap->width; + height = new_bitmap->height; + bitmask = new_bitmap->bitmask; +} + +Ref<Image> BitMap::convert_to_image() const { + + Ref<Image> image; + image.instance(); + image->create(width,height,false,Image::FORMAT_L8); + image->lock(); + for(int i=0;i<width;i++) { + for(int j=0;j<height;j++) { + image->set_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<BitMap>& 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<w;i++) { + for (int j=0;j<h;j++) { + int px = x+i; + int py = y+j; + if (px<0 || px>=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 b3c86afd38..6e1171b8a9 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<BitMap>& p_bitmap); + Ref<Image> convert_to_image() const; + Vector<Vector<Vector2> > 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 3ca2b56d08..a5eb950c36 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<Mesh> &p_mesh) { + mesh = p_mesh; +} +Ref<Mesh> 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<Texture> &p_texture) { + base_texture = p_texture; +} + +Ref<Texture> 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<Texture> &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<Texture> &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<Texture> &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 281a33929c..58287b7593 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<Texture> base_texture; + Ref<Mesh> 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<Mesh> &p_mesh); + Ref<Mesh> get_mesh() const; + + void set_image_size(const Size2 &p_size); + Size2 get_image_size() const; + + void set_base_texture(const Ref<Texture> &p_texture); + Ref<Texture> 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<Texture> &p_normal_map = Ref<Texture>()) 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<Texture> &p_normal_map = Ref<Texture>()) 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<Texture> &p_normal_map = Ref<Texture>(), 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 39530bbbee..b22e26f903 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 59c7609398..791d59038a 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -830,7 +830,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); @@ -840,6 +840,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 8162085ced..7691d68639 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<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &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<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false); void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), 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 8ce25ba906..9c7f474f44 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<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) BIND7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool) BIND10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, 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 efe251e9de..9f23ad644e 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<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) FUNC7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool) FUNC10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, 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 596b893b69..c98c5b39a9 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<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &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<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), 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<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), 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; |