@codexo/exojs-tilemap 0.15.3 → 0.16.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/README.md +33 -26
- package/dist/esm/ChunkSource.d.ts +33 -0
- package/dist/esm/ChunkSource.d.ts.map +1 -0
- package/dist/esm/ChunkStreamer.d.ts +98 -0
- package/dist/esm/ChunkStreamer.d.ts.map +1 -0
- package/dist/esm/ChunkStreamer.js +201 -0
- package/dist/esm/ChunkStreamer.js.map +1 -0
- package/dist/esm/ImageLayer.d.ts +11 -3
- package/dist/esm/ImageLayer.d.ts.map +1 -0
- package/dist/esm/ImageLayer.js +71 -64
- package/dist/esm/ImageLayer.js.map +1 -1
- package/dist/esm/ImageLayerNode.d.ts +89 -0
- package/dist/esm/ImageLayerNode.d.ts.map +1 -0
- package/dist/esm/ImageLayerNode.js +205 -0
- package/dist/esm/ImageLayerNode.js.map +1 -0
- package/dist/esm/MapObject.d.ts +70 -0
- package/dist/esm/MapObject.d.ts.map +1 -0
- package/dist/esm/MapObject.js +34 -0
- package/dist/esm/MapObject.js.map +1 -0
- package/dist/esm/MapObjectSpawner.d.ts +133 -0
- package/dist/esm/MapObjectSpawner.d.ts.map +1 -0
- package/dist/esm/MapObjectSpawner.js +147 -0
- package/dist/esm/MapObjectSpawner.js.map +1 -0
- package/dist/esm/MapSpawnSession.d.ts +53 -0
- package/dist/esm/MapSpawnSession.d.ts.map +1 -0
- package/dist/esm/MapSpawnSession.js +88 -0
- package/dist/esm/MapSpawnSession.js.map +1 -0
- package/dist/esm/MapWorld.d.ts +134 -0
- package/dist/esm/MapWorld.d.ts.map +1 -0
- package/dist/esm/MapWorld.js +150 -0
- package/dist/esm/MapWorld.js.map +1 -0
- package/dist/esm/MapWorldRuntime.d.ts +182 -0
- package/dist/esm/MapWorldRuntime.d.ts.map +1 -0
- package/dist/esm/MapWorldRuntime.js +261 -0
- package/dist/esm/MapWorldRuntime.js.map +1 -0
- package/dist/esm/ObjectLayer.d.ts +93 -7
- package/dist/esm/ObjectLayer.d.ts.map +1 -0
- package/dist/esm/ObjectLayer.js +184 -167
- package/dist/esm/ObjectLayer.js.map +1 -1
- package/dist/esm/SampledChunkSource.d.ts +43 -0
- package/dist/esm/SampledChunkSource.d.ts.map +1 -0
- package/dist/esm/SampledChunkSource.js +48 -0
- package/dist/esm/SampledChunkSource.js.map +1 -0
- package/dist/esm/TileAnimator.d.ts +12 -2
- package/dist/esm/TileAnimator.d.ts.map +1 -0
- package/dist/esm/TileAnimator.js +154 -165
- package/dist/esm/TileAnimator.js.map +1 -1
- package/dist/esm/TileChunk.d.ts +30 -5
- package/dist/esm/TileChunk.d.ts.map +1 -0
- package/dist/esm/TileChunk.js +190 -188
- package/dist/esm/TileChunk.js.map +1 -1
- package/dist/esm/TileChunkNode.d.ts +18 -3
- package/dist/esm/TileChunkNode.d.ts.map +1 -0
- package/dist/esm/TileChunkNode.js +104 -85
- package/dist/esm/TileChunkNode.js.map +1 -1
- package/dist/esm/TileLayer.d.ts +104 -24
- package/dist/esm/TileLayer.d.ts.map +1 -0
- package/dist/esm/TileLayer.js +511 -469
- package/dist/esm/TileLayer.js.map +1 -1
- package/dist/esm/TileLayerNode.d.ts +52 -11
- package/dist/esm/TileLayerNode.d.ts.map +1 -0
- package/dist/esm/TileLayerNode.js +224 -166
- package/dist/esm/TileLayerNode.js.map +1 -1
- package/dist/esm/TileMap.d.ts +96 -31
- package/dist/esm/TileMap.d.ts.map +1 -0
- package/dist/esm/TileMap.js +401 -357
- package/dist/esm/TileMap.js.map +1 -1
- package/dist/esm/TileMapBand.d.ts +42 -29
- package/dist/esm/TileMapBand.d.ts.map +1 -0
- package/dist/esm/TileMapBand.js +151 -158
- package/dist/esm/TileMapBand.js.map +1 -1
- package/dist/esm/TileMapNode.d.ts +34 -18
- package/dist/esm/TileMapNode.d.ts.map +1 -0
- package/dist/esm/TileMapNode.js +122 -109
- package/dist/esm/TileMapNode.js.map +1 -1
- package/dist/esm/TileMapView.d.ts +108 -47
- package/dist/esm/TileMapView.d.ts.map +1 -0
- package/dist/esm/TileMapView.js +385 -338
- package/dist/esm/TileMapView.js.map +1 -1
- package/dist/esm/TileSet.d.ts +15 -6
- package/dist/esm/TileSet.d.ts.map +1 -0
- package/dist/esm/TileSet.js +161 -181
- package/dist/esm/TileSet.js.map +1 -1
- package/dist/esm/WangSet.d.ts +5 -4
- package/dist/esm/WangSet.d.ts.map +1 -0
- package/dist/esm/WangSet.js +70 -78
- package/dist/esm/WangSet.js.map +1 -1
- package/dist/esm/WorkerSampledChunkSource.d.ts +95 -0
- package/dist/esm/WorkerSampledChunkSource.d.ts.map +1 -0
- package/dist/esm/WorkerSampledChunkSource.js +117 -0
- package/dist/esm/WorkerSampledChunkSource.js.map +1 -0
- package/dist/esm/autoTile.d.ts +10 -5
- package/dist/esm/autoTile.d.ts.map +1 -0
- package/dist/esm/autoTile.js +164 -205
- package/dist/esm/autoTile.js.map +1 -1
- package/dist/esm/chunkGeometry.d.ts +8 -7
- package/dist/esm/chunkGeometry.d.ts.map +1 -0
- package/dist/esm/chunkGeometry.js +83 -94
- package/dist/esm/chunkGeometry.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +26 -15
- package/dist/esm/nodeBounds.d.ts +20 -0
- package/dist/esm/nodeBounds.d.ts.map +1 -0
- package/dist/esm/nodeBounds.js +40 -0
- package/dist/esm/nodeBounds.js.map +1 -0
- package/dist/esm/pixelSnap.d.ts +4 -3
- package/dist/esm/pixelSnap.d.ts.map +1 -0
- package/dist/esm/pixelSnap.js +18 -16
- package/dist/esm/pixelSnap.js.map +1 -1
- package/dist/esm/public.d.ts +23 -3
- package/dist/esm/public.d.ts.map +1 -0
- package/dist/esm/tileCollision.d.ts +190 -0
- package/dist/esm/tileCollision.d.ts.map +1 -0
- package/dist/esm/tileCollision.js +367 -0
- package/dist/esm/tileCollision.js.map +1 -0
- package/dist/esm/tileWord.d.ts +12 -0
- package/dist/esm/tileWord.d.ts.map +1 -0
- package/dist/esm/tileWord.js +16 -0
- package/dist/esm/tileWord.js.map +1 -0
- package/dist/esm/tilemapExtension.d.ts +4 -3
- package/dist/esm/tilemapExtension.d.ts.map +1 -0
- package/dist/esm/tilemapExtension.js +47 -47
- package/dist/esm/tilemapExtension.js.map +1 -1
- package/dist/esm/tilemapSerializers.d.ts +5 -4
- package/dist/esm/tilemapSerializers.d.ts.map +1 -0
- package/dist/esm/tilemapSerializers.js +48 -41
- package/dist/esm/tilemapSerializers.js.map +1 -1
- package/dist/esm/types.d.ts +34 -18
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +111 -120
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts +50 -2
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts.map +1 -0
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.js +366 -332
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.js.map +1 -1
- package/dist/esm/webgl2/shaders/tile-chunk.frag.js +6 -0
- package/dist/esm/webgl2/shaders/tile-chunk.frag.js.map +1 -0
- package/dist/esm/webgl2/shaders/tile-chunk.vert.js +6 -0
- package/dist/esm/webgl2/shaders/tile-chunk.vert.js.map +1 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts +70 -4
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts.map +1 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.js +496 -383
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.js.map +1 -1
- package/dist/esm/webgpu/shaders/tile-chunk.wgsl.js +6 -0
- package/dist/esm/webgpu/shaders/tile-chunk.wgsl.js.map +1 -0
- package/package.json +8 -15
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/register.d.ts +0 -1
- package/dist/esm/register.js +0 -25
- package/dist/esm/register.js.map +0 -1
package/dist/esm/TileMapView.js
CHANGED
|
@@ -1,342 +1,389 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ImageLayer } from "./ImageLayer.js";
|
|
2
|
+
import { assertPixelSnapMode } from "./pixelSnap.js";
|
|
3
|
+
import { ImageLayerNode } from "./ImageLayerNode.js";
|
|
4
|
+
import { TileLayerNode } from "./TileLayerNode.js";
|
|
5
|
+
import { TileMapBand } from "./TileMapBand.js";
|
|
6
|
+
import { PixelSnapMode } from "@codexo/exojs/renderer-sdk";
|
|
4
7
|
|
|
8
|
+
//#region src/TileMapView.ts
|
|
5
9
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
10
|
+
* Groups a {@link TileMap}'s layers into independently placeable scene nodes so
|
|
11
|
+
* application actors can be interleaved **between** tile layers.
|
|
12
|
+
*
|
|
13
|
+
* A view produces exactly one canonical {@link TileLayerNode} per map layer
|
|
14
|
+
* (stable identity, map document order) and, optionally, named {@link TileMapBand}s
|
|
15
|
+
* grouping subsets of those nodes. The application parents the bands / layer
|
|
16
|
+
* nodes wherever it wants - typically as siblings of its own actor containers:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const view = map.createView({ bands: { ground: ['background', 'ground'], roof: ['roofs'] } });
|
|
20
|
+
* worldRoot.addChild(view.band('ground'), actors, view.band('roof'));
|
|
21
|
+
* // or without bands:
|
|
22
|
+
* worldRoot.addChild(view.getLayerNodeById(groundId)!, actors, view.getLayerNodeById(roofId)!);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* **Actors are application-owned siblings.** A `TileMapView` never adopts or
|
|
26
|
+
* destroys actors. The view is a helper, not a scene node - it does not own the
|
|
27
|
+
* world container, the {@link TileMap}, the {@link TileLayer}s, or tileset
|
|
28
|
+
* textures.
|
|
29
|
+
*
|
|
30
|
+
* **Ownership:** the view owns its generated layer nodes and bands. A layer
|
|
31
|
+
* assigned to a band is owned by that band; an unbanded layer is owned by the
|
|
32
|
+
* view directly. {@link TileMapView.destroy} destroys every band and layer node
|
|
33
|
+
* (detaching them from their application parents) but leaves actors, the map,
|
|
34
|
+
* its layers, and Loader-owned textures untouched. There is no map-replacement
|
|
35
|
+
* mutation API: to swap maps, destroy the old view, construct a new one, and
|
|
36
|
+
* re-parent its bands - the actor tree is never involved.
|
|
37
|
+
*
|
|
38
|
+
* **Image layers.** A view also produces exactly one canonical
|
|
39
|
+
* {@link ImageLayerNode} per {@link TileMap.imageLayers} entry (stable identity,
|
|
40
|
+
* map document order), reachable through {@link imageLayerNodes},
|
|
41
|
+
* {@link getImageLayerNodeById}, and {@link getImageLayerNodeByName}. Image
|
|
42
|
+
* layers are selectable in {@link TileMapViewOptions.bands} exactly like tile
|
|
43
|
+
* layers: a band member list may mix both kinds, and the band stacks its
|
|
44
|
+
* members by the map's combined document order
|
|
45
|
+
* ({@link import('./TileMap').TileMap.renderableLayers}). A banded image node
|
|
46
|
+
* is owned by its band; an unbanded one is owned by the view directly, and the
|
|
47
|
+
* application parents it wherever the image belongs in draw order - the same
|
|
48
|
+
* way actors are interleaved.
|
|
49
|
+
*
|
|
50
|
+
* @advanced
|
|
51
|
+
*/
|
|
52
|
+
var TileMapView = class {
|
|
53
|
+
_map;
|
|
54
|
+
_cullable;
|
|
55
|
+
/** All canonical tile-layer nodes, in map document order. */
|
|
56
|
+
_layerNodes = [];
|
|
57
|
+
/** Tile layer id → its canonical layer node. */
|
|
58
|
+
_layerNodeById = /* @__PURE__ */ new Map();
|
|
59
|
+
/** Bands in definition (insertion) order. */
|
|
60
|
+
_bands = [];
|
|
61
|
+
/** Band name → band. */
|
|
62
|
+
_bandByName = /* @__PURE__ */ new Map();
|
|
63
|
+
/** Original band definitions (frozen) for re-resolution on refresh. */
|
|
64
|
+
_bandDefs = [];
|
|
65
|
+
/** Layer node → its owning band (absent = view-owned / unbanded). */
|
|
66
|
+
_nodeBand = /* @__PURE__ */ new Map();
|
|
67
|
+
/** Unbanded tile-layer nodes owned directly by the view, in map document order. */
|
|
68
|
+
_directLayerNodes = [];
|
|
69
|
+
/** All canonical image layer nodes, in map document order. */
|
|
70
|
+
_imageLayerNodes = [];
|
|
71
|
+
/** Image layer id → its canonical image layer node. */
|
|
72
|
+
_imageLayerNodeById = /* @__PURE__ */ new Map();
|
|
73
|
+
_destroyed = false;
|
|
74
|
+
_pixelSnapMode = PixelSnapMode.None;
|
|
75
|
+
/**
|
|
76
|
+
* @param map The runtime map to compose. Referenced, never owned.
|
|
77
|
+
* @param options Band definitions and culling.
|
|
78
|
+
* @throws When a band definition references an unknown/ambiguous layer or
|
|
79
|
+
* assigns a layer twice / to multiple bands.
|
|
80
|
+
*/
|
|
81
|
+
constructor(map, options) {
|
|
82
|
+
this._map = map;
|
|
83
|
+
this._cullable = options?.cullable ?? true;
|
|
84
|
+
for (const layer of map.layers) {
|
|
85
|
+
const node = new TileLayerNode(layer, { cullable: this._cullable });
|
|
86
|
+
this._layerNodes.push(node);
|
|
87
|
+
this._layerNodeById.set(layer.id, node);
|
|
88
|
+
}
|
|
89
|
+
for (const imageLayer of map.imageLayers) {
|
|
90
|
+
const imageNode = new ImageLayerNode(imageLayer);
|
|
91
|
+
this._imageLayerNodes.push(imageNode);
|
|
92
|
+
this._imageLayerNodeById.set(imageLayer.id, imageNode);
|
|
93
|
+
}
|
|
94
|
+
if (options?.bands) for (const [name, selectors] of Object.entries(options.bands)) this._defineBand(name, selectors);
|
|
95
|
+
for (const node of this._layerNodes) if (!this._nodeBand.has(node)) this._directLayerNodes.push(node);
|
|
96
|
+
}
|
|
97
|
+
/** The runtime map this view composes. Referenced, never owned. */
|
|
98
|
+
get map() {
|
|
99
|
+
return this._map;
|
|
100
|
+
}
|
|
101
|
+
/** All canonical tile-layer nodes, one per map tile layer, in map document order. */
|
|
102
|
+
get layers() {
|
|
103
|
+
return this._layerNodes;
|
|
104
|
+
}
|
|
105
|
+
/** The bands, in definition (insertion) order. */
|
|
106
|
+
get bands() {
|
|
107
|
+
return this._bands;
|
|
108
|
+
}
|
|
109
|
+
/** Whether this view has been destroyed. */
|
|
110
|
+
get destroyed() {
|
|
111
|
+
return this._destroyed;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Render-only pixel-snap mode applied to every layer node this view owns (and
|
|
115
|
+
* forwarded to every chunk drawable, current and rebuilt by
|
|
116
|
+
* {@link refreshLayers}). Snaps tile chunk origins to the active render
|
|
117
|
+
* target's device-pixel grid for crisp tiles; with integer tile pitch the grid
|
|
118
|
+
* stays exact and adjacent chunks cannot drift apart. Purely visual - tile
|
|
119
|
+
* data, layer offsets, chunk revisions, and culling are unchanged. Setting the
|
|
120
|
+
* current value is a no-op; an invalid value throws and leaves the prior mode
|
|
121
|
+
* unchanged.
|
|
122
|
+
*
|
|
123
|
+
* @default PixelSnapMode.None
|
|
124
|
+
* @stable
|
|
125
|
+
*/
|
|
126
|
+
get pixelSnapMode() {
|
|
127
|
+
return this._pixelSnapMode;
|
|
128
|
+
}
|
|
129
|
+
set pixelSnapMode(mode) {
|
|
130
|
+
if (mode === this._pixelSnapMode) return;
|
|
131
|
+
assertPixelSnapMode(mode);
|
|
132
|
+
this._pixelSnapMode = mode;
|
|
133
|
+
for (const node of this._layerNodes) node.pixelSnapMode = mode;
|
|
134
|
+
for (const node of this._imageLayerNodes) node.pixelSnapMode = mode;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The canonical layer node for the **tile** layer with the given **id**, or
|
|
138
|
+
* `undefined`. Tile ids are authoritative and unique - this is the
|
|
139
|
+
* unambiguous lookup. The returned node may be reparented into the caller's
|
|
140
|
+
* own containers; the view still tracks it for refresh and destruction.
|
|
141
|
+
*/
|
|
142
|
+
getLayerNodeById(id) {
|
|
143
|
+
return this._layerNodeById.get(id);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Every canonical tile-layer node whose layer has the given **name**, in map
|
|
147
|
+
* document order. Layer names are not guaranteed unique, so this returns an
|
|
148
|
+
* array (empty when no layer matches). Prefer {@link getLayerNodeById} when
|
|
149
|
+
* you have the id.
|
|
150
|
+
*/
|
|
151
|
+
getLayerNodesByName(name) {
|
|
152
|
+
return this._layerNodes.filter((node) => node.layer.name === name);
|
|
153
|
+
}
|
|
154
|
+
/** All canonical image layer nodes, one per map image layer, in map document order. */
|
|
155
|
+
get imageLayerNodes() {
|
|
156
|
+
return this._imageLayerNodes;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The canonical image layer node for the image layer with the given **id**,
|
|
160
|
+
* or `undefined`. Ids are authoritative and unique - this is the unambiguous
|
|
161
|
+
* lookup. The returned node may be reparented into the caller's own
|
|
162
|
+
* containers; the view still tracks it for refresh and destruction.
|
|
163
|
+
*/
|
|
164
|
+
getImageLayerNodeById(id) {
|
|
165
|
+
return this._imageLayerNodeById.get(id);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The canonical image layer node for the image layer with the given
|
|
169
|
+
* **name**, or `undefined` if no image layer has that name. Prefer
|
|
170
|
+
* {@link getImageLayerNodeById} when you have the id.
|
|
171
|
+
* @throws If more than one image layer shares that name (reference such
|
|
172
|
+
* layers by id instead).
|
|
173
|
+
*/
|
|
174
|
+
getImageLayerNodeByName(name) {
|
|
175
|
+
const matches = this._map.imageLayers.filter((layer) => layer.name === name);
|
|
176
|
+
if (matches.length === 0) return;
|
|
177
|
+
if (matches.length > 1) throw new Error(`TileMapView image layer name "${name}" is ambiguous (${matches.length} image layers share it); reference it by id instead.`);
|
|
178
|
+
return this._imageLayerNodeById.get(matches[0].id);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The band registered under `name`.
|
|
182
|
+
* @throws If no band with that name was defined.
|
|
183
|
+
*/
|
|
184
|
+
band(name) {
|
|
185
|
+
const band = this._bandByName.get(name);
|
|
186
|
+
if (!band) throw new Error(`TileMapView has no band named "${name}". Defined bands: ${this._bands.length > 0 ? this._bands.map((b) => `"${b.name}"`).join(", ") : "(none)"}.`);
|
|
187
|
+
return band;
|
|
188
|
+
}
|
|
189
|
+
/** Whether a band with the given name was defined. */
|
|
190
|
+
hasBand(name) {
|
|
191
|
+
return this._bandByName.has(name);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Rebuild the view after **structural** map changes (tile or image layers
|
|
195
|
+
* added to or removed from the map). Ordinary tile edits and chunk
|
|
196
|
+
* creation/removal do NOT need this - those are handled by chunk revisions
|
|
197
|
+
* and {@link TileLayerNode.refresh} respectively.
|
|
198
|
+
*
|
|
199
|
+
* - Removed layers (tile or image): their generated node is detached and
|
|
200
|
+
* destroyed.
|
|
201
|
+
* - Unchanged layers: keep their existing node (stable identity).
|
|
202
|
+
* - Added layers (tile or image): a new node is created and assigned to the
|
|
203
|
+
* first band whose definition selects it (by a currently-unambiguous id or
|
|
204
|
+
* name), otherwise owned directly by the view.
|
|
205
|
+
* - Every band's children are re-ordered to the map's combined document
|
|
206
|
+
* order ({@link import('./TileMap').TileMap.renderableLayers}).
|
|
207
|
+
*
|
|
208
|
+
* Application actors are never touched, and bands keep their placement in the
|
|
209
|
+
* application scene graph.
|
|
210
|
+
*
|
|
211
|
+
* @throws If the view has been destroyed.
|
|
212
|
+
*/
|
|
213
|
+
refreshLayers() {
|
|
214
|
+
if (this._destroyed) throw new Error("Cannot refresh a destroyed TileMapView.");
|
|
215
|
+
const currentLayers = this._map.layers;
|
|
216
|
+
const currentIds = /* @__PURE__ */ new Set();
|
|
217
|
+
for (const layer of currentLayers) currentIds.add(layer.id);
|
|
218
|
+
for (const node of [...this._layerNodes]) if (!currentIds.has(node.layer.id)) this._removeTileNode(node);
|
|
219
|
+
const currentImageLayers = new Set(this._map.imageLayers);
|
|
220
|
+
for (const node of [...this._imageLayerNodes]) if (!currentImageLayers.has(node.layer)) this._removeImageNode(node);
|
|
221
|
+
const newOrder = [];
|
|
222
|
+
for (const layer of currentLayers) {
|
|
223
|
+
let node = this._layerNodeById.get(layer.id);
|
|
224
|
+
if (!node) {
|
|
225
|
+
node = new TileLayerNode(layer, { cullable: this._cullable });
|
|
226
|
+
if (this._pixelSnapMode !== PixelSnapMode.None) node.pixelSnapMode = this._pixelSnapMode;
|
|
227
|
+
this._layerNodeById.set(layer.id, node);
|
|
228
|
+
this._assignNewNode(node, layer);
|
|
229
|
+
}
|
|
230
|
+
newOrder.push(node);
|
|
231
|
+
}
|
|
232
|
+
this._layerNodes.length = 0;
|
|
233
|
+
this._layerNodes.push(...newOrder);
|
|
234
|
+
const newImageOrder = [];
|
|
235
|
+
for (const imageLayer of this._map.imageLayers) {
|
|
236
|
+
let node = this._imageLayerNodes.find((candidate) => candidate.layer === imageLayer);
|
|
237
|
+
if (!node) {
|
|
238
|
+
node = new ImageLayerNode(imageLayer);
|
|
239
|
+
if (this._pixelSnapMode !== PixelSnapMode.None) node.pixelSnapMode = this._pixelSnapMode;
|
|
240
|
+
this._imageLayerNodeById.set(imageLayer.id, node);
|
|
241
|
+
this._assignNewNode(node, imageLayer);
|
|
242
|
+
}
|
|
243
|
+
newImageOrder.push(node);
|
|
244
|
+
}
|
|
245
|
+
this._imageLayerNodes.length = 0;
|
|
246
|
+
this._imageLayerNodes.push(...newImageOrder);
|
|
247
|
+
const documentIndex = /* @__PURE__ */ new Map();
|
|
248
|
+
for (const [index, layer] of this._map.renderableLayers.entries()) documentIndex.set(layer, index);
|
|
249
|
+
for (const band of this._bands) band._reorder(documentIndex);
|
|
250
|
+
this._directLayerNodes.length = 0;
|
|
251
|
+
for (const node of newOrder) if (!this._nodeBand.has(node)) this._directLayerNodes.push(node);
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Destroy the view: every band, generated tile-layer node, and generated
|
|
256
|
+
* {@link ImageLayerNode} is destroyed (and detached from its application
|
|
257
|
+
* parent), freeing cached chunk geometry. Banded nodes are destroyed by
|
|
258
|
+
* their band; unbanded ones by the view directly. Idempotent. Application
|
|
259
|
+
* actors, sibling content, the {@link TileMap}, its {@link TileLayer}s and
|
|
260
|
+
* image layers, and Loader-owned textures all survive.
|
|
261
|
+
*/
|
|
262
|
+
destroy() {
|
|
263
|
+
if (this._destroyed) return;
|
|
264
|
+
this._destroyed = true;
|
|
265
|
+
for (const band of this._bands) band.destroy();
|
|
266
|
+
for (const node of this._directLayerNodes) {
|
|
267
|
+
node.parent?.removeChild(node);
|
|
268
|
+
node.destroy();
|
|
269
|
+
}
|
|
270
|
+
for (const node of this._imageLayerNodes) {
|
|
271
|
+
if (this._nodeBand.has(node)) continue;
|
|
272
|
+
node.parent?.removeChild(node);
|
|
273
|
+
node.destroy();
|
|
274
|
+
}
|
|
275
|
+
this._bands.length = 0;
|
|
276
|
+
this._bandByName.clear();
|
|
277
|
+
this._bandDefs.length = 0;
|
|
278
|
+
this._directLayerNodes.length = 0;
|
|
279
|
+
this._layerNodes.length = 0;
|
|
280
|
+
this._layerNodeById.clear();
|
|
281
|
+
this._nodeBand.clear();
|
|
282
|
+
this._imageLayerNodes.length = 0;
|
|
283
|
+
this._imageLayerNodeById.clear();
|
|
284
|
+
}
|
|
285
|
+
/** Resolve one band definition into a {@link TileMapBand} and record it. */
|
|
286
|
+
_defineBand(name, selectors) {
|
|
287
|
+
const members = /* @__PURE__ */ new Set();
|
|
288
|
+
for (const selector of selectors) {
|
|
289
|
+
const layer = this._resolveSelector(name, selector);
|
|
290
|
+
if (members.has(layer)) throw new Error(`TileMapView band "${name}" lists layer ${layer.id} more than once.`);
|
|
291
|
+
const existing = this._nodeFor(layer);
|
|
292
|
+
if (existing && this._nodeBand.has(existing)) throw new Error(`TileMapView layer ${layer.id} is assigned to multiple bands ("${this._nodeBand.get(existing).name}" and "${name}").`);
|
|
293
|
+
members.add(layer);
|
|
294
|
+
}
|
|
295
|
+
const orderedNodes = [];
|
|
296
|
+
for (const layer of this._map.renderableLayers) if (members.has(layer)) orderedNodes.push(this._nodeFor(layer));
|
|
297
|
+
const band = new TileMapBand(name, orderedNodes);
|
|
298
|
+
for (const node of orderedNodes) this._nodeBand.set(node, band);
|
|
299
|
+
this._bands.push(band);
|
|
300
|
+
this._bandByName.set(name, band);
|
|
301
|
+
this._bandDefs.push({
|
|
302
|
+
name,
|
|
303
|
+
selectors: Object.freeze([...selectors])
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Resolve a single selector to a tile or image layer instance, throwing on
|
|
308
|
+
* unknown/ambiguous. Instances (not ids) disambiguate fallback-ordered maps
|
|
309
|
+
* in which a tile layer and an image layer share an id.
|
|
310
|
+
*/
|
|
311
|
+
_resolveSelector(bandName, selector) {
|
|
312
|
+
if (typeof selector === "number") {
|
|
313
|
+
const tileLayer = this._map.getTileLayerById(selector);
|
|
314
|
+
const imageLayer = this._map.imageLayers.find((layer) => layer.id === selector);
|
|
315
|
+
if (tileLayer && imageLayer) throw new Error(`TileMapView band "${bandName}": layer id ${selector} is ambiguous (a tile layer and an image layer share it); reference it by a unique name instead.`);
|
|
316
|
+
const layer = tileLayer ?? imageLayer;
|
|
317
|
+
if (!layer) throw new Error(`TileMapView band "${bandName}": no layer with id ${selector} in map "${this._map.name}".`);
|
|
318
|
+
return layer;
|
|
319
|
+
}
|
|
320
|
+
const matches = [...this._map.layers.filter((layer) => layer.name === selector), ...this._map.imageLayers.filter((layer) => layer.name === selector)];
|
|
321
|
+
if (matches.length === 0) throw new Error(`TileMapView band "${bandName}": no layer named "${selector}" in map "${this._map.name}".`);
|
|
322
|
+
if (matches.length > 1) throw new Error(`TileMapView band "${bandName}": layer name "${selector}" is ambiguous (${matches.length} layers share it); reference it by id instead.`);
|
|
323
|
+
return matches[0];
|
|
324
|
+
}
|
|
325
|
+
/** The canonical node for a tile or image layer instance, if one exists. */
|
|
326
|
+
_nodeFor(layer) {
|
|
327
|
+
if (layer instanceof ImageLayer) return this._imageLayerNodes.find((node) => node.layer === layer);
|
|
328
|
+
return this._layerNodeById.get(layer.id);
|
|
329
|
+
}
|
|
330
|
+
/** Assign a freshly created node to the first band that selects its layer. */
|
|
331
|
+
_assignNewNode(node, layer) {
|
|
332
|
+
for (const def of this._bandDefs) if (this._definitionSelects(def, layer)) {
|
|
333
|
+
const band = this._bandByName.get(def.name);
|
|
334
|
+
band._adopt(node);
|
|
335
|
+
this._nodeBand.set(node, band);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Whether a band definition selects the given layer - only by a selector
|
|
341
|
+
* that is currently unambiguous (a unique name, or an id not shared across
|
|
342
|
+
* kinds), mirroring {@link _resolveSelector}'s construction-time rules.
|
|
343
|
+
*/
|
|
344
|
+
_definitionSelects(def, layer) {
|
|
345
|
+
for (const selector of def.selectors) if (typeof selector === "number") {
|
|
346
|
+
if (selector === layer.id && !this._isCrossKindId(selector)) return true;
|
|
347
|
+
} else if (selector === layer.name) {
|
|
348
|
+
if (this._map.layers.filter((other) => other.name === selector).length + this._map.imageLayers.filter((other) => other.name === selector).length === 1) return true;
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
/** Whether an id currently belongs to both a tile layer and an image layer. */
|
|
353
|
+
_isCrossKindId(id) {
|
|
354
|
+
return this._map.getTileLayerById(id) !== void 0 && this._map.imageLayers.some((layer) => layer.id === id);
|
|
355
|
+
}
|
|
356
|
+
/** Detach + destroy a tile node, dropping it from bands and registries. */
|
|
357
|
+
_removeTileNode(node) {
|
|
358
|
+
this._releaseFromOwner(node);
|
|
359
|
+
node.parent?.removeChild(node);
|
|
360
|
+
this._layerNodeById.delete(node.layer.id);
|
|
361
|
+
const orderIndex = this._layerNodes.indexOf(node);
|
|
362
|
+
if (orderIndex !== -1) this._layerNodes.splice(orderIndex, 1);
|
|
363
|
+
node.destroy();
|
|
364
|
+
}
|
|
365
|
+
/** Detach + destroy an image node, dropping it from bands and registries. */
|
|
366
|
+
_removeImageNode(node) {
|
|
367
|
+
this._releaseFromOwner(node);
|
|
368
|
+
node.parent?.removeChild(node);
|
|
369
|
+
if (this._imageLayerNodeById.get(node.layer.id) === node) this._imageLayerNodeById.delete(node.layer.id);
|
|
370
|
+
const orderIndex = this._imageLayerNodes.indexOf(node);
|
|
371
|
+
if (orderIndex !== -1) this._imageLayerNodes.splice(orderIndex, 1);
|
|
372
|
+
node.destroy();
|
|
373
|
+
}
|
|
374
|
+
/** Release a node from its band, or from the view's direct-ownership list. */
|
|
375
|
+
_releaseFromOwner(node) {
|
|
376
|
+
const band = this._nodeBand.get(node);
|
|
377
|
+
if (band) {
|
|
378
|
+
band._release(node);
|
|
379
|
+
this._nodeBand.delete(node);
|
|
380
|
+
} else if (node instanceof TileLayerNode) {
|
|
381
|
+
const directIndex = this._directLayerNodes.indexOf(node);
|
|
382
|
+
if (directIndex !== -1) this._directLayerNodes.splice(directIndex, 1);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
340
386
|
|
|
387
|
+
//#endregion
|
|
341
388
|
export { TileMapView };
|
|
342
|
-
//# sourceMappingURL=TileMapView.js.map
|
|
389
|
+
//# sourceMappingURL=TileMapView.js.map
|