minecraft-renderer 0.1.79 → 0.1.81
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 +66 -26
- package/dist/mesher.js +36 -36
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -217
- package/dist/minecraft-renderer.js +66 -66
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +450 -450
- package/package.json +5 -2
- package/src/bundler/bundlePrepare.ts +3 -8
- package/src/graphicsBackend/appViewer.ts +10 -7
- package/src/graphicsBackend/config.ts +1 -5
- package/src/graphicsBackend/playerState.ts +35 -34
- package/src/graphicsBackend/preloadWorkers.ts +43 -41
- package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
- package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
- package/src/graphicsBackend/types.ts +2 -2
- package/src/index.ts +6 -27
- package/src/lib/DebugGui.ts +34 -31
- package/src/lib/animationController.ts +9 -9
- package/src/lib/bakeLegacyLight.ts +1 -6
- package/src/lib/bindAbortableListener.test.ts +32 -12
- package/src/lib/bindAbortableListener.ts +14 -6
- package/src/lib/blockEntityLightRegistry.ts +11 -20
- package/src/lib/blockEntityLighting.test.ts +1 -6
- package/src/lib/blockEntityLighting.ts +5 -5
- package/src/lib/buildSharedConfig.mjs +4 -4
- package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
- package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
- package/src/lib/cameraBobbing.ts +1 -1
- package/src/lib/canvas2DOverlay.example.ts +13 -33
- package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
- package/src/lib/canvas2DOverlay.ts +28 -47
- package/src/lib/cleanupDecorator.ts +2 -2
- package/src/lib/createPlayerObject.test.ts +2 -7
- package/src/lib/createPlayerObject.ts +18 -25
- package/src/lib/frameTimingCollector.ts +2 -5
- package/src/lib/guiRenderer.ts +57 -42
- package/src/lib/items.ts +15 -9
- package/src/lib/mesherlogReader.ts +5 -6
- package/src/lib/simpleUtils.ts +5 -5
- package/src/lib/skyLight.ts +3 -3
- package/src/lib/smoothSwitcher.ts +11 -18
- package/src/lib/ui/newStats.ts +10 -12
- package/src/lib/utils/proxy.ts +7 -1
- package/src/lib/utils/skins.ts +4 -4
- package/src/lib/utils.ts +1 -1
- package/src/lib/workerMessageSanitize.ts +5 -12
- package/src/lib/workerProxy.ts +52 -42
- package/src/lib/workerSyncOps.test.ts +58 -41
- package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
- package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
- package/src/lib/worldrendererCommon.ts +349 -211
- package/src/mesher-legacy/mesher.ts +9 -4
- package/src/mesher-legacy/test/a.ts +1 -1
- package/src/mesher-legacy/test/mesherTester.ts +2 -2
- package/src/mesher-legacy/test/playground.ts +1 -1
- package/src/mesher-legacy/test/run/test-js.ts +1 -1
- package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
- package/src/mesher-legacy/test/test-perf.ts +1 -1
- package/src/mesher-legacy/test/tests.test.ts +2 -2
- package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
- package/src/mesher-shared/blockEntityMetadata.ts +28 -19
- package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
- package/src/mesher-shared/computeHeightmap.ts +2 -4
- package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
- package/src/mesher-shared/faceOcclusion.ts +324 -0
- package/src/mesher-shared/models.ts +80 -131
- package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
- package/src/mesher-shared/shared.ts +46 -46
- package/src/mesher-shared/standaloneRenderer.ts +40 -44
- package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
- package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
- package/src/mesher-shared/vertexShading.ts +2 -11
- package/src/mesher-shared/world.ts +19 -19
- package/src/mesher-shared/worldLighting.test.ts +2 -2
- package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
- package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
- package/src/performanceMonitor/index.ts +1 -5
- package/src/performanceMonitor/types.ts +1 -1
- package/src/playerState/playerState.ts +55 -50
- package/src/playerState/types.ts +2 -8
- package/src/playground/allEntitiesDebug.ts +19 -16
- package/src/playground/baseScene.ts +29 -32
- package/src/playground/mobileControls.tsx +133 -129
- package/src/playground/playground.html +76 -73
- package/src/playground/playground.ts +14 -1
- package/src/playground/playgroundUi.tsx +100 -74
- package/src/playground/reactUtils.ts +3 -7
- package/src/playground/scenes/entities.ts +10 -7
- package/src/playground/scenes/frequentUpdates.ts +5 -5
- package/src/playground/scenes/geometryExport.ts +6 -20
- package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
- package/src/playground/scenes/index.ts +1 -1
- package/src/playground/scenes/lightingStarfield.ts +18 -12
- package/src/playground/scenes/main.ts +15 -11
- package/src/playground/scenes/partialBlockCulling.ts +31 -0
- package/src/playground/scenes/railsCobweb.ts +1 -1
- package/src/playground/scenes/rotationIssue.ts +1 -1
- package/src/playground/scenes/slabsOptimization.ts +1 -2
- package/src/playground/scenes/transparencyIssue.ts +1 -1
- package/src/playground/shared.ts +2 -2
- package/src/resourcesManager/resourcesManager.ts +29 -54
- package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
- package/src/shims/minecraftData.ts +70 -24
- package/src/sign-renderer/index.html +10 -12
- package/src/sign-renderer/index.ts +29 -29
- package/src/sign-renderer/playground.ts +22 -15
- package/src/sign-renderer/tests.test.ts +16 -13
- package/src/sign-renderer/vite.config.ts +2 -2
- package/src/three/appShared.ts +46 -25
- package/src/three/bannerRenderer.ts +33 -61
- package/src/three/cameraCollisionBlockCache.ts +156 -0
- package/src/three/cameraCollisionSolidity.ts +50 -0
- package/src/three/cameraShake.ts +15 -6
- package/src/three/chunkMeshManager.ts +223 -390
- package/src/three/cinimaticScript.ts +26 -15
- package/src/three/cubeDrawSpans.ts +27 -37
- package/src/three/cubeMultiDraw.ts +9 -22
- package/src/three/documentRenderer.ts +15 -18
- package/src/three/entities.ts +175 -150
- package/src/three/entity/EntityMesh.ts +114 -108
- package/src/three/entity/animations.js +3 -3
- package/src/three/entity/armorModels.ts +15 -15
- package/src/three/entity/gltfAnimationUtils.ts +2 -5
- package/src/three/fireworks.ts +34 -32
- package/src/three/fireworksRenderer.ts +32 -29
- package/src/three/globalBlockBuffer.ts +167 -100
- package/src/three/globalLegacyBuffer.ts +248 -264
- package/src/three/graphicsBackendBase.ts +19 -25
- package/src/three/graphicsBackendOffThread.ts +12 -15
- package/src/three/hand.ts +21 -21
- package/src/three/handLegacy.ts +3 -13
- package/src/three/holdingBlock.ts +116 -79
- package/src/three/holdingBlockFactory.ts +1 -4
- package/src/three/holdingBlockItemIdentity.test.ts +25 -17
- package/src/three/holdingBlockItemIdentity.ts +9 -6
- package/src/three/holdingBlockLegacy.ts +113 -132
- package/src/three/itemMesh.ts +20 -29
- package/src/three/legacyMultiDraw.ts +10 -16
- package/src/three/legacySectionCull.ts +8 -14
- package/src/three/menuBackground/activeView.ts +1 -4
- package/src/three/menuBackground/assetUrl.ts +1 -1
- package/src/three/menuBackground/classic.ts +4 -12
- package/src/three/menuBackground/gpuPreference.ts +1 -3
- package/src/three/menuBackground/index.ts +2 -11
- package/src/three/menuBackground/renderer.ts +1 -5
- package/src/three/menuBackground/types.ts +1 -4
- package/src/three/menuBackground/v2.ts +196 -96
- package/src/three/menuBackground/v2Meta.ts +3 -3
- package/src/three/menuBackground/worldBlocks.ts +37 -35
- package/src/three/modules/blockBreakParticles.ts +59 -28
- package/src/three/modules/cameraBobbing.ts +3 -6
- package/src/three/modules/index.ts +1 -1
- package/src/three/modules/rain.ts +10 -23
- package/src/three/modules/sciFiWorldReveal.ts +11 -25
- package/src/three/modules/starfield.ts +7 -13
- package/src/three/renderSlot.ts +28 -16
- package/src/three/rendererModuleSystem.ts +1 -3
- package/src/three/sceneOrigin.ts +96 -33
- package/src/three/sectionRaycastAabb.ts +24 -110
- package/src/three/shaderCubeMesh.ts +6 -17
- package/src/three/shaders/cubeBlockShader.ts +85 -96
- package/src/three/shaders/legacyBlockShader.ts +21 -43
- package/src/three/shaders/textureIndexMapping.ts +89 -95
- package/src/three/shaders/tintPalette.ts +156 -170
- package/src/three/signTextureCache.ts +9 -12
- package/src/three/skyboxRenderer.ts +62 -70
- package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -64
- package/src/three/tests/cubeDrawSpans.test.ts +55 -25
- package/src/three/tests/globalBlockBuffer.test.ts +217 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
- package/src/three/tests/legacyMultiDraw.test.ts +8 -29
- package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
- package/src/three/tests/signTextureCache.test.ts +4 -4
- package/src/three/thirdPersonVoxelRaycast.ts +120 -0
- package/src/three/threeJsMedia.ts +55 -72
- package/src/three/threeJsParticles.ts +32 -41
- package/src/three/threeJsSound.ts +3 -3
- package/src/three/threeJsUtils.ts +3 -3
- package/src/three/threeWorker.ts +2 -2
- package/src/three/waypointSprite.ts +55 -82
- package/src/three/waypoints.ts +20 -23
- package/src/three/world/cursorBlock.ts +25 -12
- package/src/three/world/vr.ts +11 -17
- package/src/three/worldGeometryExport.ts +15 -34
- package/src/three/worldRendererThree.ts +144 -166
- package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
- package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
- package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
- package/src/wasm-mesher/tests/cameraCollisionBlockCache.test.ts +82 -0
- package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
- package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
- package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
- package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +1 -93
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
- package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
- package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
- package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
- package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
- package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
- package/src/worldView/worldView.spiral.test.ts +1 -1
- package/src/worldView/worldView.ts +34 -39
- package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
2
|
import { expect, test, vi } from 'vitest'
|
|
3
|
-
import {
|
|
4
|
-
createLegacyMultiDrawScratch,
|
|
5
|
-
detectLegacyMultiDrawCaps,
|
|
6
|
-
drawLegacySpans,
|
|
7
|
-
} from '../legacyMultiDraw'
|
|
3
|
+
import { createLegacyMultiDrawScratch, detectLegacyMultiDrawCaps, drawLegacySpans } from '../legacyMultiDraw'
|
|
8
4
|
|
|
9
|
-
function makeMockGl
|
|
5
|
+
function makeMockGl(opts?: { multiDraw?: boolean }): WebGL2RenderingContext {
|
|
10
6
|
const multiDrawElementsWEBGL = vi.fn()
|
|
11
7
|
const drawElements = vi.fn()
|
|
12
8
|
return {
|
|
@@ -18,7 +14,7 @@ function makeMockGl (opts?: { multiDraw?: boolean }): WebGL2RenderingContext {
|
|
|
18
14
|
}
|
|
19
15
|
return null
|
|
20
16
|
},
|
|
21
|
-
drawElements
|
|
17
|
+
drawElements
|
|
22
18
|
} as unknown as WebGL2RenderingContext
|
|
23
19
|
}
|
|
24
20
|
|
|
@@ -42,7 +38,7 @@ test('drawLegacySpans: tier A uses multiDrawElementsWEBGL with byte offsets', ()
|
|
|
42
38
|
const scratch = createLegacyMultiDrawScratch()
|
|
43
39
|
const spans = [
|
|
44
40
|
{ indexStart: 12, indexCount: 6 },
|
|
45
|
-
{ indexStart: 30, indexCount: 12 }
|
|
41
|
+
{ indexStart: 30, indexCount: 12 }
|
|
46
42
|
]
|
|
47
43
|
|
|
48
44
|
drawLegacySpans(gl, caps, spans, scratch)
|
|
@@ -54,13 +50,7 @@ test('drawLegacySpans: tier A uses multiDrawElementsWEBGL with byte offsets', ()
|
|
|
54
50
|
|
|
55
51
|
const ext = caps.ext as { multiDrawElementsWEBGL: ReturnType<typeof vi.fn> }
|
|
56
52
|
expect(ext.multiDrawElementsWEBGL).toHaveBeenCalledTimes(1)
|
|
57
|
-
expect(ext.multiDrawElementsWEBGL).toHaveBeenCalledWith(
|
|
58
|
-
gl.TRIANGLES,
|
|
59
|
-
scratch.counts, 0,
|
|
60
|
-
gl.UNSIGNED_INT,
|
|
61
|
-
scratch.offsets, 0,
|
|
62
|
-
2,
|
|
63
|
-
)
|
|
53
|
+
expect(ext.multiDrawElementsWEBGL).toHaveBeenCalledWith(gl.TRIANGLES, scratch.counts, 0, gl.UNSIGNED_INT, scratch.offsets, 0, 2)
|
|
64
54
|
})
|
|
65
55
|
|
|
66
56
|
test('drawLegacySpans: tier B loops drawElements per span', () => {
|
|
@@ -71,12 +61,7 @@ test('drawLegacySpans: tier B loops drawElements per span', () => {
|
|
|
71
61
|
|
|
72
62
|
drawLegacySpans(gl, caps, spans, scratch)
|
|
73
63
|
|
|
74
|
-
expect((gl as unknown as { drawElements: ReturnType<typeof vi.fn> }).drawElements).toHaveBeenCalledWith(
|
|
75
|
-
gl.TRIANGLES,
|
|
76
|
-
6,
|
|
77
|
-
gl.UNSIGNED_INT,
|
|
78
|
-
16,
|
|
79
|
-
)
|
|
64
|
+
expect((gl as unknown as { drawElements: ReturnType<typeof vi.fn> }).drawElements).toHaveBeenCalledWith(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 16)
|
|
80
65
|
})
|
|
81
66
|
|
|
82
67
|
test('drawLegacySpans: grows scratch past MAX_OPAQUE_SPANS for uncapped blend sets', () => {
|
|
@@ -88,7 +73,7 @@ test('drawLegacySpans: grows scratch past MAX_OPAQUE_SPANS for uncapped blend se
|
|
|
88
73
|
const spanCount = 70
|
|
89
74
|
const spans = Array.from({ length: spanCount }, (_, i) => ({
|
|
90
75
|
indexStart: i * 6,
|
|
91
|
-
indexCount: 6
|
|
76
|
+
indexCount: 6
|
|
92
77
|
}))
|
|
93
78
|
|
|
94
79
|
drawLegacySpans(gl, caps, spans, scratch)
|
|
@@ -99,11 +84,5 @@ test('drawLegacySpans: grows scratch past MAX_OPAQUE_SPANS for uncapped blend se
|
|
|
99
84
|
expect(scratch.offsets[69]).toBe(69 * 6 * 4)
|
|
100
85
|
|
|
101
86
|
const ext = caps.ext as { multiDrawElementsWEBGL: ReturnType<typeof vi.fn> }
|
|
102
|
-
expect(ext.multiDrawElementsWEBGL).toHaveBeenCalledWith(
|
|
103
|
-
gl.TRIANGLES,
|
|
104
|
-
scratch.counts, 0,
|
|
105
|
-
gl.UNSIGNED_INT,
|
|
106
|
-
scratch.offsets, 0,
|
|
107
|
-
spanCount,
|
|
108
|
-
)
|
|
87
|
+
expect(ext.multiDrawElementsWEBGL).toHaveBeenCalledWith(gl.TRIANGLES, scratch.counts, 0, gl.UNSIGNED_INT, scratch.offsets, 0, spanCount)
|
|
109
88
|
})
|
|
@@ -3,7 +3,7 @@ import { test, expect, vi, afterEach } from 'vitest'
|
|
|
3
3
|
import * as THREE from 'three'
|
|
4
4
|
|
|
5
5
|
vi.mock('../entity/EntityMesh', () => ({
|
|
6
|
-
getMesh: vi.fn()
|
|
6
|
+
getMesh: vi.fn()
|
|
7
7
|
}))
|
|
8
8
|
|
|
9
9
|
import { ChunkMeshManager } from '../chunkMeshManager'
|
|
@@ -11,13 +11,8 @@ import type { GlobalLegacyBuffer } from '../globalLegacyBuffer'
|
|
|
11
11
|
import type { WorldRendererThree } from '../worldRendererThree'
|
|
12
12
|
import type { MesherGeometryOutput } from '../../mesher-shared/shared'
|
|
13
13
|
|
|
14
|
-
function makeQuadArrays
|
|
15
|
-
const positions = new Float32Array([
|
|
16
|
-
-1, -1, -1,
|
|
17
|
-
-1, 1, -1,
|
|
18
|
-
-1, 1, 1,
|
|
19
|
-
-1, -1, 1,
|
|
20
|
-
])
|
|
14
|
+
function makeQuadArrays() {
|
|
15
|
+
const positions = new Float32Array([-1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1])
|
|
21
16
|
const colors = new Float32Array(12).fill(1)
|
|
22
17
|
const skyLights = new Float32Array(4).fill(1)
|
|
23
18
|
const blockLights = new Float32Array(4).fill(0)
|
|
@@ -26,7 +21,7 @@ function makeQuadArrays () {
|
|
|
26
21
|
return { positions, colors, skyLights, blockLights, uvs, indices }
|
|
27
22
|
}
|
|
28
23
|
|
|
29
|
-
function makeBlendOnlyGeometry
|
|
24
|
+
function makeBlendOnlyGeometry(): MesherGeometryOutput {
|
|
30
25
|
const blend = makeQuadArrays()
|
|
31
26
|
return {
|
|
32
27
|
sectionYNumber: 0,
|
|
@@ -62,12 +57,12 @@ function makeBlendOnlyGeometry (): MesherGeometryOutput {
|
|
|
62
57
|
skyLights: blend.skyLights,
|
|
63
58
|
blockLights: blend.blockLights,
|
|
64
59
|
uvs: blend.uvs,
|
|
65
|
-
indices: blend.indices
|
|
66
|
-
}
|
|
60
|
+
indices: blend.indices
|
|
61
|
+
}
|
|
67
62
|
}
|
|
68
63
|
}
|
|
69
64
|
|
|
70
|
-
function makeOpaqueOnlyGeometry
|
|
65
|
+
function makeOpaqueOnlyGeometry(sx = 8, sy = 8, sz = 8): MesherGeometryOutput {
|
|
71
66
|
const opaque = makeQuadArrays()
|
|
72
67
|
return {
|
|
73
68
|
sectionYNumber: 0,
|
|
@@ -95,11 +90,11 @@ function makeOpaqueOnlyGeometry (sx = 8, sy = 8, sz = 8): MesherGeometryOutput {
|
|
|
95
90
|
signs: {},
|
|
96
91
|
banners: {},
|
|
97
92
|
hadErrors: false,
|
|
98
|
-
blocksCount: 1
|
|
93
|
+
blocksCount: 1
|
|
99
94
|
}
|
|
100
95
|
}
|
|
101
96
|
|
|
102
|
-
function makeMixedGeometry
|
|
97
|
+
function makeMixedGeometry(): MesherGeometryOutput {
|
|
103
98
|
const opaque = makeQuadArrays()
|
|
104
99
|
const blend = makeQuadArrays()
|
|
105
100
|
return {
|
|
@@ -136,12 +131,12 @@ function makeMixedGeometry (): MesherGeometryOutput {
|
|
|
136
131
|
skyLights: blend.skyLights,
|
|
137
132
|
blockLights: blend.blockLights,
|
|
138
133
|
uvs: blend.uvs,
|
|
139
|
-
indices: blend.indices
|
|
140
|
-
}
|
|
134
|
+
indices: blend.indices
|
|
135
|
+
}
|
|
141
136
|
}
|
|
142
137
|
}
|
|
143
138
|
|
|
144
|
-
function createManager
|
|
139
|
+
function createManager(): ChunkMeshManager {
|
|
145
140
|
const scene = new THREE.Scene()
|
|
146
141
|
const material = new THREE.MeshBasicMaterial()
|
|
147
142
|
const worldRenderer = {
|
|
@@ -150,25 +145,25 @@ function createManager (): ChunkMeshManager {
|
|
|
150
145
|
sceneOrigin: {
|
|
151
146
|
track: () => {},
|
|
152
147
|
removeAndUntrack: () => {},
|
|
153
|
-
removeAndUntrackAll: () => {}
|
|
148
|
+
removeAndUntrackAll: () => {}
|
|
154
149
|
},
|
|
155
150
|
blockEntities: {},
|
|
156
|
-
worldRendererConfig: {}
|
|
151
|
+
worldRendererConfig: {}
|
|
157
152
|
} as unknown as WorldRendererThree
|
|
158
153
|
return new ChunkMeshManager(worldRenderer, scene, material, 256, 1)
|
|
159
154
|
}
|
|
160
155
|
|
|
161
156
|
type ManagerInternals = {
|
|
162
|
-
legacyCullSections: Map<string, { worldX: number
|
|
157
|
+
legacyCullSections: Map<string, { worldX: number; worldY: number; worldZ: number }>
|
|
163
158
|
registerLegacyCullSection: (key: string, wx: number, wy: number, wz: number) => void
|
|
164
159
|
maybeUnregisterLegacyCullSection: (key: string) => void
|
|
165
160
|
}
|
|
166
161
|
|
|
167
|
-
function getLegacyCullSections
|
|
162
|
+
function getLegacyCullSections(manager: ChunkMeshManager): Map<string, { worldX: number; worldY: number; worldZ: number }> {
|
|
168
163
|
return (manager as unknown as ManagerInternals).legacyCullSections
|
|
169
164
|
}
|
|
170
165
|
|
|
171
|
-
function makeCamera
|
|
166
|
+
function makeCamera(x: number, y: number, z: number): THREE.PerspectiveCamera {
|
|
172
167
|
const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 1000)
|
|
173
168
|
camera.position.set(x, y, z)
|
|
174
169
|
camera.lookAt(8, 8, 8)
|
|
@@ -225,9 +220,14 @@ test('updateSectionCullAndSort: same visible set skips span rebuild on camera mo
|
|
|
225
220
|
manager.updateSectionCullAndSort(camera1, 8, 8, 20)
|
|
226
221
|
expect(updateDrawSpansSpy).toHaveBeenCalledTimes(1)
|
|
227
222
|
|
|
223
|
+
while (blendBuffer.hasPendingUploads()) blendBuffer.uploadDirtyRange()
|
|
224
|
+
|
|
225
|
+
manager.updateSectionCullAndSort(camera1, 8, 8, 20)
|
|
226
|
+
expect(updateDrawSpansSpy).toHaveBeenCalledTimes(2)
|
|
227
|
+
|
|
228
228
|
const camera2 = makeCamera(8, 8, 18)
|
|
229
229
|
manager.updateSectionCullAndSort(camera2, 8, 8, 18)
|
|
230
|
-
expect(updateDrawSpansSpy).toHaveBeenCalledTimes(
|
|
230
|
+
expect(updateDrawSpansSpy).toHaveBeenCalledTimes(2)
|
|
231
231
|
|
|
232
232
|
manager.cleanupSection(key)
|
|
233
233
|
manager.dispose()
|
|
@@ -246,11 +246,7 @@ test('updateSectionCullAndSort: layoutVersion change forces span rebuild', () =>
|
|
|
246
246
|
expect(updateDrawSpansSpy).toHaveBeenCalledTimes(1)
|
|
247
247
|
|
|
248
248
|
blendBuffer.removeSection(key)
|
|
249
|
-
blendBuffer.addSection(
|
|
250
|
-
key,
|
|
251
|
-
makeBlendOnlyGeometry().blend!,
|
|
252
|
-
8, 8, 8,
|
|
253
|
-
)
|
|
249
|
+
blendBuffer.addSection(key, makeBlendOnlyGeometry().blend!, 8, 8, 8)
|
|
254
250
|
;(manager as unknown as ManagerInternals).registerLegacyCullSection(key, 8, 8, 8)
|
|
255
251
|
|
|
256
252
|
manager.updateSectionCullAndSort(camera, 8, 8, 20)
|
|
@@ -260,10 +256,91 @@ test('updateSectionCullAndSort: layoutVersion change forces span rebuild', () =>
|
|
|
260
256
|
manager.dispose()
|
|
261
257
|
})
|
|
262
258
|
|
|
263
|
-
function drainLegacyUploads
|
|
259
|
+
function drainLegacyUploads(buffer: GlobalLegacyBuffer): void {
|
|
264
260
|
while (buffer.hasPendingUploads()) buffer.uploadDirtyRange()
|
|
265
261
|
}
|
|
266
262
|
|
|
263
|
+
function simulateRenderCullGate(manager: ChunkMeshManager, camera: THREE.PerspectiveCamera, x: number, y: number, z: number): void {
|
|
264
|
+
for (const buf of [manager.globalLegacyBuffer, manager.globalLegacyBlendBuffer, manager.globalBlockBuffer]) {
|
|
265
|
+
if (!buf) continue
|
|
266
|
+
buf.compactStep()
|
|
267
|
+
if (buf.hasPendingUploads()) buf.uploadDirtyRange()
|
|
268
|
+
}
|
|
269
|
+
manager.markCullDirtyIfBufferStateChanged()
|
|
270
|
+
if (manager.cullDirty) {
|
|
271
|
+
manager.updateSectionCullAndSort(camera, x, y, z)
|
|
272
|
+
manager.clearCullDirty()
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
test('markCullDirtyIfBufferStateChanged: finalize layout bump marks cull dirty', () => {
|
|
277
|
+
const manager = createManager()
|
|
278
|
+
const key = '0,0,0'
|
|
279
|
+
manager.updateSection(key, makeOpaqueOnlyGeometry(8, 8, 8))
|
|
280
|
+
|
|
281
|
+
const opaqueBuf = manager.globalLegacyBuffer!
|
|
282
|
+
drainLegacyUploads(opaqueBuf)
|
|
283
|
+
|
|
284
|
+
const camera = makeCamera(8, 8, 20)
|
|
285
|
+
manager.updateSectionCullAndSort(camera, 8, 8, 20)
|
|
286
|
+
manager.clearCullDirty()
|
|
287
|
+
|
|
288
|
+
opaqueBuf.addSection(
|
|
289
|
+
key,
|
|
290
|
+
{
|
|
291
|
+
positions: makeQuadArrays().positions,
|
|
292
|
+
colors: makeQuadArrays().colors,
|
|
293
|
+
skyLights: makeQuadArrays().skyLights,
|
|
294
|
+
blockLights: makeQuadArrays().blockLights,
|
|
295
|
+
uvs: makeQuadArrays().uvs,
|
|
296
|
+
indices: makeQuadArrays().indices
|
|
297
|
+
},
|
|
298
|
+
16,
|
|
299
|
+
8,
|
|
300
|
+
8
|
|
301
|
+
)
|
|
302
|
+
drainLegacyUploads(opaqueBuf)
|
|
303
|
+
opaqueBuf.compactStep()
|
|
304
|
+
expect(opaqueBuf.hasPendingReplace()).toBe(false)
|
|
305
|
+
|
|
306
|
+
manager.markCullDirtyIfBufferStateChanged()
|
|
307
|
+
expect(manager.cullDirty).toBe(true)
|
|
308
|
+
|
|
309
|
+
manager.cleanupSection(key)
|
|
310
|
+
manager.dispose()
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
test('simulateRenderCullGate: finalize remesh refreshes visible spans without camera move', () => {
|
|
314
|
+
const manager = createManager()
|
|
315
|
+
const key = '0,0,0'
|
|
316
|
+
const camera = makeCamera(8, 8, 20)
|
|
317
|
+
|
|
318
|
+
manager.updateSection(key, makeOpaqueOnlyGeometry(8, 8, 8))
|
|
319
|
+
const opaqueBuf = manager.globalLegacyBuffer!
|
|
320
|
+
drainLegacyUploads(opaqueBuf)
|
|
321
|
+
simulateRenderCullGate(manager, camera, 8, 8, 20)
|
|
322
|
+
|
|
323
|
+
const slotA = opaqueBuf.getSectionSlot(key)!.start
|
|
324
|
+
opaqueBuf.updateDrawSpans([{ key, distSq: 1 }], 'opaque')
|
|
325
|
+
expect(opaqueBuf.getVisibleIndexSpans()[0]!.indexStart).toBe(slotA * 6)
|
|
326
|
+
|
|
327
|
+
manager.updateSection(key, makeOpaqueOnlyGeometry(16, 8, 8))
|
|
328
|
+
for (let i = 0; i < 32 && (manager.hasPendingBufferWork() || opaqueBuf.hasPendingReplace() || opaqueBuf.hasPendingUploads()); i++) {
|
|
329
|
+
simulateRenderCullGate(manager, camera, 8, 8, 20)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
expect(opaqueBuf.hasPendingReplace()).toBe(false)
|
|
333
|
+
expect(opaqueBuf.hasPendingUploads()).toBe(false)
|
|
334
|
+
|
|
335
|
+
const drawStart = opaqueBuf.getSectionDrawStart(key)!
|
|
336
|
+
const spans = opaqueBuf.getVisibleIndexSpans()
|
|
337
|
+
expect(spans.length).toBeGreaterThan(0)
|
|
338
|
+
expect(spans[0]!.indexStart).toBe(drawStart * 6)
|
|
339
|
+
|
|
340
|
+
manager.cleanupSection(key)
|
|
341
|
+
manager.dispose()
|
|
342
|
+
})
|
|
343
|
+
|
|
267
344
|
test('updateSectionCullAndSort: defrag finalize forces span rebuild with static camera', () => {
|
|
268
345
|
const manager = createManager()
|
|
269
346
|
const keys = ['0,0,0', '1,0,0', '2,0,0'] as const
|
|
@@ -4,21 +4,21 @@ import * as THREE from 'three'
|
|
|
4
4
|
|
|
5
5
|
const renderSignMock = vi.fn()
|
|
6
6
|
vi.mock('../../sign-renderer', () => ({
|
|
7
|
-
renderSign: (...args: unknown[]) => renderSignMock(...args)
|
|
7
|
+
renderSign: (...args: unknown[]) => renderSignMock(...args)
|
|
8
8
|
}))
|
|
9
9
|
|
|
10
10
|
vi.mock('prismarine-chat', () => ({
|
|
11
|
-
default: () => () => ({})
|
|
11
|
+
default: () => () => ({})
|
|
12
12
|
}))
|
|
13
13
|
|
|
14
14
|
import { getSignTexture, releaseSignTexture, disposeAllSignTextures } from '../signTextureCache'
|
|
15
15
|
import type { WorldRendererThree } from '../worldRendererThree'
|
|
16
16
|
|
|
17
|
-
function createWorldRenderer
|
|
17
|
+
function createWorldRenderer(): WorldRendererThree {
|
|
18
18
|
return { version: '1.20' } as WorldRendererThree
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function stubCanvas
|
|
21
|
+
function stubCanvas() {
|
|
22
22
|
return { width: 64, height: 32 } as HTMLCanvasElement
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { raycastAabb, raycastAabbFromInside } from './sectionRaycastAabb'
|
|
3
|
+
|
|
4
|
+
export type VoxelRaycastHit = {
|
|
5
|
+
distance: number
|
|
6
|
+
blockX: number
|
|
7
|
+
blockY: number
|
|
8
|
+
blockZ: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const intBound = (s: number, ds: number): number => {
|
|
12
|
+
if (ds === 0) return Infinity
|
|
13
|
+
if (ds < 0) return intBound(-s, -ds)
|
|
14
|
+
const frac = s - Math.floor(s)
|
|
15
|
+
return (1 - frac) / ds
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const hitSolidBlock = (
|
|
19
|
+
ox: number,
|
|
20
|
+
oy: number,
|
|
21
|
+
oz: number,
|
|
22
|
+
dx: number,
|
|
23
|
+
dy: number,
|
|
24
|
+
dz: number,
|
|
25
|
+
bx: number,
|
|
26
|
+
by: number,
|
|
27
|
+
bz: number,
|
|
28
|
+
maxDist: number,
|
|
29
|
+
radius: number,
|
|
30
|
+
minCameraDistance: number
|
|
31
|
+
): number | undefined => {
|
|
32
|
+
const minX = bx - radius
|
|
33
|
+
const minY = by - radius
|
|
34
|
+
const minZ = bz - radius
|
|
35
|
+
const maxX = bx + 1 + radius
|
|
36
|
+
const maxY = by + 1 + radius
|
|
37
|
+
const maxZ = bz + 1 + radius
|
|
38
|
+
|
|
39
|
+
let t = raycastAabb(ox, oy, oz, dx, dy, dz, minX, minY, minZ, maxX, maxY, maxZ, maxDist)
|
|
40
|
+
if (t === undefined) {
|
|
41
|
+
t = raycastAabbFromInside(ox, oy, oz, dx, dy, dz, minX, minY, minZ, maxX, maxY, maxZ, maxDist)
|
|
42
|
+
}
|
|
43
|
+
if (t === undefined) return undefined
|
|
44
|
+
return Math.max(minCameraDistance, t)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Amanatides–Woo grid traversal against solid block volumes (not rendered mesh faces).
|
|
49
|
+
* `radius` is baked into per-block AABB expansion (swept sphere).
|
|
50
|
+
*/
|
|
51
|
+
export function raycastVoxelSolid(
|
|
52
|
+
ox: number,
|
|
53
|
+
oy: number,
|
|
54
|
+
oz: number,
|
|
55
|
+
dx: number,
|
|
56
|
+
dy: number,
|
|
57
|
+
dz: number,
|
|
58
|
+
maxDist: number,
|
|
59
|
+
radius: number,
|
|
60
|
+
minCameraDistance: number,
|
|
61
|
+
isSolid: (x: number, y: number, z: number) => boolean
|
|
62
|
+
): VoxelRaycastHit | undefined {
|
|
63
|
+
if (maxDist <= 0) return undefined
|
|
64
|
+
|
|
65
|
+
let x = Math.floor(ox)
|
|
66
|
+
let y = Math.floor(oy)
|
|
67
|
+
let z = Math.floor(oz)
|
|
68
|
+
|
|
69
|
+
const stepX = dx > 0 ? 1 : dx < 0 ? -1 : 0
|
|
70
|
+
const stepY = dy > 0 ? 1 : dy < 0 ? -1 : 0
|
|
71
|
+
const stepZ = dz > 0 ? 1 : dz < 0 ? -1 : 0
|
|
72
|
+
|
|
73
|
+
const tDeltaX = stepX !== 0 ? Math.abs(1 / dx) : Infinity
|
|
74
|
+
const tDeltaY = stepY !== 0 ? Math.abs(1 / dy) : Infinity
|
|
75
|
+
const tDeltaZ = stepZ !== 0 ? Math.abs(1 / dz) : Infinity
|
|
76
|
+
|
|
77
|
+
let tMaxX = stepX !== 0 ? intBound(ox, dx) : Infinity
|
|
78
|
+
let tMaxY = stepY !== 0 ? intBound(oy, dy) : Infinity
|
|
79
|
+
let tMaxZ = stepZ !== 0 ? intBound(oz, dz) : Infinity
|
|
80
|
+
|
|
81
|
+
const tryHit = (bx: number, by: number, bz: number): VoxelRaycastHit | undefined => {
|
|
82
|
+
if (!isSolid(bx, by, bz)) return undefined
|
|
83
|
+
const distance = hitSolidBlock(ox, oy, oz, dx, dy, dz, bx, by, bz, maxDist, radius, minCameraDistance)
|
|
84
|
+
if (distance === undefined || distance > maxDist) return undefined
|
|
85
|
+
return { distance, blockX: bx, blockY: by, blockZ: bz }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let hit = tryHit(x, y, z)
|
|
89
|
+
if (hit) return hit
|
|
90
|
+
|
|
91
|
+
let t = 0
|
|
92
|
+
while (t <= maxDist) {
|
|
93
|
+
if (tMaxX < tMaxY) {
|
|
94
|
+
if (tMaxX < tMaxZ) {
|
|
95
|
+
x += stepX
|
|
96
|
+
t = tMaxX
|
|
97
|
+
tMaxX += tDeltaX
|
|
98
|
+
} else {
|
|
99
|
+
z += stepZ
|
|
100
|
+
t = tMaxZ
|
|
101
|
+
tMaxZ += tDeltaZ
|
|
102
|
+
}
|
|
103
|
+
} else if (tMaxY < tMaxZ) {
|
|
104
|
+
y += stepY
|
|
105
|
+
t = tMaxY
|
|
106
|
+
tMaxY += tDeltaY
|
|
107
|
+
} else {
|
|
108
|
+
z += stepZ
|
|
109
|
+
t = tMaxZ
|
|
110
|
+
tMaxZ += tDeltaZ
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (t > maxDist) break
|
|
114
|
+
|
|
115
|
+
hit = tryHit(x, y, z)
|
|
116
|
+
if (hit) return hit
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return undefined
|
|
120
|
+
}
|