Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/melonjs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- UI: `UITextButton#bitmapText`, for `label`

### Fixed
- Math: `isPowerOfTwo()` rejects zero, negative and fractional values instead of accepting them after 32-bit coercion, and handles powers and non-powers beyond the 32-bit range (thanks @mmporong)
- Input: a child cropped out of view by a container with `clipping`, or scrolled out of a `UIPanel`, no longer gets pointer events where it is not drawn
- UI: a `UITextButton` moved after it was built draws its background where it is, not where it was first put
- UI: a blocking `UIPanel` stays opaque to hover for as long as the pointer is on it, not only on the frame the pointer enters
Expand Down
6 changes: 5 additions & 1 deletion packages/melonjs/src/math/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export const EPSILON = 0.000001;
* @returns true if number is a power of two
*/
export function isPowerOfTwo(val: number) {
return (val & (val - 1)) === 0;
if (!Number.isInteger(val) || val <= 0) {
return false;
}
const exponent = Math.log2(val);
return Number.isInteger(exponent) && val === 2 ** exponent;
}

/**
Expand Down
21 changes: 21 additions & 0 deletions packages/melonjs/tests/math.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,27 @@ describe("Math", () => {
it("32 is a Power of 2", () => {
expect(math.isPowerOfTwo(32)).toEqual(true);
});
it("0 and negative values are not Powers of 2", () => {
expect(math.isPowerOfTwo(0)).toEqual(false);
expect(math.isPowerOfTwo(-2)).toEqual(false);
});
it("fractional values are not Powers of 2", () => {
expect(math.isPowerOfTwo(2.5)).toEqual(false);
});
it("supports Powers of 2 outside the 32-bit range", () => {
expect(math.isPowerOfTwo(2 ** 40)).toEqual(true);
expect(math.isPowerOfTwo(3 * 2 ** 32)).toEqual(false);
});
it("rejects large non-Powers whose logarithms round to integers", () => {
for (const value of [
Number.MAX_SAFE_INTEGER,
2 ** 53 + 2,
2 ** 53 + 4,
2 ** 54 - 2,
]) {
expect(math.isPowerOfTwo(value)).toEqual(false);
}
});
it("1027 is not a Power of 2", () => {
expect(math.isPowerOfTwo(1027)).toEqual(false);
});
Expand Down