minecraft-renderer 0.1.37 → 0.1.39
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/mesher.js +20 -20
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +72 -75
- package/dist/minecraft-renderer.js +57 -57
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +239 -239
- package/package.json +3 -1
- package/src/graphicsBackend/config.ts +6 -1
- package/src/lib/worldrendererCommon.ts +119 -53
- package/src/mesher/blockEntityMetadata.ts +70 -0
- package/src/mesher/computeHeightmap.ts +66 -0
- package/src/mesher/mesher.ts +13 -20
- package/src/mesher/mesherWasm.ts +432 -140
- package/src/mesher/mesherWasmConversionCache.ts +155 -0
- package/src/mesher/mesherWasmRequestTracker.ts +56 -0
- package/src/mesher/models.ts +2 -46
- package/src/mesher/shared.ts +22 -3
- package/src/mesher/test/heightmapParity.test.ts +231 -0
- package/src/mesher/test/mesherWasmConversionCache.test.ts +128 -0
- package/src/mesher/test/run/chunk.ts +2 -2
- package/src/mesher/test/splitColumnWasmOutput.test.ts +163 -0
- package/src/three/chunkMeshManager.ts +342 -5
- package/src/three/modules/cameraBobbing.ts +8 -1
- package/src/three/worldRendererThree.ts +65 -33
- package/src/wasm-lib/render-from-wasm.ts +158 -13
- package/wasm/wasm_mesher.d.ts +4 -4
- package/wasm/wasm_mesher.js +23 -66
- package/wasm/wasm_mesher_bg.wasm +0 -0
- package/wasm/wasm_mesher_bg.wasm.d.ts +9 -0
|
@@ -67,7 +67,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
67
67
|
cameraContainer!: THREE.Object3D
|
|
68
68
|
media: ThreeJsMedia
|
|
69
69
|
get waitingChunksToDisplay() {
|
|
70
|
-
return
|
|
70
|
+
return this.chunkMeshManager.waitingChunksToDisplay
|
|
71
71
|
}
|
|
72
72
|
waypoints: WaypointsRenderer
|
|
73
73
|
cinimaticScript: CinimaticScriptRunner
|
|
@@ -82,7 +82,14 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
82
82
|
camera!: THREE.PerspectiveCamera
|
|
83
83
|
renderTimeAvg = 0
|
|
84
84
|
private pendingSectionUpdates = new Map<string, { geometry: MesherGeometryOutput, key: string, type: string }>()
|
|
85
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Per-section buffering timestamps for `applyPendingSectionUpdates`.
|
|
87
|
+
* Each section gets its own deadline so a continuous stream of updates
|
|
88
|
+
* (e.g. server-side block changes from explosions, pistons, fluid ticks)
|
|
89
|
+
* does not flush freshly added sections together with stale ones via a
|
|
90
|
+
* single global timer.
|
|
91
|
+
*/
|
|
92
|
+
private pendingSectionBufferStartTimes = new Map<string, number>()
|
|
86
93
|
private static readonly MAX_SECTION_UPDATE_BUFFER_MS = 500
|
|
87
94
|
// Memory usage tracking (in bytes)
|
|
88
95
|
get estimatedMemoryUsage() {
|
|
@@ -747,42 +754,57 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
747
754
|
}
|
|
748
755
|
|
|
749
756
|
finishChunk(chunkKey: string) {
|
|
750
|
-
//
|
|
757
|
+
// Reveal all sections of this chunk that were held invisible by the
|
|
758
|
+
// "Batch Chunks Display" (`_renderByChunks`) option. No-op when the
|
|
759
|
+
// option is off — `waitingChunksToDisplay` is empty in that case.
|
|
760
|
+
this.chunkMeshManager.finishChunkDisplay(chunkKey)
|
|
751
761
|
}
|
|
752
762
|
|
|
753
763
|
private applyPendingSectionUpdates() {
|
|
754
764
|
if (this.pendingSectionUpdates.size === 0) return
|
|
755
765
|
|
|
756
766
|
const now = performance.now()
|
|
757
|
-
const
|
|
767
|
+
const sectionHeight = this.getSectionHeight()
|
|
768
|
+
const ready: string[] = []
|
|
758
769
|
|
|
759
|
-
|
|
760
|
-
const
|
|
761
|
-
|
|
770
|
+
for (const key of this.pendingSectionUpdates.keys()) {
|
|
771
|
+
const startedAt = this.pendingSectionBufferStartTimes.get(key) ?? now
|
|
772
|
+
const sinceFirst = now - startedAt
|
|
773
|
+
|
|
774
|
+
if (sinceFirst < WorldRendererThree.MAX_SECTION_UPDATE_BUFFER_MS) {
|
|
775
|
+
// Still within this section's grace window — wait if any neighbor is
|
|
776
|
+
// currently being re-meshed so we don't briefly expose a hole between
|
|
777
|
+
// the just-updated section and a stale neighbor (sky-flicker bug).
|
|
762
778
|
const [sx, sy, sz] = key.split(',').map(Number)
|
|
763
779
|
const neighborKeys = [
|
|
764
780
|
`${sx - 16},${sy},${sz}`, `${sx + 16},${sy},${sz}`,
|
|
765
781
|
`${sx},${sy - sectionHeight},${sz}`, `${sx},${sy + sectionHeight},${sz}`,
|
|
766
782
|
`${sx},${sy},${sz - 16}`, `${sx},${sy},${sz + 16}`,
|
|
767
783
|
]
|
|
768
|
-
|
|
784
|
+
let neighborBusy = false
|
|
769
785
|
for (const neighborKey of neighborKeys) {
|
|
770
786
|
if (
|
|
771
787
|
this.sectionsWaiting.has(neighborKey) &&
|
|
772
788
|
!this.pendingSectionUpdates.has(neighborKey) &&
|
|
773
789
|
this.sectionObjects[neighborKey]
|
|
774
790
|
) {
|
|
775
|
-
|
|
791
|
+
neighborBusy = true
|
|
792
|
+
break
|
|
776
793
|
}
|
|
777
794
|
}
|
|
795
|
+
if (neighborBusy) continue
|
|
778
796
|
}
|
|
797
|
+
|
|
798
|
+
ready.push(key)
|
|
779
799
|
}
|
|
780
800
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
801
|
+
if (ready.length === 0) return
|
|
802
|
+
|
|
803
|
+
for (const key of ready) {
|
|
804
|
+
const update = this.pendingSectionUpdates.get(key)!
|
|
805
|
+
this.pendingSectionUpdates.delete(key)
|
|
806
|
+
this.pendingSectionBufferStartTimes.delete(key)
|
|
784
807
|
|
|
785
|
-
for (const update of updates) {
|
|
786
808
|
const chunkCoords = update.key.split(',')
|
|
787
809
|
const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
|
|
788
810
|
|
|
@@ -805,12 +827,9 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
805
827
|
for (const key of [...this.pendingSectionUpdates.keys()]) {
|
|
806
828
|
if (key.startsWith(`${x},`) && key.endsWith(`,${z}`)) {
|
|
807
829
|
this.pendingSectionUpdates.delete(key)
|
|
830
|
+
this.pendingSectionBufferStartTimes.delete(key)
|
|
808
831
|
}
|
|
809
832
|
}
|
|
810
|
-
|
|
811
|
-
if (this.pendingSectionUpdates.size === 0) {
|
|
812
|
-
this.pendingSectionBufferStartTime = null
|
|
813
|
-
}
|
|
814
833
|
}
|
|
815
834
|
|
|
816
835
|
handleWorkerMessage(data: { geometry: MesherGeometryOutput, key, type }): void {
|
|
@@ -819,15 +838,17 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
819
838
|
const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
|
|
820
839
|
if (!this.loadedChunks[chunkKey] || !this.active) {
|
|
821
840
|
this.pendingSectionUpdates.delete(data.key)
|
|
822
|
-
|
|
823
|
-
this.pendingSectionBufferStartTime = null
|
|
824
|
-
}
|
|
841
|
+
this.pendingSectionBufferStartTimes.delete(data.key)
|
|
825
842
|
return
|
|
826
843
|
}
|
|
827
844
|
|
|
828
845
|
if (this.sectionObjects[data.key]) {
|
|
829
846
|
this.pendingSectionUpdates.set(data.key, data)
|
|
830
|
-
|
|
847
|
+
// Per-section deadline: only set if we don't already have one, so
|
|
848
|
+
// repeated updates to the same section don't postpone its flush.
|
|
849
|
+
if (!this.pendingSectionBufferStartTimes.has(data.key)) {
|
|
850
|
+
this.pendingSectionBufferStartTimes.set(data.key, performance.now())
|
|
851
|
+
}
|
|
831
852
|
return
|
|
832
853
|
}
|
|
833
854
|
|
|
@@ -1137,6 +1158,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1137
1158
|
chunksRenderDistanceOverride !== undefined
|
|
1138
1159
|
) {
|
|
1139
1160
|
for (const [key, object] of Object.entries(this.sectionObjects)) {
|
|
1161
|
+
if (object._waitingForChunkDisplay) continue
|
|
1140
1162
|
const [x, y, z] = key.split(',').map(Number)
|
|
1141
1163
|
const isVisible =
|
|
1142
1164
|
// eslint-disable-next-line no-constant-binary-expression, sonarjs/no-redundant-boolean
|
|
@@ -1149,9 +1171,11 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1149
1171
|
object.visible = isVisible
|
|
1150
1172
|
}
|
|
1151
1173
|
} else {
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1174
|
+
// No debug visibility override active — defer to the manager so the
|
|
1175
|
+
// performance-based override distance (set by `recordRenderTime` /
|
|
1176
|
+
// `autoLowerRenderDistance`) is honored, instead of force-showing every
|
|
1177
|
+
// section every frame and clobbering it.
|
|
1178
|
+
this.chunkMeshManager.updateSectionsVisibility()
|
|
1155
1179
|
}
|
|
1156
1180
|
}
|
|
1157
1181
|
|
|
@@ -1322,20 +1346,16 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1322
1346
|
}
|
|
1323
1347
|
|
|
1324
1348
|
updateShowChunksBorder(value: boolean) {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
child.visible = value
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1349
|
+
// Lazily create helpers on the first toggle (they are not created upfront
|
|
1350
|
+
// for sections streamed in while the option was off).
|
|
1351
|
+
this.chunkMeshManager.updateAllBoxHelpers(value)
|
|
1332
1352
|
}
|
|
1333
1353
|
|
|
1334
1354
|
resetWorld() {
|
|
1335
1355
|
super.resetWorld()
|
|
1336
1356
|
|
|
1337
1357
|
this.pendingSectionUpdates.clear()
|
|
1338
|
-
this.
|
|
1358
|
+
this.pendingSectionBufferStartTimes.clear()
|
|
1339
1359
|
this.chunkMeshManager.dispose()
|
|
1340
1360
|
this.chunkMeshManager = new ChunkMeshManager(this, this.scene, this.material, this.worldSizeParams.worldHeight, this.viewDistance)
|
|
1341
1361
|
|
|
@@ -1366,6 +1386,11 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1366
1386
|
textures[key].dispose()
|
|
1367
1387
|
delete textures[key]
|
|
1368
1388
|
}
|
|
1389
|
+
// Sign / head textures moved to ChunkMeshManager.signHeadsRenderer in PR
|
|
1390
|
+
// #16; without invalidating that cache here, sign edits (and any other
|
|
1391
|
+
// block-entity NBT change picked up via setSectionDirty) would re-render
|
|
1392
|
+
// with the stale cached canvas until a full world reset.
|
|
1393
|
+
this.chunkMeshManager.cleanSignChunkTextures(x, z)
|
|
1369
1394
|
}
|
|
1370
1395
|
|
|
1371
1396
|
readdChunks() {
|
|
@@ -1399,6 +1424,13 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1399
1424
|
this.chunkMeshManager.releaseSection(key)
|
|
1400
1425
|
}
|
|
1401
1426
|
}
|
|
1427
|
+
// Drop near-first reveal state and re-check any farther chunks
|
|
1428
|
+
// that may have been blocked by this column.
|
|
1429
|
+
this.chunkMeshManager.onChunkRemovedFromGate(`${x},${z}`)
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
protected onViewerChunkPositionChanged(): void {
|
|
1433
|
+
this.chunkMeshManager.tryRevealPending()
|
|
1402
1434
|
}
|
|
1403
1435
|
|
|
1404
1436
|
setSectionDirty(...args: Parameters<WorldRendererCommon['setSectionDirty']>) {
|
|
@@ -1422,7 +1454,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1422
1454
|
|
|
1423
1455
|
destroy(): void {
|
|
1424
1456
|
this.pendingSectionUpdates.clear()
|
|
1425
|
-
this.
|
|
1457
|
+
this.pendingSectionBufferStartTimes.clear()
|
|
1426
1458
|
this.chunkMeshManager.dispose()
|
|
1427
1459
|
this.disposeModules()
|
|
1428
1460
|
this.fireworksLegacy.destroy()
|
|
@@ -64,6 +64,7 @@ interface CachedBlockModel {
|
|
|
64
64
|
blockProps: Record<string, any>
|
|
65
65
|
models: any // BlockModelPartsResolved
|
|
66
66
|
isCube: boolean
|
|
67
|
+
boundingBox: string
|
|
67
68
|
// Precomputed per-model variant
|
|
68
69
|
modelVariants: Array<{
|
|
69
70
|
model: any
|
|
@@ -86,10 +87,51 @@ interface WasmBlockFaceData {
|
|
|
86
87
|
light_data: number[][]
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
interface WasmGeometryOutput {
|
|
90
|
+
export interface WasmGeometryOutput {
|
|
90
91
|
blocks: WasmBlockFaceData[]
|
|
91
92
|
block_count: number
|
|
92
93
|
block_iterations: number
|
|
94
|
+
/**
|
|
95
|
+
* Per-(x,z) max non-invisible block Y for the meshed column, indexed as
|
|
96
|
+
* `z * 16 + x`. Sentinel value `-32768` = no block in that column.
|
|
97
|
+
*
|
|
98
|
+
* Populated by Rust `Mesher::generate_with_world` (see
|
|
99
|
+
* `wasm-mesher/src/mesher.rs`, field `heightmap`). serde_wasm_bindgen
|
|
100
|
+
* serializes `Vec<i16>` as a plain JS `number[]`, which is why the type
|
|
101
|
+
* here is `ArrayLike<number>` rather than `Int16Array` — the runtime
|
|
102
|
+
* adapter `extractColumnHeightmap` handles both shapes.
|
|
103
|
+
*
|
|
104
|
+
* Used at runtime by `mesherWasm.ts` `processColumnTick`: every column
|
|
105
|
+
* tick the WASM heightmap is extracted via `extractColumnHeightmap` and
|
|
106
|
+
* posted to the main thread as a `'heightmap'` message. JS
|
|
107
|
+
* `computeHeightmap` is now only a fallback (length mismatch / missing
|
|
108
|
+
* field) and a safety-net for empty columns at chunk load. Empty-column
|
|
109
|
+
* semantics are aligned: both Rust and JS use `-32768` (see
|
|
110
|
+
* `EMPTY_COLUMN_HEIGHTMAP_SENTINEL`).
|
|
111
|
+
*/
|
|
112
|
+
heightmap?: ArrayLike<number> | null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Extract a 256-entry Int16Array heightmap from a full-column WASM mesher
|
|
117
|
+
* result, indexed as `z * 16 + x` (matching the JS `computeHeightmap`
|
|
118
|
+
* convention). Returns `null` when the WASM output does not carry a
|
|
119
|
+
* heightmap or carries one of unexpected length — in that case the
|
|
120
|
+
* caller MUST fall back to JS `computeHeightmap` rather than guess.
|
|
121
|
+
*
|
|
122
|
+
* This adapter is the single place that converts Rust's `Vec<i16>` heightmap
|
|
123
|
+
* shape into a transferable typed array. Tests exercise this same adapter so
|
|
124
|
+
* future runtime usage and parity assertions cannot drift apart.
|
|
125
|
+
*/
|
|
126
|
+
export function extractColumnHeightmap(
|
|
127
|
+
wasmOutput: { heightmap?: ArrayLike<number> | null } | null | undefined
|
|
128
|
+
): Int16Array | null {
|
|
129
|
+
const raw = wasmOutput?.heightmap
|
|
130
|
+
if (!raw || raw.length !== 256) return null
|
|
131
|
+
if (raw instanceof Int16Array) return new Int16Array(raw)
|
|
132
|
+
const out = new Int16Array(256)
|
|
133
|
+
for (let i = 0; i < 256; i++) out[i] = raw[i]
|
|
134
|
+
return out
|
|
93
135
|
}
|
|
94
136
|
|
|
95
137
|
/**
|
|
@@ -181,6 +223,7 @@ function getCachedBlockModel(
|
|
|
181
223
|
models,
|
|
182
224
|
modelVariants,
|
|
183
225
|
isCube,
|
|
226
|
+
boundingBox: blockObj.boundingBox,
|
|
184
227
|
}
|
|
185
228
|
|
|
186
229
|
cache.set(cacheKey, cached)
|
|
@@ -697,6 +740,11 @@ export function renderWasmOutputToGeometry(
|
|
|
697
740
|
globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
|
|
698
741
|
}
|
|
699
742
|
|
|
743
|
+
// Mirror JS mesher: doAO = model.ao ?? block.boundingBox !== 'empty'.
|
|
744
|
+
// When false, faces are emitted full-bright without AO/light sampling and without
|
|
745
|
+
// triangle-flip reordering (matches JS `light = 1` and standard winding).
|
|
746
|
+
const doAO = (model as any).ao ?? cachedModel.boundingBox !== 'empty'
|
|
747
|
+
|
|
700
748
|
for (const element of model.elements ?? []) {
|
|
701
749
|
let localMatrix = null as any
|
|
702
750
|
let localShift = null as any
|
|
@@ -723,8 +771,12 @@ export function renderWasmOutputToGeometry(
|
|
|
723
771
|
Math.round(transformedDir[2]),
|
|
724
772
|
]
|
|
725
773
|
const dirKey = `${transformedDirI[0]},${transformedDirI[1]},${transformedDirI[2]}`
|
|
774
|
+
// faceIdx may be undefined for diagonal-rotated faces (e.g. signs at 45/135/225/315 deg).
|
|
775
|
+
// Such faces are not representable in the 6-axis WASM visible_faces / ao_data / light_data
|
|
776
|
+
// arrays. We still emit them (mirrors JS mesher behavior); cullface and AO/light data
|
|
777
|
+
// lookups are skipped, and the model-lighting fallback below derives AO/light by
|
|
778
|
+
// sampling neighbors via transformedDirI (its rounded form, same as for cardinal axes).
|
|
726
779
|
const faceIdx = dirKeyToIndex[dirKey]
|
|
727
|
-
if (faceIdx === undefined) continue
|
|
728
780
|
|
|
729
781
|
const minx = element.from[0]
|
|
730
782
|
const miny = element.from[1]
|
|
@@ -733,13 +785,13 @@ export function renderWasmOutputToGeometry(
|
|
|
733
785
|
const maxy = element.to[1]
|
|
734
786
|
const maxz = element.to[2]
|
|
735
787
|
|
|
736
|
-
if (matchingEFace.cullface) {
|
|
788
|
+
if (matchingEFace.cullface && faceIdx !== undefined) {
|
|
737
789
|
if ((block.visible_faces & (1 << faceIdx)) === 0) {
|
|
738
790
|
continue
|
|
739
791
|
}
|
|
740
792
|
}
|
|
741
793
|
|
|
742
|
-
const faceDataIndex = wasmFaceToDataIndex[faceIdx]
|
|
794
|
+
const faceDataIndex = faceIdx === undefined ? undefined : wasmFaceToDataIndex[faceIdx]
|
|
743
795
|
const aoValuesRaw = faceDataIndex === undefined ? undefined : block.ao_data[faceDataIndex]
|
|
744
796
|
const lightValuesRaw = faceDataIndex === undefined ? undefined : block.light_data[faceDataIndex]
|
|
745
797
|
|
|
@@ -787,8 +839,13 @@ export function renderWasmOutputToGeometry(
|
|
|
787
839
|
|
|
788
840
|
let ao = 3
|
|
789
841
|
let cornerLightResult = 15
|
|
842
|
+
let light: number
|
|
790
843
|
|
|
791
|
-
if (
|
|
844
|
+
if (!doAO) {
|
|
845
|
+
// JS parity: skip AO/light sampling, emit full-bright vertex.
|
|
846
|
+
computedAoValues[cornerIdx] = 3
|
|
847
|
+
light = 1
|
|
848
|
+
} else if (useModelLighting) {
|
|
792
849
|
const cursor = new Vec3(bx, by, bz)
|
|
793
850
|
|
|
794
851
|
const dx = pos[0] * 2 - 1
|
|
@@ -849,9 +906,11 @@ export function renderWasmOutputToGeometry(
|
|
|
849
906
|
cornerLightResult = baseLight * 15
|
|
850
907
|
}
|
|
851
908
|
|
|
852
|
-
|
|
909
|
+
if (doAO) {
|
|
910
|
+
light = (ao + 1) / 4 * (cornerLightResult / 15)
|
|
911
|
+
}
|
|
853
912
|
|
|
854
|
-
colors.push(tint[0] * light
|
|
913
|
+
colors.push(tint[0] * light!, tint[1] * light!, tint[2] * light!)
|
|
855
914
|
|
|
856
915
|
const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5
|
|
857
916
|
const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5
|
|
@@ -865,7 +924,7 @@ export function renderWasmOutputToGeometry(
|
|
|
865
924
|
const aoValues = computedAoValues
|
|
866
925
|
|
|
867
926
|
let tri1: number[], tri2: number[]
|
|
868
|
-
if (aoValues[0] + aoValues[3] >= aoValues[1] + aoValues[2]) {
|
|
927
|
+
if (doAO && aoValues[0] + aoValues[3] >= aoValues[1] + aoValues[2]) {
|
|
869
928
|
tri1 = [baseIndex, baseIndex + 3, baseIndex + 2]
|
|
870
929
|
tri2 = [baseIndex, baseIndex + 1, baseIndex + 3]
|
|
871
930
|
} else {
|
|
@@ -915,15 +974,101 @@ export function renderWasmOutputToGeometry(
|
|
|
915
974
|
},
|
|
916
975
|
}
|
|
917
976
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
977
|
+
log(`[WASM] Final geometry summary:`)
|
|
978
|
+
log(`[WASM] Total vertices: ${positions.length / 3}`)
|
|
979
|
+
log(`[WASM] Total triangles: ${indices.length / 3}`)
|
|
980
|
+
log(`[WASM] Positions: [${positions.slice(0, 12).join(',')}...] (first 4 vertices)`)
|
|
981
|
+
log(`[WASM] Indices: [${indices.slice(0, 12).join(',')}...] (first 2 faces)`)
|
|
923
982
|
|
|
924
983
|
return result
|
|
925
984
|
}
|
|
926
985
|
|
|
986
|
+
/**
|
|
987
|
+
* Split a single full-column WASM mesher result into per-section
|
|
988
|
+
* `ExportedSection` outputs by filtering `wasmResult.blocks` per requested
|
|
989
|
+
* section's Y range and invoking `renderWasmOutputToGeometry` once per
|
|
990
|
+
* section.
|
|
991
|
+
*
|
|
992
|
+
* Why split at the block level (and not after geometry generation):
|
|
993
|
+
* - Liquids (water/lava), signs/heads/banners metadata, AO/light arrays
|
|
994
|
+
* and index numbering are computed inside `renderWasmOutputToGeometry`.
|
|
995
|
+
* Splitting *finished* vertex/index buffers would silently break those.
|
|
996
|
+
* - Filtering blocks by Y range and re-running the post-processor per
|
|
997
|
+
* section keeps the output identical to the existing per-section path.
|
|
998
|
+
*
|
|
999
|
+
* Y=15/16 (and any other inter-section) seam handling:
|
|
1000
|
+
* - The Rust mesher produced `wasmResult` over the full column, so each
|
|
1001
|
+
* block's `visible_faces`, `ao_data` and `light_data` already account
|
|
1002
|
+
* for its true neighbors — including the block above at the section
|
|
1003
|
+
* seam (e.g. a Y=15 top face is correctly suppressed when Y=16 is
|
|
1004
|
+
* opaque, even though Y=16 lives in the next render section).
|
|
1005
|
+
* - This helper therefore does NOT need to widen the per-section block
|
|
1006
|
+
* window: a strict `[sy*sectionHeight, sy*sectionHeight + sectionHeight)`
|
|
1007
|
+
* filter on `block.position[1]` is sufficient. The neighbor information
|
|
1008
|
+
* is already baked into each block's per-face mask/AO/light arrays.
|
|
1009
|
+
*
|
|
1010
|
+
* Empty sections: sections with no blocks in range still get a call into
|
|
1011
|
+
* `renderWasmOutputToGeometry` with an empty `blocks` array, so the
|
|
1012
|
+
* returned `ExportedSection` shape matches what the per-section path
|
|
1013
|
+
* produces for an empty section (empty positions/normals/colors/uvs/
|
|
1014
|
+
* indices arrays).
|
|
1015
|
+
*
|
|
1016
|
+
* Note: this pure helper is not gated internally; callers decide whether
|
|
1017
|
+
* column meshing is enabled.
|
|
1018
|
+
*/
|
|
1019
|
+
export function splitColumnWasmOutputToSections(
|
|
1020
|
+
fullColumnOutput: WasmGeometryOutput,
|
|
1021
|
+
requestedSectionKeys: Array<{ x: number, y: number, z: number }>,
|
|
1022
|
+
ctx: { version: string, world?: World, sectionHeight?: number }
|
|
1023
|
+
): Map<string, { exported: ExportedSection, blocksCount: number }> {
|
|
1024
|
+
const { version, world } = ctx
|
|
1025
|
+
const sectionHeight = ctx.sectionHeight ?? 16
|
|
1026
|
+
|
|
1027
|
+
// Bucket blocks by section Y once, so we don't re-scan the full column
|
|
1028
|
+
// for every requested section. Bucket key = section-relative chunk Y
|
|
1029
|
+
// (i.e. floor(by / sectionHeight)).
|
|
1030
|
+
const blocksByChunkY = new Map<number, WasmBlockFaceData[]>()
|
|
1031
|
+
for (const block of fullColumnOutput.blocks) {
|
|
1032
|
+
const by = block.position[1]
|
|
1033
|
+
const chunkY = Math.floor(by / sectionHeight)
|
|
1034
|
+
let bucket = blocksByChunkY.get(chunkY)
|
|
1035
|
+
if (!bucket) {
|
|
1036
|
+
bucket = []
|
|
1037
|
+
blocksByChunkY.set(chunkY, bucket)
|
|
1038
|
+
}
|
|
1039
|
+
bucket.push(block)
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
const out = new Map<string, { exported: ExportedSection, blocksCount: number }>()
|
|
1043
|
+
for (const { x, y, z } of requestedSectionKeys) {
|
|
1044
|
+
// `y` here is the section's world-Y origin (multiple of sectionHeight),
|
|
1045
|
+
// matching the convention used by `mesherWasm.ts` (section keys are
|
|
1046
|
+
// `${chunkX*16},${sectionY},${chunkZ*16}` with sectionY a world-Y
|
|
1047
|
+
// multiple of 16). Translate to chunk-Y bucket index.
|
|
1048
|
+
const chunkY = Math.floor(y / sectionHeight)
|
|
1049
|
+
const sectionBlocks = blocksByChunkY.get(chunkY) ?? []
|
|
1050
|
+
|
|
1051
|
+
const sectionView: WasmGeometryOutput = {
|
|
1052
|
+
blocks: sectionBlocks,
|
|
1053
|
+
block_count: sectionBlocks.length,
|
|
1054
|
+
block_iterations: fullColumnOutput.block_iterations,
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const sectionKey = `${x},${y},${z}`
|
|
1058
|
+
const sectionPosition = { x: x + 8, y: y + 8, z: z + 8 }
|
|
1059
|
+
const exported = renderWasmOutputToGeometry(
|
|
1060
|
+
sectionView,
|
|
1061
|
+
version,
|
|
1062
|
+
sectionKey,
|
|
1063
|
+
sectionPosition,
|
|
1064
|
+
world
|
|
1065
|
+
)
|
|
1066
|
+
out.set(sectionKey, { exported, blocksCount: sectionBlocks.length })
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
return out
|
|
1070
|
+
}
|
|
1071
|
+
|
|
927
1072
|
/**
|
|
928
1073
|
* Convert WASM output to exported geometry format
|
|
929
1074
|
*/
|
package/wasm/wasm_mesher.d.ts
CHANGED
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
* Input: Serialized chunk data as TypedArrays
|
|
8
8
|
* Output: Geometry data (positions, normals, colors, uvs, indices)
|
|
9
9
|
*/
|
|
10
|
-
export function generate_geometry(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
10
|
+
export function generate_geometry(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, section_data_start_y: number, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
11
11
|
|
|
12
|
-
export function generate_geometry_multi(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, chunk_xs: Int32Array, chunk_zs: Int32Array, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
12
|
+
export function generate_geometry_multi(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, section_data_start_y: number, chunk_xs: Int32Array, chunk_zs: Int32Array, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
13
13
|
|
|
14
14
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
15
15
|
|
|
16
16
|
export interface InitOutput {
|
|
17
17
|
readonly memory: WebAssembly.Memory;
|
|
18
|
-
readonly generate_geometry: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number) => any;
|
|
19
|
-
readonly generate_geometry_multi: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number, b1: number, c1: number, d1: number, e1: number) => any;
|
|
18
|
+
readonly generate_geometry: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number, b1: number) => any;
|
|
19
|
+
readonly generate_geometry_multi: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number, b1: number, c1: number, d1: number, e1: number, f1: number) => any;
|
|
20
20
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
21
21
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
22
22
|
readonly __wbindgen_externrefs: WebAssembly.Table;
|
package/wasm/wasm_mesher.js
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
let wasm;
|
|
2
2
|
|
|
3
|
-
function _assertBoolean(n) {
|
|
4
|
-
if (typeof(n) !== 'boolean') {
|
|
5
|
-
throw new Error(`expected a boolean argument, found ${typeof(n)}`);
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function _assertNum(n) {
|
|
10
|
-
if (typeof(n) !== 'number') throw new Error(`expected a number argument, found ${typeof(n)}`);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
3
|
function debugString(val) {
|
|
14
4
|
// primitive types
|
|
15
5
|
const type = typeof val;
|
|
@@ -112,22 +102,6 @@ function getUint8ArrayMemory0() {
|
|
|
112
102
|
return cachedUint8ArrayMemory0;
|
|
113
103
|
}
|
|
114
104
|
|
|
115
|
-
function logError(f, args) {
|
|
116
|
-
try {
|
|
117
|
-
return f.apply(this, args);
|
|
118
|
-
} catch (e) {
|
|
119
|
-
let error = (function () {
|
|
120
|
-
try {
|
|
121
|
-
return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString();
|
|
122
|
-
} catch(_) {
|
|
123
|
-
return "<failed to stringify thrown value>";
|
|
124
|
-
}
|
|
125
|
-
}());
|
|
126
|
-
console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error);
|
|
127
|
-
throw e;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
105
|
function passArray16ToWasm0(arg, malloc) {
|
|
132
106
|
const ptr = malloc(arg.length * 2, 2) >>> 0;
|
|
133
107
|
getUint16ArrayMemory0().set(arg, ptr / 2);
|
|
@@ -150,7 +124,6 @@ function passArray8ToWasm0(arg, malloc) {
|
|
|
150
124
|
}
|
|
151
125
|
|
|
152
126
|
function passStringToWasm0(arg, malloc, realloc) {
|
|
153
|
-
if (typeof(arg) !== 'string') throw new Error(`expected a string argument, found ${typeof(arg)}`);
|
|
154
127
|
if (realloc === undefined) {
|
|
155
128
|
const buf = cachedTextEncoder.encode(arg);
|
|
156
129
|
const ptr = malloc(buf.length, 1) >>> 0;
|
|
@@ -178,7 +151,7 @@ function passStringToWasm0(arg, malloc, realloc) {
|
|
|
178
151
|
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
179
152
|
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
180
153
|
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
181
|
-
|
|
154
|
+
|
|
182
155
|
offset += ret.written;
|
|
183
156
|
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
184
157
|
}
|
|
@@ -227,6 +200,7 @@ let WASM_VECTOR_LEN = 0;
|
|
|
227
200
|
* @param {number} section_height
|
|
228
201
|
* @param {number} world_min_y
|
|
229
202
|
* @param {number} world_max_y
|
|
203
|
+
* @param {number} section_data_start_y
|
|
230
204
|
* @param {Uint16Array} block_states
|
|
231
205
|
* @param {Uint8Array} block_light
|
|
232
206
|
* @param {Uint8Array} sky_light
|
|
@@ -241,13 +215,7 @@ let WASM_VECTOR_LEN = 0;
|
|
|
241
215
|
* @param {number} sky_light_value
|
|
242
216
|
* @returns {any}
|
|
243
217
|
*/
|
|
244
|
-
export function generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
245
|
-
_assertNum(section_x);
|
|
246
|
-
_assertNum(section_y);
|
|
247
|
-
_assertNum(section_z);
|
|
248
|
-
_assertNum(section_height);
|
|
249
|
-
_assertNum(world_min_y);
|
|
250
|
-
_assertNum(world_max_y);
|
|
218
|
+
export function generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
251
219
|
const ptr0 = passArray16ToWasm0(block_states, wasm.__wbindgen_malloc);
|
|
252
220
|
const len0 = WASM_VECTOR_LEN;
|
|
253
221
|
const ptr1 = passArray8ToWasm0(block_light, wasm.__wbindgen_malloc);
|
|
@@ -266,10 +234,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
|
|
|
266
234
|
const len7 = WASM_VECTOR_LEN;
|
|
267
235
|
const ptr8 = passArray16ToWasm0(occluding_blocks, wasm.__wbindgen_malloc);
|
|
268
236
|
const len8 = WASM_VECTOR_LEN;
|
|
269
|
-
|
|
270
|
-
_assertBoolean(smooth_lighting);
|
|
271
|
-
_assertNum(sky_light_value);
|
|
272
|
-
const ret = wasm.generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, enable_lighting, smooth_lighting, sky_light_value);
|
|
237
|
+
const ret = wasm.generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, enable_lighting, smooth_lighting, sky_light_value);
|
|
273
238
|
return ret;
|
|
274
239
|
}
|
|
275
240
|
|
|
@@ -280,6 +245,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
|
|
|
280
245
|
* @param {number} section_height
|
|
281
246
|
* @param {number} world_min_y
|
|
282
247
|
* @param {number} world_max_y
|
|
248
|
+
* @param {number} section_data_start_y
|
|
283
249
|
* @param {Int32Array} chunk_xs
|
|
284
250
|
* @param {Int32Array} chunk_zs
|
|
285
251
|
* @param {Uint16Array} block_states
|
|
@@ -296,13 +262,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
|
|
|
296
262
|
* @param {number} sky_light_value
|
|
297
263
|
* @returns {any}
|
|
298
264
|
*/
|
|
299
|
-
export function generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, chunk_xs, chunk_zs, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
300
|
-
_assertNum(section_x);
|
|
301
|
-
_assertNum(section_y);
|
|
302
|
-
_assertNum(section_z);
|
|
303
|
-
_assertNum(section_height);
|
|
304
|
-
_assertNum(world_min_y);
|
|
305
|
-
_assertNum(world_max_y);
|
|
265
|
+
export function generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, chunk_xs, chunk_zs, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
306
266
|
const ptr0 = passArray32ToWasm0(chunk_xs, wasm.__wbindgen_malloc);
|
|
307
267
|
const len0 = WASM_VECTOR_LEN;
|
|
308
268
|
const ptr1 = passArray32ToWasm0(chunk_zs, wasm.__wbindgen_malloc);
|
|
@@ -325,10 +285,7 @@ export function generate_geometry_multi(section_x, section_y, section_z, section
|
|
|
325
285
|
const len9 = WASM_VECTOR_LEN;
|
|
326
286
|
const ptr10 = passArray16ToWasm0(occluding_blocks, wasm.__wbindgen_malloc);
|
|
327
287
|
const len10 = WASM_VECTOR_LEN;
|
|
328
|
-
|
|
329
|
-
_assertBoolean(smooth_lighting);
|
|
330
|
-
_assertNum(sky_light_value);
|
|
331
|
-
const ret = wasm.generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, ptr9, len9, ptr10, len10, enable_lighting, smooth_lighting, sky_light_value);
|
|
288
|
+
const ret = wasm.generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, ptr9, len9, ptr10, len10, enable_lighting, smooth_lighting, sky_light_value);
|
|
332
289
|
return ret;
|
|
333
290
|
}
|
|
334
291
|
|
|
@@ -367,10 +324,10 @@ async function __wbg_load(module, imports) {
|
|
|
367
324
|
function __wbg_get_imports() {
|
|
368
325
|
const imports = {};
|
|
369
326
|
imports.wbg = {};
|
|
370
|
-
imports.wbg.__wbg_Error_52673b7de5a0ca89 = function(
|
|
327
|
+
imports.wbg.__wbg_Error_52673b7de5a0ca89 = function(arg0, arg1) {
|
|
371
328
|
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
372
329
|
return ret;
|
|
373
|
-
}
|
|
330
|
+
};
|
|
374
331
|
imports.wbg.__wbg___wbindgen_debug_string_adfb662ae34724b6 = function(arg0, arg1) {
|
|
375
332
|
const ret = debugString(arg1);
|
|
376
333
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
@@ -381,35 +338,35 @@ function __wbg_get_imports() {
|
|
|
381
338
|
imports.wbg.__wbg___wbindgen_throw_dd24417ed36fc46e = function(arg0, arg1) {
|
|
382
339
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
383
340
|
};
|
|
384
|
-
imports.wbg.__wbg_new_1ba21ce319a06297 = function() {
|
|
341
|
+
imports.wbg.__wbg_new_1ba21ce319a06297 = function() {
|
|
385
342
|
const ret = new Object();
|
|
386
343
|
return ret;
|
|
387
|
-
}
|
|
388
|
-
imports.wbg.__wbg_new_25f239778d6112b9 = function() {
|
|
344
|
+
};
|
|
345
|
+
imports.wbg.__wbg_new_25f239778d6112b9 = function() {
|
|
389
346
|
const ret = new Array();
|
|
390
347
|
return ret;
|
|
391
|
-
}
|
|
392
|
-
imports.wbg.__wbg_set_3f1d0b984ed272ed = function(
|
|
348
|
+
};
|
|
349
|
+
imports.wbg.__wbg_set_3f1d0b984ed272ed = function(arg0, arg1, arg2) {
|
|
393
350
|
arg0[arg1] = arg2;
|
|
394
|
-
}
|
|
395
|
-
imports.wbg.__wbg_set_7df433eea03a5c14 = function(
|
|
351
|
+
};
|
|
352
|
+
imports.wbg.__wbg_set_7df433eea03a5c14 = function(arg0, arg1, arg2) {
|
|
396
353
|
arg0[arg1 >>> 0] = arg2;
|
|
397
|
-
}
|
|
398
|
-
imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(
|
|
354
|
+
};
|
|
355
|
+
imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(arg0, arg1) {
|
|
399
356
|
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
400
357
|
const ret = getStringFromWasm0(arg0, arg1);
|
|
401
358
|
return ret;
|
|
402
|
-
}
|
|
403
|
-
imports.wbg.__wbindgen_cast_4625c577ab2ec9ee = function(
|
|
359
|
+
};
|
|
360
|
+
imports.wbg.__wbindgen_cast_4625c577ab2ec9ee = function(arg0) {
|
|
404
361
|
// Cast intrinsic for `U64 -> Externref`.
|
|
405
362
|
const ret = BigInt.asUintN(64, arg0);
|
|
406
363
|
return ret;
|
|
407
|
-
}
|
|
408
|
-
imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(
|
|
364
|
+
};
|
|
365
|
+
imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
|
|
409
366
|
// Cast intrinsic for `F64 -> Externref`.
|
|
410
367
|
const ret = arg0;
|
|
411
368
|
return ret;
|
|
412
|
-
}
|
|
369
|
+
};
|
|
413
370
|
imports.wbg.__wbindgen_init_externref_table = function() {
|
|
414
371
|
const table = wasm.__wbindgen_externrefs;
|
|
415
372
|
const offset = table.grow(4);
|