diff options
author | Juan Linietsky <reduzio@gmail.com> | 2018-08-23 22:10:15 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2018-08-23 22:11:10 -0300 |
commit | 34e58fd831172bad1eebb748c97238c28864423a (patch) | |
tree | 45c0a84ce5233a8ea98e2e7e34b5562ae51cfd92 | |
parent | cef310e0ea0f8e7f3621e9ba29a567f09fb51beb (diff) |
Added a function to cache texture opacity at a pixel, and modified editor to use it.
Provides massive speedups to selecting objects, still awaiting for @MarianoGNU to do fixes to the region editor to improve performance.
-rw-r--r-- | scene/2d/sprite.cpp | 38 | ||||
-rw-r--r-- | scene/2d/sprite.h | 2 | ||||
-rw-r--r-- | scene/resources/texture.cpp | 112 | ||||
-rw-r--r-- | scene/resources/texture.h | 15 |
4 files changed, 137 insertions, 30 deletions
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index ebe0e81f6e..bb5990fa79 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -298,6 +298,11 @@ int Sprite::get_hframes() const { bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + return is_pixel_opaque(p_point); +} + +bool Sprite::is_pixel_opaque(const Point2 &p_point) const { + if (texture.is_null()) return false; @@ -316,32 +321,6 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc q.y = 1.0f - q.y; q = q * src_rect.size + src_rect.position; - Ref<Image> image; - Ref<AtlasTexture> atlasTexture = texture; - if (atlasTexture.is_null()) { - image = texture->get_data(); - } else { - ERR_FAIL_COND_V(atlasTexture->get_atlas().is_null(), false); - - image = atlasTexture->get_atlas()->get_data(); - - Rect2 region = atlasTexture->get_region(); - Rect2 margin = atlasTexture->get_margin(); - - q -= margin.position; - - if ((q.x > region.size.width) || (q.y > region.size.height)) { - return false; - } - - q += region.position; - } - - ERR_FAIL_COND_V(image.is_null(), false); - if (image->is_compressed()) { - return dst_rect.has_point(p_point); - } - bool is_repeat = texture->get_flags() & Texture::FLAG_REPEAT; bool is_mirrored_repeat = texture->get_flags() & Texture::FLAG_MIRRORED_REPEAT; if (is_repeat) { @@ -363,11 +342,8 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc q.x = MIN(q.x, texture->get_size().width - 1); q.y = MIN(q.y, texture->get_size().height - 1); } - image->lock(); - const Color c = image->get_pixel((int)q.x, (int)q.y); - image->unlock(); - return c.a > 0.01; + return texture->is_pixel_opaque((int)q.x, (int)q.y); } Rect2 Sprite::get_rect() const { @@ -437,6 +413,8 @@ void Sprite::_bind_methods() { ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite::set_region); ClassDB::bind_method(D_METHOD("is_region"), &Sprite::is_region); + ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite::is_pixel_opaque); + ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect); ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect); diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index 0a5ff002cd..ab444f89fc 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -75,6 +75,8 @@ public: virtual bool _edit_use_pivot() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + bool is_pixel_opaque(const Point2 &p_point) const; + virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 41f3ee1fce..c763c9bc79 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "texture.h" +#include "bit_mask.h" #include "core/method_bind_ext.gen.inc" #include "core/os/os.h" #include "core_string_names.h" @@ -39,6 +40,9 @@ Size2 Texture::get_size() const { return Size2(get_width(), get_height()); } +bool Texture::is_pixel_opaque(int p_x, int p_y) const { + return true; +} void Texture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const { RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); @@ -234,6 +238,7 @@ void ImageTexture::set_data(const Ref<Image> &p_image) { VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); + alpha_cache.unref(); } void ImageTexture::_resource_path_changed() { @@ -288,6 +293,41 @@ void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, p_clip_uv); } +bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { + + if (!alpha_cache.is_valid()) { + Ref<Image> img = get_data(); + if (img.is_valid()) { + if (img->is_compressed()) { //must decompress, if compressed + Ref<Image> decom = img->duplicate(); + decom->decompress(); + img = decom; + } + alpha_cache.instance(); + alpha_cache->create_from_image_alpha(img); + } + } + + if (alpha_cache.is_valid()) { + + int aw = int(alpha_cache->get_size().width); + int ah = int(alpha_cache->get_size().height); + if (aw == 0 || ah == 0) { + return true; + } + + int x = p_x * aw / w; + int y = p_y * ah / h; + + x = CLAMP(x, 0, aw); + y = CLAMP(y, 0, aw); + + return alpha_cache->get_bit(Point2(x, y)); + } + + return true; +} + void ImageTexture::set_size_override(const Size2 &p_size) { Size2 s = p_size; @@ -421,6 +461,8 @@ Image::Format StreamTexture::get_format() const { Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit) { + alpha_cache.unref(); + ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER); FileAccess *f = FileAccess::open(p_path, FileAccess::READ); @@ -709,6 +751,40 @@ Ref<Image> StreamTexture::get_data() const { return VS::get_singleton()->texture_get_data(texture); } +bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { + + if (!alpha_cache.is_valid()) { + Ref<Image> img = get_data(); + if (img.is_valid()) { + if (img->is_compressed()) { //must decompress, if compressed + Ref<Image> decom = img->duplicate(); + decom->decompress(); + img = decom; + } + alpha_cache.instance(); + alpha_cache->create_from_image_alpha(img); + } + } + + if (alpha_cache.is_valid()) { + + int aw = int(alpha_cache->get_size().width); + int ah = int(alpha_cache->get_size().height); + if (aw == 0 || ah == 0) { + return true; + } + + int x = p_x * aw / w; + int y = p_y * ah / h; + + x = CLAMP(x, 0, aw); + y = CLAMP(y, 0, aw); + + return alpha_cache->get_bit(Point2(x, y)); + } + + return true; +} void StreamTexture::set_flags(uint32_t p_flags) { flags = p_flags; VS::get_singleton()->texture_set_flags(texture, flags); @@ -1007,6 +1083,15 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, return true; } +bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const { + + if (atlas.is_valid()) { + return atlas->is_pixel_opaque(p_x + region.position.x + margin.position.x, p_x + region.position.y + margin.position.y); + } + + return true; +} + AtlasTexture::AtlasTexture() { filter_clip = false; } @@ -1184,6 +1269,23 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons } } +bool LargeTexture::is_pixel_opaque(int p_x, int p_y) const { + + for (int i = 0; i < pieces.size(); i++) { + + // TODO + if (!pieces[i].texture.is_valid()) + continue; + + Rect2 rect(pieces[i].offset, pieces[i].texture->get_size()); + if (rect.has_point(Point2(p_x, p_y))) { + return pieces[i].texture->is_pixel_opaque(p_x - rect.position.x, p_y - rect.position.y); + } + } + + return true; +} + LargeTexture::LargeTexture() { } @@ -1803,6 +1905,16 @@ Ref<Image> AnimatedTexture::get_data() const { return frames[current_frame].texture->get_data(); } +bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const { + + RWLockRead r(rw_lock); + + if (frames[current_frame].texture.is_valid()) { + return frames[current_frame].texture->is_pixel_opaque(p_x, p_y); + } + return true; +} + void AnimatedTexture::set_flags(uint32_t p_flags) { } uint32_t AnimatedTexture::get_flags() const { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index b02cbb8fa8..79e6d2cdf9 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -68,6 +68,8 @@ public: virtual Size2 get_size() const; virtual RID get_rid() const = 0; + virtual bool is_pixel_opaque(int p_x, int p_y) const; + virtual bool has_alpha() const = 0; virtual void set_flags(uint32_t p_flags) = 0; @@ -85,6 +87,8 @@ public: VARIANT_ENUM_CAST(Texture::Flags); +class BitMap; + class ImageTexture : public Texture { GDCLASS(ImageTexture, Texture); @@ -105,6 +109,7 @@ private: Storage storage; Size2 size_override; float lossy_storage_quality; + mutable Ref<BitMap> alpha_cache; protected: virtual void reload_from_file(); @@ -144,6 +149,8 @@ public: void set_storage(Storage p_storage); Storage get_storage() const; + bool is_pixel_opaque(int p_x, int p_y) const; + void set_lossy_storage_quality(float p_lossy_storage_quality); float get_lossy_storage_quality() const; @@ -184,6 +191,7 @@ private: Image::Format format; uint32_t flags; int w, h; + mutable Ref<BitMap> alpha_cache; virtual void reload_from_file(); @@ -216,6 +224,7 @@ public: virtual bool has_alpha() const; virtual void set_flags(uint32_t p_flags); + bool is_pixel_opaque(int p_x, int p_y) const; virtual Ref<Image> get_data() const; @@ -273,6 +282,8 @@ public: 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; + AtlasTexture(); }; @@ -320,6 +331,8 @@ public: 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; + bool is_pixel_opaque(int p_x, int p_y) const; + LargeTexture(); }; @@ -670,6 +683,8 @@ public: virtual Ref<Image> get_data() const; + bool is_pixel_opaque(int p_x, int p_y) const; + AnimatedTexture(); ~AnimatedTexture(); }; |