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..d79c1a3ccc3c 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -704,6 +704,125 @@ 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(); + + const uint64_t *d_u64 = (uint64_t*) d; + const uint64_t *d2_u64 = (uint64_t*) d2; + uint64_t *w_u64 = (uint64_t*) w; + + for (int i = 0; i < (ds >> 3); i++) { + w_u64[i] = d_u64[i] & d2_u64[i]; + } + + for (int i = ds & ~0b111; 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(); + + const uint64_t *d_u64 = (uint64_t*) d; + uint64_t *w_u64 = (uint64_t*) w; + + for (int i = 0; i < (ds >> 3); i++) { + w_u64[i] = ~d_u64[i]; + } + + for (int i = ds & ~0b111; 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(); + + const uint64_t *d_u64 = (uint64_t*) d; + const uint64_t *d2_u64 = (uint64_t*) d2; + uint64_t *w_u64 = (uint64_t*) w; + + for (int i = 0; i < (ds >> 3); i++) { + w_u64[i] = d_u64[i] | d2_u64[i]; + } + + for (int i = ds & ~0b111; 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(); + + const uint64_t *d_u64 = (uint64_t*) d; + const uint64_t *d2_u64 = (uint64_t*) d2; + uint64_t *w_u64 = (uint64_t*) w; + + for (int i = 0; i < (ds >> 3); i++) { + w_u64[i] = d_u64[i] ^ d2_u64[i]; + } + + for (int i = ds & ~0b111; 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 +845,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(); };