From 425906e40d35c503c9de9a36cbf249b3d9577c52 Mon Sep 17 00:00:00 2001 From: Ethan Curtis Date: Tue, 23 Apr 2024 17:30:19 -0400 Subject: [PATCH] Add BitMap methods for bitwise boolean operations Created methods for BitMap for boolean operators AND, OR, XOR, and NOT. Binary operations only work when two BitMaps are the same size. Docs included. Co-Authored-By: Micky <66727710+Mickeon@users.noreply.github.com> Co-Authored-By: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> --- doc/classes/BitMap.xml | 30 ++++++++++++ scene/resources/bit_map.cpp | 93 +++++++++++++++++++++++++++++++++++++ scene/resources/bit_map.h | 5 ++ 3 files changed, 128 insertions(+) diff --git a/doc/classes/BitMap.xml b/doc/classes/BitMap.xml index fa454a1b0ded..5e41dfdf80b7 100644 --- a/doc/classes/BitMap.xml +++ b/doc/classes/BitMap.xml @@ -9,6 +9,36 @@ + + + + + Creates a new [BitMap] from the boolean AND operation between this bitmap and [param other]. + This method fails and returns an empty [BitMap] if the two bitmaps are not exactly the same size. + + + + + + Creates a new [BitMap] from the boolean NOT operation on this bitmap. This causes every bit to flip from [code]true[/code] to [code]false[/code], and from [code]false[/code] to [code]true[/code]. + + + + + + + Creates a new [BitMap] from the boolean OR operation between this bitmap and [param other]. + This method fails and returns an empty [BitMap] if the two bitmaps are not exactly the same size. + + + + + + + Creates a new [BitMap] from the boolean XOR operation between this bitmap and [param other]. + This method fails and returns an empty [BitMap] if the two bitmaps are not exactly the same size. + + diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 653a4f4949de..fb96b23343fc 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -704,6 +704,94 @@ void BitMap::blit(const Vector2i &p_pos, const Ref &p_bitmap) { } } +Ref BitMap::bitwise_and(const Ref &p_other) const { + ERR_FAIL_COND_V_EDMSG(p_other.is_null(), Ref(), "Null reference to supplied BitMap other."); + + Ref new_bitmap; + new_bitmap.instantiate(); + + ERR_FAIL_COND_V_EDMSG(get_size() != p_other->get_size(), new_bitmap, "The given bitmap is not the expected size for the specified operation."); + + new_bitmap->create(get_size()); + + int ds = bitmask.size(); + const uint8_t *d = bitmask.ptr(); + const uint8_t *d2 = p_other->bitmask.ptr(); + uint8_t *w = new_bitmap->bitmask.ptrw(); + + for (int i = 0; i < ds; i++) { + w[i] = d[i] & d2[i]; + } + + return new_bitmap; +} + +Ref BitMap::bitwise_not() const { + Ref new_bitmap; + new_bitmap.instantiate(); + new_bitmap->create(get_size()); + + int ds = bitmask.size(); + const uint8_t *d = bitmask.ptr(); + uint8_t *w = new_bitmap->bitmask.ptrw(); + + for (int i = 0; i < ds; i++) { + w[i] = ~d[i]; + } + + // mask "hidden" bits for true bit count + int hidden_count = (ds << 3) - (width * height); + if (hidden_count > 0) { + w[ds - 1] &= 0xFF << hidden_count; + } + + return new_bitmap; +} + +Ref BitMap::bitwise_or(const Ref &p_other) const { + ERR_FAIL_COND_V_EDMSG(p_other.is_null(), Ref(), "Null reference to supplied BitMap other."); + + Ref new_bitmap; + new_bitmap.instantiate(); + + ERR_FAIL_COND_V_EDMSG(get_size() != p_other->get_size(), new_bitmap, "The given bitmap is not the expected size for the specified operation."); + + new_bitmap->create(get_size()); + + int ds = bitmask.size(); + const uint8_t *d = bitmask.ptr(); + const uint8_t *d2 = p_other->bitmask.ptr(); + uint8_t *w = new_bitmap->bitmask.ptrw(); + + for (int i = 0; i < ds; i++) { + w[i] = d[i] | d2[i]; + } + + return new_bitmap; +} + +Ref BitMap::bitwise_xor(const Ref &p_other) const { + ERR_FAIL_COND_V_EDMSG(p_other.is_null(), Ref(), "Null reference to supplied BitMap other."); + + Ref new_bitmap; + new_bitmap.instantiate(); + + ERR_FAIL_COND_V_EDMSG(get_size() != p_other->get_size(), new_bitmap, "The given bitmap is not the expected size for the specified operation."); + + new_bitmap->create(get_size()); + + int ds = bitmask.size(); + const uint8_t *d = bitmask.ptr(); + const uint8_t *d2 = p_other->bitmask.ptr(); + uint8_t *w = new_bitmap->bitmask.ptrw(); + + for (int i = 0; i < ds; i++) { + w[i] = d[i] ^ d2[i]; + } + + return new_bitmap; +} + void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1)); @@ -726,6 +814,11 @@ void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_to_image"), &BitMap::convert_to_image); ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0)); + ClassDB::bind_method(D_METHOD("bitwise_and", "other"), &BitMap::bitwise_and); + ClassDB::bind_method(D_METHOD("bitwise_not"), &BitMap::bitwise_not); + ClassDB::bind_method(D_METHOD("bitwise_or", "other"), &BitMap::bitwise_or); + ClassDB::bind_method(D_METHOD("bitwise_xor", "other"), &BitMap::bitwise_xor); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index 8912e3992e24..0b46b8a790d7 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -79,6 +79,11 @@ class BitMap : public Resource { Vector> clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon = 2.0) const; + Ref bitwise_and(const Ref &p_other) const; + Ref bitwise_not() const; + Ref bitwise_or(const Ref &p_other) const; + Ref bitwise_xor(const Ref &p_other) const; + BitMap(); };