Skip to content

Commit

Permalink
Add BitMap methods for bitwise boolean operations
Browse files Browse the repository at this point in the history
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 <[email protected]>
Co-Authored-By: A Thousand Ships <[email protected]>
  • Loading branch information
3 people committed Aug 5, 2024
1 parent 7abe0c6 commit 6757bae
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
30 changes: 30 additions & 0 deletions doc/classes/BitMap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,36 @@
<tutorials>
</tutorials>
<methods>
<method name="bitwise_and" qualifiers="const">
<return type="BitMap" />
<param index="0" name="other" type="BitMap" />
<description>
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.
</description>
</method>
<method name="bitwise_not" qualifiers="const">
<return type="BitMap" />
<description>
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].
</description>
</method>
<method name="bitwise_or" qualifiers="const">
<return type="BitMap" />
<param index="0" name="other" type="BitMap" />
<description>
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.
</description>
</method>
<method name="bitwise_xor" qualifiers="const">
<return type="BitMap" />
<param index="0" name="other" type="BitMap" />
<description>
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.
</description>
</method>
<method name="convert_to_image" qualifiers="const">
<return type="Image" />
<description>
Expand Down
124 changes: 124 additions & 0 deletions scene/resources/bit_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,125 @@ void BitMap::blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap) {
}
}

Ref<BitMap> BitMap::bitwise_and(const Ref<BitMap> &p_other) const {
ERR_FAIL_COND_V_EDMSG(p_other.is_null(), Ref<BitMap>(), "Null reference to supplied BitMap other.");

Ref<BitMap> 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> BitMap::bitwise_not() const {
Ref<BitMap> 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> BitMap::bitwise_or(const Ref<BitMap> &p_other) const {
ERR_FAIL_COND_V_EDMSG(p_other.is_null(), Ref<BitMap>(), "Null reference to supplied BitMap other.");

Ref<BitMap> 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> BitMap::bitwise_xor(const Ref<BitMap> &p_other) const {
ERR_FAIL_COND_V_EDMSG(p_other.is_null(), Ref<BitMap>(), "Null reference to supplied BitMap other.");

Ref<BitMap> 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));
Expand All @@ -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");
}

Expand Down
5 changes: 5 additions & 0 deletions scene/resources/bit_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ class BitMap : public Resource {

Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon = 2.0) const;

Ref<BitMap> bitwise_and(const Ref<BitMap> &p_other) const;
Ref<BitMap> bitwise_not() const;
Ref<BitMap> bitwise_or(const Ref<BitMap> &p_other) const;
Ref<BitMap> bitwise_xor(const Ref<BitMap> &p_other) const;

BitMap();
};

Expand Down

0 comments on commit 6757bae

Please sign in to comment.