@vpmedia/phaser 1.113.0 → 1.115.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +402 -379
- package/dist/index.js.map +1 -1
- package/dist/phaser/core/animation_manager.d.ts +2 -1
- package/dist/phaser/core/animation_manager.d.ts.map +1 -1
- package/dist/phaser/core/array_set.d.ts +1 -1
- package/dist/phaser/core/array_set.d.ts.map +1 -1
- package/dist/phaser/core/cache.d.ts +1 -1
- package/dist/phaser/core/cache.d.ts.map +1 -1
- package/dist/phaser/core/factory.d.ts +1 -1
- package/dist/phaser/core/factory.d.ts.map +1 -1
- package/dist/phaser/core/game.d.ts +2 -0
- package/dist/phaser/core/game.d.ts.map +1 -1
- package/dist/phaser/core/input.d.ts +5 -5
- package/dist/phaser/core/input.d.ts.map +1 -1
- package/dist/phaser/core/input_event.d.ts +35 -0
- package/dist/phaser/core/input_event.d.ts.map +1 -0
- package/dist/phaser/core/input_handler.d.ts +2 -2
- package/dist/phaser/core/input_handler.d.ts.map +1 -1
- package/dist/phaser/core/input_mouse.d.ts +27 -26
- package/dist/phaser/core/input_mouse.d.ts.map +1 -1
- package/dist/phaser/core/input_mspointer.d.ts +16 -15
- package/dist/phaser/core/input_mspointer.d.ts.map +1 -1
- package/dist/phaser/core/input_pointer.d.ts +9 -8
- package/dist/phaser/core/input_pointer.d.ts.map +1 -1
- package/dist/phaser/core/input_touch.d.ts +18 -17
- package/dist/phaser/core/input_touch.d.ts.map +1 -1
- package/dist/phaser/core/loader.d.ts +64 -30
- package/dist/phaser/core/loader.d.ts.map +1 -1
- package/dist/phaser/core/scale_manager.d.ts +1 -1
- package/dist/phaser/core/scale_manager.d.ts.map +1 -1
- package/dist/phaser/core/scene_manager.d.ts +14 -4
- package/dist/phaser/core/scene_manager.d.ts.map +1 -1
- package/dist/phaser/core/signal.d.ts +8 -8
- package/dist/phaser/core/signal.d.ts.map +1 -1
- package/dist/phaser/core/signal_binding.d.ts +2 -2
- package/dist/phaser/core/signal_binding.d.ts.map +1 -1
- package/dist/phaser/core/sound.d.ts +1 -1
- package/dist/phaser/core/sound.d.ts.map +1 -1
- package/dist/phaser/core/sound_manager.d.ts +3 -3
- package/dist/phaser/core/sound_manager.d.ts.map +1 -1
- package/dist/phaser/core/sound_sprite.d.ts +1 -1
- package/dist/phaser/core/sound_sprite.d.ts.map +1 -1
- package/dist/phaser/core/timer.d.ts +5 -5
- package/dist/phaser/core/timer.d.ts.map +1 -1
- package/dist/phaser/core/timer_event.d.ts +2 -2
- package/dist/phaser/core/timer_event.d.ts.map +1 -1
- package/dist/phaser/core/tween.d.ts +4 -4
- package/dist/phaser/core/tween.d.ts.map +1 -1
- package/dist/phaser/core/tween_data.d.ts +2 -1
- package/dist/phaser/core/tween_data.d.ts.map +1 -1
- package/dist/phaser/core/tween_manager.d.ts +1 -1
- package/dist/phaser/core/tween_manager.d.ts.map +1 -1
- package/dist/phaser/display/button.d.ts +1 -1
- package/dist/phaser/display/button.d.ts.map +1 -1
- package/dist/phaser/display/canvas/buffer.d.ts +3 -3
- package/dist/phaser/display/canvas/buffer.d.ts.map +1 -1
- package/dist/phaser/display/canvas/graphics.d.ts +2 -2
- package/dist/phaser/display/canvas/graphics.d.ts.map +1 -1
- package/dist/phaser/display/canvas/masker.d.ts +5 -2
- package/dist/phaser/display/canvas/masker.d.ts.map +1 -1
- package/dist/phaser/display/canvas/renderer.d.ts +6 -5
- package/dist/phaser/display/canvas/renderer.d.ts.map +1 -1
- package/dist/phaser/display/canvas/tinter.d.ts +2 -1
- package/dist/phaser/display/canvas/tinter.d.ts.map +1 -1
- package/dist/phaser/display/canvas/util.d.ts +11 -4
- package/dist/phaser/display/canvas/util.d.ts.map +1 -1
- package/dist/phaser/display/display_object.d.ts +4 -3
- package/dist/phaser/display/display_object.d.ts.map +1 -1
- package/dist/phaser/display/graphics.d.ts +47 -27
- package/dist/phaser/display/graphics.d.ts.map +1 -1
- package/dist/phaser/display/graphics_data.d.ts +20 -11
- package/dist/phaser/display/graphics_data.d.ts.map +1 -1
- package/dist/phaser/display/image.d.ts +4 -3
- package/dist/phaser/display/image.d.ts.map +1 -1
- package/dist/phaser/display/render_session.d.ts +44 -0
- package/dist/phaser/display/render_session.d.ts.map +1 -0
- package/dist/phaser/display/sprite_util.d.ts +4 -3
- package/dist/phaser/display/sprite_util.d.ts.map +1 -1
- package/dist/phaser/display/text.d.ts +65 -31
- package/dist/phaser/display/text.d.ts.map +1 -1
- package/dist/phaser/display/webgl/base_texture.d.ts +3 -3
- package/dist/phaser/display/webgl/base_texture.d.ts.map +1 -1
- package/dist/phaser/display/webgl/earcut.d.ts +25 -25
- package/dist/phaser/display/webgl/earcut.d.ts.map +1 -1
- package/dist/phaser/display/webgl/earcut_node.d.ts +2 -2
- package/dist/phaser/display/webgl/earcut_node.d.ts.map +1 -1
- package/dist/phaser/display/webgl/fast_sprite_batch.d.ts +3 -2
- package/dist/phaser/display/webgl/fast_sprite_batch.d.ts.map +1 -1
- package/dist/phaser/display/webgl/filter_manager.d.ts +1 -1
- package/dist/phaser/display/webgl/filter_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/graphics.d.ts +2 -1
- package/dist/phaser/display/webgl/graphics.d.ts.map +1 -1
- package/dist/phaser/display/webgl/graphics_data.d.ts +9 -9
- package/dist/phaser/display/webgl/graphics_data.d.ts.map +1 -1
- package/dist/phaser/display/webgl/mask_manager.d.ts +3 -2
- package/dist/phaser/display/webgl/mask_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/render_texture.d.ts +3 -3
- package/dist/phaser/display/webgl/render_texture.d.ts.map +1 -1
- package/dist/phaser/display/webgl/renderer.d.ts +5 -4
- package/dist/phaser/display/webgl/renderer.d.ts.map +1 -1
- package/dist/phaser/display/webgl/shader/normal.d.ts +3 -1
- package/dist/phaser/display/webgl/shader/normal.d.ts.map +1 -1
- package/dist/phaser/display/webgl/shader_manager.d.ts +10 -4
- package/dist/phaser/display/webgl/shader_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/sprite_batch.d.ts +4 -3
- package/dist/phaser/display/webgl/sprite_batch.d.ts.map +1 -1
- package/dist/phaser/display/webgl/stencil_manager.d.ts +4 -3
- package/dist/phaser/display/webgl/stencil_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/texture.d.ts +6 -6
- package/dist/phaser/display/webgl/texture.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/phaser/core/animation_manager.ts +2 -2
- package/src/phaser/core/array_set.ts +1 -1
- package/src/phaser/core/cache.ts +1 -1
- package/src/phaser/core/factory.ts +1 -1
- package/src/phaser/core/game.ts +2 -0
- package/src/phaser/core/input.ts +7 -6
- package/src/phaser/core/input_event.ts +34 -0
- package/src/phaser/core/input_handler.ts +2 -11
- package/src/phaser/core/input_mouse.ts +53 -36
- package/src/phaser/core/input_mspointer.ts +54 -29
- package/src/phaser/core/input_pointer.test.ts +149 -0
- package/src/phaser/core/input_pointer.ts +20 -21
- package/src/phaser/core/input_touch.ts +48 -31
- package/src/phaser/core/loader.test.ts +139 -0
- package/src/phaser/core/loader.ts +146 -83
- package/src/phaser/core/scale_manager.ts +1 -1
- package/src/phaser/core/scene_manager.ts +16 -8
- package/src/phaser/core/signal.ts +8 -8
- package/src/phaser/core/signal_binding.ts +2 -2
- package/src/phaser/core/sound.ts +4 -4
- package/src/phaser/core/sound_manager.ts +17 -19
- package/src/phaser/core/sound_sprite.ts +2 -2
- package/src/phaser/core/timer.ts +6 -6
- package/src/phaser/core/timer_event.ts +2 -2
- package/src/phaser/core/tween.ts +6 -6
- package/src/phaser/core/tween_data.ts +2 -1
- package/src/phaser/core/tween_manager.ts +1 -1
- package/src/phaser/display/button.ts +1 -1
- package/src/phaser/display/canvas/buffer.ts +3 -3
- package/src/phaser/display/canvas/graphics.ts +24 -20
- package/src/phaser/display/canvas/masker.ts +5 -2
- package/src/phaser/display/canvas/renderer.ts +10 -11
- package/src/phaser/display/canvas/tinter.ts +4 -3
- package/src/phaser/display/canvas/util.ts +15 -5
- package/src/phaser/display/display_object.ts +6 -5
- package/src/phaser/display/graphics.test.ts +122 -0
- package/src/phaser/display/graphics.ts +73 -64
- package/src/phaser/display/graphics_data.ts +22 -12
- package/src/phaser/display/image.ts +4 -3
- package/src/phaser/display/render_session.ts +45 -0
- package/src/phaser/display/sprite_util.ts +10 -8
- package/src/phaser/display/text.test.ts +136 -0
- package/src/phaser/display/text.ts +183 -119
- package/src/phaser/display/webgl/base_texture.ts +3 -3
- package/src/phaser/display/webgl/earcut.test.ts +132 -0
- package/src/phaser/display/webgl/earcut.ts +84 -74
- package/src/phaser/display/webgl/earcut_node.ts +5 -5
- package/src/phaser/display/webgl/fast_sprite_batch.ts +4 -4
- package/src/phaser/display/webgl/filter_manager.ts +1 -1
- package/src/phaser/display/webgl/graphics.ts +26 -17
- package/src/phaser/display/webgl/graphics_data.ts +9 -9
- package/src/phaser/display/webgl/mask_manager.ts +3 -2
- package/src/phaser/display/webgl/render_texture.ts +3 -3
- package/src/phaser/display/webgl/renderer.ts +7 -6
- package/src/phaser/display/webgl/shader/normal.ts +23 -6
- package/src/phaser/display/webgl/shader_manager.ts +15 -6
- package/src/phaser/display/webgl/sprite_batch.ts +4 -3
- package/src/phaser/display/webgl/stencil_manager.ts +10 -3
- package/src/phaser/display/webgl/texture.ts +6 -6
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { triangulate } from './earcut.js';
|
|
3
|
+
|
|
4
|
+
/** Signed area of the polygon a triangulation covers, used to check it tiles the input. */
|
|
5
|
+
const triangleArea = (data: number[], a: number, b: number, c: number): number => {
|
|
6
|
+
const ax = data[a * 2]!;
|
|
7
|
+
const ay = data[a * 2 + 1]!;
|
|
8
|
+
const bx = data[b * 2]!;
|
|
9
|
+
const by = data[b * 2 + 1]!;
|
|
10
|
+
const cx = data[c * 2]!;
|
|
11
|
+
const cy = data[c * 2 + 1]!;
|
|
12
|
+
return Math.abs((ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) / 2);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const coveredArea = (data: number[], triangles: number[]): number => {
|
|
16
|
+
let total = 0;
|
|
17
|
+
for (let i = 0; i < triangles.length; i += 3) {
|
|
18
|
+
total += triangleArea(data, triangles[i]!, triangles[i + 1]!, triangles[i + 2]!);
|
|
19
|
+
}
|
|
20
|
+
return total;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const SQUARE = [0, 0, 10, 0, 10, 10, 0, 10];
|
|
24
|
+
const TRIANGLE = [0, 0, 10, 0, 0, 10];
|
|
25
|
+
const L_SHAPE = [0, 0, 20, 0, 20, 10, 10, 10, 10, 20, 0, 20];
|
|
26
|
+
const CONCAVE = [0, 0, 20, 0, 20, 20, 10, 10, 0, 20];
|
|
27
|
+
const SQUARE_WITH_HOLE = [
|
|
28
|
+
// outer ring
|
|
29
|
+
0, 0, 30, 0, 30, 30, 0, 30,
|
|
30
|
+
// hole
|
|
31
|
+
10, 10, 20, 10, 20, 20, 10, 20,
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
describe('earcut triangulate', () => {
|
|
35
|
+
describe('simple polygons', () => {
|
|
36
|
+
it('cuts a square into two triangles', () => {
|
|
37
|
+
const triangles = triangulate(SQUARE, null, 2);
|
|
38
|
+
expect(triangles).toHaveLength(6);
|
|
39
|
+
expect(coveredArea(SQUARE, triangles)).toBeCloseTo(100, 6);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('leaves a triangle as one triangle', () => {
|
|
43
|
+
const triangles = triangulate(TRIANGLE, null, 2);
|
|
44
|
+
expect(triangles).toHaveLength(3);
|
|
45
|
+
expect(coveredArea(TRIANGLE, triangles)).toBeCloseTo(50, 6);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('covers an L shape exactly', () => {
|
|
49
|
+
const triangles = triangulate(L_SHAPE, null, 2);
|
|
50
|
+
expect(triangles).toHaveLength(12);
|
|
51
|
+
expect(coveredArea(L_SHAPE, triangles)).toBeCloseTo(300, 6);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('covers a concave polygon exactly', () => {
|
|
55
|
+
const triangles = triangulate(CONCAVE, null, 2);
|
|
56
|
+
expect(coveredArea(CONCAVE, triangles)).toBeCloseTo(300, 6);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('emits indices in range and in whole triangles', () => {
|
|
60
|
+
const triangles = triangulate(L_SHAPE, null, 2);
|
|
61
|
+
expect(triangles.length % 3).toBe(0);
|
|
62
|
+
for (const index of triangles) {
|
|
63
|
+
expect(index).toBeGreaterThanOrEqual(0);
|
|
64
|
+
expect(index).toBeLessThan(L_SHAPE.length / 2);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('polygons with holes', () => {
|
|
70
|
+
it('covers the outer ring minus the hole', () => {
|
|
71
|
+
const triangles = triangulate(SQUARE_WITH_HOLE, [4], 2);
|
|
72
|
+
expect(coveredArea(SQUARE_WITH_HOLE, triangles)).toBeCloseTo(900 - 100, 6);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('emits whole triangles', () => {
|
|
76
|
+
const triangles = triangulate(SQUARE_WITH_HOLE, [4], 2);
|
|
77
|
+
expect(triangles.length % 3).toBe(0);
|
|
78
|
+
expect(triangles.length).toBeGreaterThan(0);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('winding order', () => {
|
|
83
|
+
it('gives the same coverage whichever way the ring is wound', () => {
|
|
84
|
+
const clockwise = [0, 0, 0, 10, 10, 10, 10, 0];
|
|
85
|
+
const counter = [0, 0, 10, 0, 10, 10, 0, 10];
|
|
86
|
+
expect(coveredArea(clockwise, triangulate(clockwise, null, 2))).toBeCloseTo(
|
|
87
|
+
coveredArea(counter, triangulate(counter, null, 2)),
|
|
88
|
+
6
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('degenerate input', () => {
|
|
94
|
+
it('returns nothing for an empty ring', () => {
|
|
95
|
+
expect(triangulate([], null, 2)).toStrictEqual([]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('returns nothing for a single point', () => {
|
|
99
|
+
expect(triangulate([1, 1], null, 2)).toStrictEqual([]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns nothing for a two point ring', () => {
|
|
103
|
+
expect(triangulate([0, 0, 10, 10], null, 2)).toStrictEqual([]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('returns nothing for a zero area ring', () => {
|
|
107
|
+
expect(triangulate([0, 0, 10, 10, 20, 20], null, 2)).toStrictEqual([]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('drops duplicated consecutive points', () => {
|
|
111
|
+
const withDuplicate = [0, 0, 0, 0, 10, 0, 10, 10, 0, 10];
|
|
112
|
+
expect(coveredArea(withDuplicate, triangulate(withDuplicate, null, 2))).toBeCloseTo(100, 6);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('large rings', () => {
|
|
117
|
+
// Past 80 vertices earcut switches to the z-order curve hash, a separate code path.
|
|
118
|
+
it('covers a many sided polygon exactly, exercising the hashed path', () => {
|
|
119
|
+
const sides = 200;
|
|
120
|
+
const radius = 100;
|
|
121
|
+
const ring: number[] = [];
|
|
122
|
+
for (let i = 0; i < sides; i += 1) {
|
|
123
|
+
const angle = (i / sides) * Math.PI * 2;
|
|
124
|
+
ring.push(Math.cos(angle) * radius, Math.sin(angle) * radius);
|
|
125
|
+
}
|
|
126
|
+
const triangles = triangulate(ring, null, 2);
|
|
127
|
+
expect(triangles).toHaveLength((sides - 2) * 3);
|
|
128
|
+
const expected = 0.5 * sides * radius * radius * Math.sin((2 * Math.PI) / sides);
|
|
129
|
+
expect(coveredArea(ring, triangles)).toBeCloseTo(expected, 3);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -5,49 +5,51 @@ import { Node } from './earcut_node.js';
|
|
|
5
5
|
* @param {object} list - The list of points to process.
|
|
6
6
|
* @returns {object} The processed earcut data structure.
|
|
7
7
|
*/
|
|
8
|
-
export function sortLinked(list:
|
|
9
|
-
let i;
|
|
10
|
-
let p;
|
|
11
|
-
let q;
|
|
12
|
-
let e;
|
|
13
|
-
let tail;
|
|
8
|
+
export function sortLinked(list: Node | null): Node | null {
|
|
14
9
|
let numMerges;
|
|
15
|
-
let pSize;
|
|
16
|
-
let qSize;
|
|
17
10
|
let inSize = 1;
|
|
18
11
|
do {
|
|
19
|
-
p = list;
|
|
12
|
+
let p: Node | null = list;
|
|
13
|
+
let tail: Node | null = null;
|
|
20
14
|
list = null;
|
|
21
|
-
tail = null;
|
|
22
15
|
numMerges = 0;
|
|
23
16
|
while (p) {
|
|
24
17
|
numMerges += 1;
|
|
25
|
-
q = p;
|
|
26
|
-
pSize = 0;
|
|
27
|
-
for (i = 0; i < inSize; i += 1) {
|
|
18
|
+
let q: Node | null = p;
|
|
19
|
+
let pSize = 0;
|
|
20
|
+
for (let i = 0; i < inSize; i += 1) {
|
|
28
21
|
pSize += 1;
|
|
29
22
|
q = q.nextZ;
|
|
30
23
|
if (!q) {
|
|
31
24
|
break;
|
|
32
25
|
}
|
|
33
26
|
}
|
|
34
|
-
qSize = inSize;
|
|
27
|
+
let qSize = inSize;
|
|
35
28
|
while (pSize > 0 || (qSize > 0 && q)) {
|
|
29
|
+
let e: Node;
|
|
30
|
+
// The run counters keep p and q in step with the loop condition; the guards below cannot
|
|
31
|
+
// fire, they only spell that invariant out for the type checker.
|
|
36
32
|
if (pSize === 0) {
|
|
33
|
+
if (!q) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
37
36
|
e = q;
|
|
38
|
-
q =
|
|
37
|
+
q = e.nextZ;
|
|
39
38
|
qSize -= 1;
|
|
40
39
|
} else if (qSize === 0 || !q) {
|
|
40
|
+
if (!p) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
41
43
|
e = p;
|
|
42
|
-
p =
|
|
44
|
+
p = e.nextZ;
|
|
43
45
|
pSize -= 1;
|
|
44
|
-
} else if (p.z <= q.z) {
|
|
46
|
+
} else if (p && (p.z ?? 0) <= (q.z ?? 0)) {
|
|
45
47
|
e = p;
|
|
46
|
-
p =
|
|
48
|
+
p = e.nextZ;
|
|
47
49
|
pSize -= 1;
|
|
48
50
|
} else {
|
|
49
51
|
e = q;
|
|
50
|
-
q =
|
|
52
|
+
q = e.nextZ;
|
|
51
53
|
qSize -= 1;
|
|
52
54
|
}
|
|
53
55
|
if (tail) {
|
|
@@ -60,7 +62,9 @@ export function sortLinked(list: any) {
|
|
|
60
62
|
}
|
|
61
63
|
p = q;
|
|
62
64
|
}
|
|
63
|
-
tail
|
|
65
|
+
if (tail) {
|
|
66
|
+
tail.nextZ = null;
|
|
67
|
+
}
|
|
64
68
|
inSize *= 2;
|
|
65
69
|
} while (numMerges > 1);
|
|
66
70
|
return list;
|
|
@@ -72,7 +76,7 @@ export function sortLinked(list: any) {
|
|
|
72
76
|
* @param {object} b - The second point of the triangle.
|
|
73
77
|
* @returns {number} The calculated area of the triangle.
|
|
74
78
|
*/
|
|
75
|
-
export function compareX(a:
|
|
79
|
+
export function compareX(a: Node, b: Node): number {
|
|
76
80
|
return a.x - b.x;
|
|
77
81
|
}
|
|
78
82
|
|
|
@@ -107,17 +111,15 @@ export function zOrder(x: number, y: number, minX: number, minY: number, size: n
|
|
|
107
111
|
* @param {number} minY - The minimum y-coordinate of the bounding box.
|
|
108
112
|
* @param {number} size - The size of the bounding box.
|
|
109
113
|
*/
|
|
110
|
-
export function indexCurve(start:
|
|
114
|
+
export function indexCurve(start: Node, minX = 0, minY = 0, size = 0): void {
|
|
111
115
|
let p = start;
|
|
112
116
|
do {
|
|
113
|
-
|
|
114
|
-
p.z = zOrder(p.x, p.y, minX, minY, size);
|
|
115
|
-
}
|
|
117
|
+
p.z ??= zOrder(p.x, p.y, minX, minY, size);
|
|
116
118
|
p.prevZ = p.prev;
|
|
117
119
|
p.nextZ = p.next;
|
|
118
120
|
p = p.next;
|
|
119
121
|
} while (p !== start);
|
|
120
|
-
p.prevZ
|
|
122
|
+
p.prevZ!.nextZ = null;
|
|
121
123
|
p.prevZ = null;
|
|
122
124
|
sortLinked(p);
|
|
123
125
|
}
|
|
@@ -127,7 +129,7 @@ export function indexCurve(start: any, minX = 0, minY = 0, size = 0) {
|
|
|
127
129
|
* @param {object} start - TBD.
|
|
128
130
|
* @returns {object} The calculated point that is the closest to the triangle edge.
|
|
129
131
|
*/
|
|
130
|
-
export function getLeftmost(start:
|
|
132
|
+
export function getLeftmost(start: Node): Node {
|
|
131
133
|
let p = start;
|
|
132
134
|
let leftmost = start;
|
|
133
135
|
do {
|
|
@@ -175,7 +177,7 @@ export function pointInTriangle(
|
|
|
175
177
|
* @param {object} r - TBD.
|
|
176
178
|
* @returns {number} TBD.
|
|
177
179
|
*/
|
|
178
|
-
export function area(p:
|
|
180
|
+
export function area(p: Node, q: Node, r: Node): number {
|
|
179
181
|
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
180
182
|
}
|
|
181
183
|
|
|
@@ -185,7 +187,7 @@ export function area(p: any, q: any, r: any) {
|
|
|
185
187
|
* @param {object} p2 - The second point of the triangle.
|
|
186
188
|
* @returns {boolean} True if the point is inside the triangle, false otherwise.
|
|
187
189
|
*/
|
|
188
|
-
export function equals(p1:
|
|
190
|
+
export function equals(p1: Node, p2: Node): boolean {
|
|
189
191
|
return p1.x === p2.x && p1.y === p2.y;
|
|
190
192
|
}
|
|
191
193
|
|
|
@@ -197,7 +199,7 @@ export function equals(p1: any, p2: any) {
|
|
|
197
199
|
* @param {object} q2 - The second point of the second line segment.
|
|
198
200
|
* @returns {boolean} True if the line segments intersect, false otherwise.
|
|
199
201
|
*/
|
|
200
|
-
export function intersects(p1:
|
|
202
|
+
export function intersects(p1: Node, q1: Node, p2: Node, q2: Node): boolean {
|
|
201
203
|
return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 && area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
|
|
202
204
|
}
|
|
203
205
|
|
|
@@ -207,7 +209,7 @@ export function intersects(p1: any, q1: any, p2: any, q2: any) {
|
|
|
207
209
|
* @param {object} b - The second point of the line segment.
|
|
208
210
|
* @returns {boolean} True if the points are collinear, false otherwise.
|
|
209
211
|
*/
|
|
210
|
-
export function intersectsPolygon(a:
|
|
212
|
+
export function intersectsPolygon(a: Node, b: Node): boolean {
|
|
211
213
|
let p = a;
|
|
212
214
|
do {
|
|
213
215
|
if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) {
|
|
@@ -224,7 +226,7 @@ export function intersectsPolygon(a: any, b: any) {
|
|
|
224
226
|
* @param {object} b - The second point of the cross product.
|
|
225
227
|
* @returns {object} The calculated cross product result.
|
|
226
228
|
*/
|
|
227
|
-
export function locallyInside(a:
|
|
229
|
+
export function locallyInside(a: Node, b: Node): boolean {
|
|
228
230
|
return area(a.prev, a, a.next) < 0
|
|
229
231
|
? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0
|
|
230
232
|
: area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
|
|
@@ -236,7 +238,7 @@ export function locallyInside(a: any, b: any) {
|
|
|
236
238
|
* @param {object} b - The second point of the triangle.
|
|
237
239
|
* @returns {boolean} True if the point is inside the triangle, false otherwise.
|
|
238
240
|
*/
|
|
239
|
-
export function middleInside(a:
|
|
241
|
+
export function middleInside(a: Node, b: Node): boolean {
|
|
240
242
|
let p = a;
|
|
241
243
|
let inside = false;
|
|
242
244
|
const px = (a.x + b.x) / 2;
|
|
@@ -256,7 +258,7 @@ export function middleInside(a: any, b: any) {
|
|
|
256
258
|
* @param {object} b - The second point of the triangle.
|
|
257
259
|
* @returns {boolean} True if the point is inside the triangle, false otherwise.
|
|
258
260
|
*/
|
|
259
|
-
export function isValidDiagonal(a:
|
|
261
|
+
export function isValidDiagonal(a: Node, b: Node): boolean {
|
|
260
262
|
return (
|
|
261
263
|
equals(a, b) ||
|
|
262
264
|
(a.next.i !== b.i &&
|
|
@@ -274,7 +276,7 @@ export function isValidDiagonal(a: any, b: any) {
|
|
|
274
276
|
* @param {object} b - TBD.
|
|
275
277
|
* @returns {object} TBD.
|
|
276
278
|
*/
|
|
277
|
-
export function splitPolygon(a:
|
|
279
|
+
export function splitPolygon(a: Node, b: Node): Node {
|
|
278
280
|
const a2 = new Node(a.i, a.x, a.y);
|
|
279
281
|
const b2 = new Node(b.i, b.x, b.y);
|
|
280
282
|
const an = a.next;
|
|
@@ -298,7 +300,7 @@ export function splitPolygon(a: any, b: any) {
|
|
|
298
300
|
* @param {object} last - TBD.
|
|
299
301
|
* @returns {object} TBD.
|
|
300
302
|
*/
|
|
301
|
-
export function insertNode(i: number, x: number, y: number, last:
|
|
303
|
+
export function insertNode(i: number, x: number, y: number, last: Node | null): Node {
|
|
302
304
|
const p = new Node(i, x, y);
|
|
303
305
|
if (!last) {
|
|
304
306
|
p.prev = p;
|
|
@@ -316,7 +318,7 @@ export function insertNode(i: number, x: number, y: number, last: any) {
|
|
|
316
318
|
* TBD.
|
|
317
319
|
* @param {object} p - TBD.
|
|
318
320
|
*/
|
|
319
|
-
export function removeNode(p:
|
|
321
|
+
export function removeNode(p: Node): void {
|
|
320
322
|
p.next.prev = p.prev;
|
|
321
323
|
p.prev.next = p.next;
|
|
322
324
|
if (p.prevZ) {
|
|
@@ -332,7 +334,7 @@ export function removeNode(p: any) {
|
|
|
332
334
|
* @param {object} ear - TBD.
|
|
333
335
|
* @returns {boolean} TBD.
|
|
334
336
|
*/
|
|
335
|
-
export function isEar(ear:
|
|
337
|
+
export function isEar(ear: Node): boolean {
|
|
336
338
|
const a = ear.prev;
|
|
337
339
|
const b = ear;
|
|
338
340
|
const c = ear.next;
|
|
@@ -358,7 +360,7 @@ export function isEar(ear: any) {
|
|
|
358
360
|
* @param {number} size - TBD.
|
|
359
361
|
* @returns {boolean} TBD.
|
|
360
362
|
*/
|
|
361
|
-
export function isEarHashed(ear:
|
|
363
|
+
export function isEarHashed(ear: Node, minX = 0, minY = 0, size = 0): boolean {
|
|
362
364
|
const a = ear.prev;
|
|
363
365
|
const b = ear;
|
|
364
366
|
const c = ear.next;
|
|
@@ -375,7 +377,7 @@ export function isEarHashed(ear: any, minX = 0, minY = 0, size = 0) {
|
|
|
375
377
|
const maxZ = zOrder(maxTX, maxTY, minX, minY, size);
|
|
376
378
|
// first look for points inside the triangle in increasing z-order
|
|
377
379
|
let p = ear.nextZ;
|
|
378
|
-
while (p && p.z <= maxZ) {
|
|
380
|
+
while (p && p.z! <= maxZ) {
|
|
379
381
|
if (
|
|
380
382
|
p !== ear.prev &&
|
|
381
383
|
p !== ear.next &&
|
|
@@ -388,7 +390,7 @@ export function isEarHashed(ear: any, minX = 0, minY = 0, size = 0) {
|
|
|
388
390
|
}
|
|
389
391
|
// then look for points in decreasing z-order
|
|
390
392
|
p = ear.prevZ;
|
|
391
|
-
while (p && p.z >= minZ) {
|
|
393
|
+
while (p && p.z! >= minZ) {
|
|
392
394
|
if (
|
|
393
395
|
p !== ear.prev &&
|
|
394
396
|
p !== ear.next &&
|
|
@@ -411,24 +413,24 @@ export function isEarHashed(ear: any, minX = 0, minY = 0, size = 0) {
|
|
|
411
413
|
* @param {boolean} clockwise - Whether the triangles should be clockwise or counterclockwise.
|
|
412
414
|
* @returns {object} The processed earcut data structure with triangulation information.
|
|
413
415
|
*/
|
|
414
|
-
export function linkedList(data:
|
|
416
|
+
export function linkedList(data: number[], start: number, end: number, dim: number, clockwise: boolean): Node | null {
|
|
415
417
|
let sum = 0;
|
|
416
418
|
let i;
|
|
417
419
|
let j;
|
|
418
|
-
let last;
|
|
420
|
+
let last: Node | null = null;
|
|
419
421
|
// calculate original winding order of a polygon ring
|
|
420
422
|
for (i = start, j = end - dim; i < end; i += dim) {
|
|
421
|
-
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
423
|
+
sum += (data[j]! - data[i]!) * (data[i + 1]! + data[j + 1]!);
|
|
422
424
|
j = i;
|
|
423
425
|
}
|
|
424
426
|
// link points into circular doubly-linked list in the specified winding order
|
|
425
427
|
if (clockwise === sum > 0) {
|
|
426
428
|
for (i = start; i < end; i += dim) {
|
|
427
|
-
last = insertNode(i, data[i]
|
|
429
|
+
last = insertNode(i, data[i]!, data[i + 1]!, last ?? null);
|
|
428
430
|
}
|
|
429
431
|
} else {
|
|
430
432
|
for (i = end - dim; i >= start; i -= dim) {
|
|
431
|
-
last = insertNode(i, data[i]
|
|
433
|
+
last = insertNode(i, data[i]!, data[i + 1]!, last ?? null);
|
|
432
434
|
}
|
|
433
435
|
}
|
|
434
436
|
return last;
|
|
@@ -440,7 +442,7 @@ export function linkedList(data: any, start: number, end: number, dim: number, c
|
|
|
440
442
|
* @param {object} end - The ending point in the data structure.
|
|
441
443
|
* @returns {object} The calculated bounding box with min and max coordinates.
|
|
442
444
|
*/
|
|
443
|
-
export function filterPoints(start:
|
|
445
|
+
export function filterPoints(start: Node | null, end?: Node | null): Node | null {
|
|
444
446
|
if (!start) {
|
|
445
447
|
return start;
|
|
446
448
|
}
|
|
@@ -470,7 +472,7 @@ export function filterPoints(start: any, end?: any) {
|
|
|
470
472
|
* @param {object} outerNode - The outer node that contains the hole.
|
|
471
473
|
* @returns {object} The processed hole data structure.
|
|
472
474
|
*/
|
|
473
|
-
export function findHoleBridge(hole:
|
|
475
|
+
export function findHoleBridge(hole: Node, outerNode: Node): Node | null {
|
|
474
476
|
let p = outerNode;
|
|
475
477
|
const hx = hole.x;
|
|
476
478
|
const hy = hole.y;
|
|
@@ -523,10 +525,10 @@ export function findHoleBridge(hole: any, outerNode: any) {
|
|
|
523
525
|
* @param {object} hole - The hole to process.
|
|
524
526
|
* @param {object} outerNode - The outer node that contains the hole.
|
|
525
527
|
*/
|
|
526
|
-
export function eliminateHole(hole:
|
|
527
|
-
|
|
528
|
-
if (
|
|
529
|
-
const b = splitPolygon(
|
|
528
|
+
export function eliminateHole(hole: Node, outerNode: Node): void {
|
|
529
|
+
const bridge = findHoleBridge(hole, outerNode);
|
|
530
|
+
if (bridge) {
|
|
531
|
+
const b = splitPolygon(bridge, hole);
|
|
530
532
|
filterPoints(b, b.next);
|
|
531
533
|
}
|
|
532
534
|
}
|
|
@@ -539,7 +541,12 @@ export function eliminateHole(hole: any, outerNode: any) {
|
|
|
539
541
|
* @param {object} dim - The dimension of the data (2 or 3).
|
|
540
542
|
* @returns {object} The processed earcut data structure with holes included.
|
|
541
543
|
*/
|
|
542
|
-
export function eliminateHoles(
|
|
544
|
+
export function eliminateHoles(
|
|
545
|
+
data: number[],
|
|
546
|
+
holeIndices: number[],
|
|
547
|
+
outerNode: Node | null,
|
|
548
|
+
dim: number
|
|
549
|
+
): Node | null {
|
|
543
550
|
const queue = [];
|
|
544
551
|
let i;
|
|
545
552
|
let len;
|
|
@@ -547,8 +554,8 @@ export function eliminateHoles(data: any, holeIndices: any, outerNode: any, dim:
|
|
|
547
554
|
let end;
|
|
548
555
|
let list;
|
|
549
556
|
for (i = 0, len = holeIndices.length; i < len; i += 1) {
|
|
550
|
-
start = holeIndices[i] * dim;
|
|
551
|
-
end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
557
|
+
start = holeIndices[i]! * dim;
|
|
558
|
+
end = i < len - 1 ? holeIndices[i + 1]! * dim : data.length;
|
|
552
559
|
list = linkedList(data, start, end, dim, false);
|
|
553
560
|
if (!list) {
|
|
554
561
|
continue;
|
|
@@ -561,7 +568,10 @@ export function eliminateHoles(data: any, holeIndices: any, outerNode: any, dim:
|
|
|
561
568
|
queue.sort(compareX);
|
|
562
569
|
// process holes from left to right
|
|
563
570
|
for (i = 0; i < queue.length; i += 1) {
|
|
564
|
-
|
|
571
|
+
if (!outerNode) {
|
|
572
|
+
return outerNode;
|
|
573
|
+
}
|
|
574
|
+
eliminateHole(queue[i]!, outerNode);
|
|
565
575
|
outerNode = filterPoints(outerNode, outerNode.next);
|
|
566
576
|
}
|
|
567
577
|
return outerNode;
|
|
@@ -574,7 +584,7 @@ export function eliminateHoles(data: any, holeIndices: any, outerNode: any, dim:
|
|
|
574
584
|
* @param {number} dim - The dimension of the data (2 or 3).
|
|
575
585
|
* @returns {object} The processed triangulation data structure.
|
|
576
586
|
*/
|
|
577
|
-
export function cureLocalIntersections(start:
|
|
587
|
+
export function cureLocalIntersections(start: Node, triangles: number[], dim: number): Node {
|
|
578
588
|
let p = start;
|
|
579
589
|
do {
|
|
580
590
|
const a = p.prev;
|
|
@@ -604,7 +614,7 @@ export function cureLocalIntersections(start: any, triangles: any, dim: number)
|
|
|
604
614
|
* @param {number} minY - The minimum y-coordinate of the bounding box.
|
|
605
615
|
* @param {number} size - The size of the bounding box.
|
|
606
616
|
*/
|
|
607
|
-
export function splitEarcut(start:
|
|
617
|
+
export function splitEarcut(start: Node, triangles: number[], dim: number, minX = 0, minY = 0, size = 0): void {
|
|
608
618
|
// look for a valid diagonal that divides the polygon into two
|
|
609
619
|
let a = start;
|
|
610
620
|
do {
|
|
@@ -612,13 +622,13 @@ export function splitEarcut(start: any, triangles: any, dim: number, minX = 0, m
|
|
|
612
622
|
while (b !== a.prev) {
|
|
613
623
|
if (a.i !== b.i && isValidDiagonal(a, b)) {
|
|
614
624
|
// split the polygon in two by the diagonal
|
|
615
|
-
|
|
625
|
+
const c = splitPolygon(a, b);
|
|
616
626
|
// filter colinear points around the cuts
|
|
617
|
-
|
|
618
|
-
|
|
627
|
+
const halfA = filterPoints(a, a.next);
|
|
628
|
+
const halfC = filterPoints(c, c.next);
|
|
619
629
|
// run earcut on each half
|
|
620
|
-
earcutLinked(
|
|
621
|
-
earcutLinked(
|
|
630
|
+
earcutLinked(halfA, triangles, dim, minX, minY, size);
|
|
631
|
+
earcutLinked(halfC, triangles, dim, minX, minY, size);
|
|
622
632
|
return;
|
|
623
633
|
}
|
|
624
634
|
b = b.next;
|
|
@@ -638,13 +648,13 @@ export function splitEarcut(start: any, triangles: any, dim: number, minX = 0, m
|
|
|
638
648
|
* @param {object} pass - The pass information for triangulation.
|
|
639
649
|
*/
|
|
640
650
|
export function earcutLinked(
|
|
641
|
-
ear:
|
|
642
|
-
triangles:
|
|
651
|
+
ear: Node | null,
|
|
652
|
+
triangles: number[],
|
|
643
653
|
dim: number,
|
|
644
654
|
minX?: number,
|
|
645
655
|
minY?: number,
|
|
646
656
|
size?: number,
|
|
647
|
-
pass?:
|
|
657
|
+
pass?: number
|
|
648
658
|
) {
|
|
649
659
|
if (!ear) {
|
|
650
660
|
return;
|
|
@@ -697,9 +707,9 @@ export function earcutLinked(
|
|
|
697
707
|
* @param {number} dim - The dimension of the data (2 or 3).
|
|
698
708
|
* @returns {object} The processed earcut data structure with triangulation information.
|
|
699
709
|
*/
|
|
700
|
-
export function triangulate(data:
|
|
710
|
+
export function triangulate(data: number[], holeIndices: number[] | null, dim = 2): number[] {
|
|
701
711
|
const hasHoles = holeIndices && holeIndices.length;
|
|
702
|
-
const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
|
|
712
|
+
const outerLen = hasHoles ? holeIndices[0]! * dim : data.length;
|
|
703
713
|
let outerNode = linkedList(data, 0, outerLen, dim, true);
|
|
704
714
|
const triangles: number[] = [];
|
|
705
715
|
if (!outerNode) {
|
|
@@ -717,13 +727,13 @@ export function triangulate(data: any, holeIndices: any, dim = 2) {
|
|
|
717
727
|
}
|
|
718
728
|
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
|
|
719
729
|
if (data.length > 80 * dim) {
|
|
720
|
-
minX = data[0]
|
|
721
|
-
maxX = data[0]
|
|
722
|
-
minY = data[1]
|
|
723
|
-
maxY = data[1]
|
|
730
|
+
minX = data[0]!;
|
|
731
|
+
maxX = data[0]!;
|
|
732
|
+
minY = data[1]!;
|
|
733
|
+
maxY = data[1]!;
|
|
724
734
|
for (let i = dim; i < outerLen; i += dim) {
|
|
725
|
-
x = data[i]
|
|
726
|
-
y = data[i + 1]
|
|
735
|
+
x = data[i]!;
|
|
736
|
+
y = data[i + 1]!;
|
|
727
737
|
if (x < minX) {
|
|
728
738
|
minX = x;
|
|
729
739
|
}
|
|
@@ -2,8 +2,8 @@ export class Node {
|
|
|
2
2
|
public i: number;
|
|
3
3
|
public x: number;
|
|
4
4
|
public y: number;
|
|
5
|
-
public prev: Node
|
|
6
|
-
public next: Node
|
|
5
|
+
public prev: Node;
|
|
6
|
+
public next: Node;
|
|
7
7
|
public z: number | null;
|
|
8
8
|
public prevZ: Node | null;
|
|
9
9
|
public nextZ: Node | null;
|
|
@@ -21,9 +21,9 @@ export class Node {
|
|
|
21
21
|
// vertex coordinates
|
|
22
22
|
this.x = x;
|
|
23
23
|
this.y = y;
|
|
24
|
-
// previous and next vertice nodes in a polygon ring
|
|
25
|
-
this.prev =
|
|
26
|
-
this.next =
|
|
24
|
+
// previous and next vertice nodes in a polygon ring; a lone node is its own ring
|
|
25
|
+
this.prev = this;
|
|
26
|
+
this.next = this;
|
|
27
27
|
// z-order curve value
|
|
28
28
|
this.z = null;
|
|
29
29
|
// previous and next nodes in z-order
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IdentifiedWebGLRenderingContext } from './util.js';
|
|
2
2
|
import type { Image } from '../../display/image.js';
|
|
3
|
+
import type { RenderSession } from '../render_session.js';
|
|
3
4
|
|
|
4
5
|
export class FastSpriteBatch {
|
|
5
6
|
public gl!: any;
|
|
@@ -15,7 +16,7 @@ export class FastSpriteBatch {
|
|
|
15
16
|
public currentBatchSize!: any;
|
|
16
17
|
public currentBaseTexture!: any;
|
|
17
18
|
public currentBlendMode!: any;
|
|
18
|
-
public renderSession!:
|
|
19
|
+
public renderSession!: RenderSession;
|
|
19
20
|
public shader!: any;
|
|
20
21
|
public matrix!: any;
|
|
21
22
|
/**
|
|
@@ -46,7 +47,6 @@ export class FastSpriteBatch {
|
|
|
46
47
|
this.currentBatchSize = 0;
|
|
47
48
|
this.currentBaseTexture = null;
|
|
48
49
|
this.currentBlendMode = 0;
|
|
49
|
-
this.renderSession = null;
|
|
50
50
|
this.shader = null;
|
|
51
51
|
this.matrix = null;
|
|
52
52
|
this.setContext(gl);
|
|
@@ -74,7 +74,7 @@ export class FastSpriteBatch {
|
|
|
74
74
|
* @param {object} spriteBatch - The sprite batch to render.
|
|
75
75
|
* @param {object} renderSession - The render session to use.
|
|
76
76
|
*/
|
|
77
|
-
public begin(spriteBatch: any, renderSession:
|
|
77
|
+
public begin(spriteBatch: any, renderSession: RenderSession) {
|
|
78
78
|
this.renderSession = renderSession;
|
|
79
79
|
this.shader = this.renderSession.shaderManager.fastShader;
|
|
80
80
|
this.matrix = spriteBatch.worldTransform.toArray(true);
|
|
@@ -230,7 +230,7 @@ export class FastSpriteBatch {
|
|
|
230
230
|
const { gl } = this;
|
|
231
231
|
// bind the current texture
|
|
232
232
|
if (!this.currentBaseTexture._glTextures[gl.id]) {
|
|
233
|
-
this.renderSession.renderer.updateTexture(this.currentBaseTexture
|
|
233
|
+
this.renderSession.renderer.updateTexture(this.currentBaseTexture);
|
|
234
234
|
}
|
|
235
235
|
gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]);
|
|
236
236
|
// upload the verts to the buffer
|