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
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
logLegacyMultiDrawTierOnce,
|
|
8
8
|
type LegacyDrawSpan,
|
|
9
9
|
type LegacyMultiDrawCaps,
|
|
10
|
-
type LegacyMultiDrawScratch
|
|
10
|
+
type LegacyMultiDrawScratch
|
|
11
11
|
} from './legacyMultiDraw'
|
|
12
12
|
import { computeCameraRelativeUniforms, type RenderOrigin } from './shaders/legacyBlockShader'
|
|
13
13
|
|
|
@@ -22,24 +22,83 @@ const DEFAULT_GROWTH_INCREMENT_QUADS = 128_000
|
|
|
22
22
|
const MAX_UPLOAD_QUADS_PER_FRAME = 5_000
|
|
23
23
|
const FRAGMENTATION_THRESHOLD = 0.25
|
|
24
24
|
|
|
25
|
-
type PendingMove = { key: string
|
|
25
|
+
type PendingMove = { key: string; oldStart: number; newStart: number; count: number }
|
|
26
|
+
type PendingReplace = { oldStart: number; oldCount: number }
|
|
26
27
|
|
|
27
28
|
/** CPU bytes per allocated quad slot (all legacy vertex/index attrs). */
|
|
28
|
-
export const LEGACY_BYTES_PER_QUAD =
|
|
29
|
-
VERTS_PER_QUAD * (FLOATS_PER_VERT * 3 + FLOATS_PER_LIGHT_VERT * 2 + FLOATS_PER_UV_VERT) * 4
|
|
30
|
-
+ INDICES_PER_QUAD * 4
|
|
29
|
+
export const LEGACY_BYTES_PER_QUAD = VERTS_PER_QUAD * (FLOATS_PER_VERT * 3 + FLOATS_PER_LIGHT_VERT * 2 + FLOATS_PER_UV_VERT) * 4 + INDICES_PER_QUAD * 4
|
|
31
30
|
|
|
32
31
|
export const FULL_DRAW_VISIBLE_FRACTION = 0.75
|
|
33
|
-
|
|
32
|
+
/** Initial multi_draw scratch size; arrays auto-grow — not a draw-call cap. */
|
|
34
33
|
export const MAX_OPAQUE_SPANS = 64
|
|
35
34
|
|
|
35
|
+
/** Dev assert: every quad in draw spans must lie in a live section's drawable range. */
|
|
36
|
+
export function assertDrawSpansWithinLiveRanges(
|
|
37
|
+
spans: ReadonlyArray<{ start: number; count: number }>,
|
|
38
|
+
liveRanges: ReadonlyArray<{ start: number; count: number }>,
|
|
39
|
+
bufferName: string
|
|
40
|
+
): void {
|
|
41
|
+
for (const span of spans) {
|
|
42
|
+
for (let q = span.start; q < span.start + span.count; q++) {
|
|
43
|
+
let inLive = false
|
|
44
|
+
for (const live of liveRanges) {
|
|
45
|
+
if (q >= live.start && q < live.start + live.count) {
|
|
46
|
+
inLive = true
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!inLive) {
|
|
51
|
+
console.error('[GlobalLegacyBuffer] draw span covers non-live quad', {
|
|
52
|
+
buffer: bufferName,
|
|
53
|
+
quad: q,
|
|
54
|
+
span,
|
|
55
|
+
liveRanges
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type DirtyRange = { start: number; end: number }
|
|
63
|
+
|
|
64
|
+
/** Split draw spans to exclude quad/face ranges still in pendingRanges (not yet on GPU). */
|
|
65
|
+
export function carveSpansAroundPendingRanges(
|
|
66
|
+
spans: Array<{ start: number; count: number }>,
|
|
67
|
+
pendingRanges: ReadonlyArray<DirtyRange>
|
|
68
|
+
): Array<{ start: number; count: number }> {
|
|
69
|
+
if (pendingRanges.length === 0) return spans
|
|
70
|
+
const out: Array<{ start: number; count: number }> = []
|
|
71
|
+
for (const span of spans) {
|
|
72
|
+
let segments: Array<{ start: number; count: number }> = [span]
|
|
73
|
+
for (const pr of pendingRanges) {
|
|
74
|
+
const next: Array<{ start: number; count: number }> = []
|
|
75
|
+
for (const seg of segments) {
|
|
76
|
+
const segEnd = seg.start + seg.count - 1
|
|
77
|
+
if (pr.end < seg.start || pr.start > segEnd) {
|
|
78
|
+
next.push(seg)
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
if (pr.start > seg.start) {
|
|
82
|
+
next.push({ start: seg.start, count: pr.start - seg.start })
|
|
83
|
+
}
|
|
84
|
+
if (pr.end < segEnd) {
|
|
85
|
+
next.push({ start: pr.end + 1, count: segEnd - pr.end })
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
segments = next
|
|
89
|
+
}
|
|
90
|
+
out.push(...segments)
|
|
91
|
+
}
|
|
92
|
+
return out.filter(s => s.count > 0)
|
|
93
|
+
}
|
|
94
|
+
|
|
36
95
|
export type GlobalLegacyBufferOptions = {
|
|
37
96
|
name?: string
|
|
38
97
|
initialCapacityQuads?: number
|
|
39
98
|
growthIncrementQuads?: number
|
|
40
99
|
}
|
|
41
100
|
|
|
42
|
-
export type VisibleSectionSpan = { key: string
|
|
101
|
+
export type VisibleSectionSpan = { key: string; distSq: number }
|
|
43
102
|
|
|
44
103
|
export type LegacySectionGeometry = {
|
|
45
104
|
positions: Float32Array
|
|
@@ -75,24 +134,22 @@ export class GlobalLegacyBuffer {
|
|
|
75
134
|
private uvs: Float32Array
|
|
76
135
|
private aOrigin: Float32Array
|
|
77
136
|
private indices: Uint32Array
|
|
78
|
-
private readonly sectionSlots = new Map<string, { start: number
|
|
79
|
-
private freeList: Array<{ start: number
|
|
137
|
+
private readonly sectionSlots = new Map<string, { start: number; count: number }>()
|
|
138
|
+
private freeList: Array<{ start: number; count: number }> = []
|
|
80
139
|
private highWatermark = 0
|
|
81
|
-
private pendingRanges: Array<{ start: number
|
|
82
|
-
private readonly _spanScratch: Array<{ start: number
|
|
140
|
+
private pendingRanges: Array<{ start: number; end: number }> = []
|
|
141
|
+
private readonly _spanScratch: Array<{ start: number; count: number }> = []
|
|
83
142
|
private renderOrigin: RenderOrigin = { x: 0, y: 0, z: 0 }
|
|
84
143
|
private layoutVersion = 0
|
|
85
144
|
private pendingMove: PendingMove | null = null
|
|
145
|
+
private readonly pendingReplace = new Map<string, PendingReplace>()
|
|
146
|
+
private uploadEpoch = 0
|
|
86
147
|
private visibleIndexSpans: LegacyDrawSpan[] = []
|
|
87
148
|
private readonly _drawScratch: LegacyMultiDrawScratch = createLegacyMultiDrawScratch()
|
|
88
149
|
private multiDrawCaps: LegacyMultiDrawCaps | null = null
|
|
89
150
|
private debugOverlay = false
|
|
90
151
|
|
|
91
|
-
constructor
|
|
92
|
-
material: THREE.ShaderMaterial,
|
|
93
|
-
scene: THREE.Object3D,
|
|
94
|
-
opts?: GlobalLegacyBufferOptions,
|
|
95
|
-
) {
|
|
152
|
+
constructor(material: THREE.ShaderMaterial, scene: THREE.Object3D, opts?: GlobalLegacyBufferOptions) {
|
|
96
153
|
this.material = material
|
|
97
154
|
this.growthIncrementQuads = opts?.growthIncrementQuads ?? DEFAULT_GROWTH_INCREMENT_QUADS
|
|
98
155
|
this.capacityQuads = opts?.initialCapacityQuads ?? DEFAULT_INITIAL_CAPACITY_QUADS
|
|
@@ -146,7 +203,7 @@ export class GlobalLegacyBuffer {
|
|
|
146
203
|
}
|
|
147
204
|
}
|
|
148
205
|
|
|
149
|
-
setDebugOverlay
|
|
206
|
+
setDebugOverlay(enabled: boolean): void {
|
|
150
207
|
this.debugOverlay = enabled
|
|
151
208
|
}
|
|
152
209
|
|
|
@@ -156,19 +213,19 @@ export class GlobalLegacyBuffer {
|
|
|
156
213
|
* program/VAO/ELEMENT_ARRAY_BUFFER stay bound while three draws ~nothing.
|
|
157
214
|
* Draws one triangle from index 0 (usually harmless; if quad 0 is culled, one stray tri).
|
|
158
215
|
*/
|
|
159
|
-
suppressThreeDraw
|
|
216
|
+
suppressThreeDraw(): void {
|
|
160
217
|
this.mesh.geometry.setDrawRange(0, 3)
|
|
161
218
|
}
|
|
162
219
|
|
|
163
|
-
setVisibleIndexSpans
|
|
220
|
+
setVisibleIndexSpans(spans: LegacyDrawSpan[]): void {
|
|
164
221
|
this.visibleIndexSpans = spans
|
|
165
222
|
}
|
|
166
223
|
|
|
167
|
-
getVisibleIndexSpans
|
|
224
|
+
getVisibleIndexSpans(): readonly LegacyDrawSpan[] {
|
|
168
225
|
return this.visibleIndexSpans
|
|
169
226
|
}
|
|
170
227
|
|
|
171
|
-
private syncDefaultDrawGroups
|
|
228
|
+
private syncDefaultDrawGroups(): void {
|
|
172
229
|
const geometry = this.mesh.geometry
|
|
173
230
|
geometry.clearGroups()
|
|
174
231
|
const indexCount = this.highWatermark * INDICES_PER_QUAD
|
|
@@ -178,13 +235,7 @@ export class GlobalLegacyBuffer {
|
|
|
178
235
|
geometry.setDrawRange(0, indexCount)
|
|
179
236
|
}
|
|
180
237
|
|
|
181
|
-
addSection
|
|
182
|
-
sectionKey: string,
|
|
183
|
-
geo: LegacySectionGeometry,
|
|
184
|
-
sx: number,
|
|
185
|
-
sy: number,
|
|
186
|
-
sz: number,
|
|
187
|
-
): boolean {
|
|
238
|
+
addSection(sectionKey: string, geo: LegacySectionGeometry, sx: number, sy: number, sz: number): boolean {
|
|
188
239
|
const vertCount = geo.positions.length / FLOATS_PER_VERT
|
|
189
240
|
const quadCount = vertCount / VERTS_PER_QUAD
|
|
190
241
|
if (vertCount === 0 || quadCount * VERTS_PER_QUAD !== vertCount) {
|
|
@@ -195,8 +246,23 @@ export class GlobalLegacyBuffer {
|
|
|
195
246
|
return false
|
|
196
247
|
}
|
|
197
248
|
|
|
198
|
-
|
|
199
|
-
|
|
249
|
+
const isRemesh = this.sectionSlots.has(sectionKey)
|
|
250
|
+
let previousSlot: { start: number; count: number } | undefined
|
|
251
|
+
if (isRemesh) {
|
|
252
|
+
const currentSlot = this.sectionSlots.get(sectionKey)!
|
|
253
|
+
const inflightReplace = this.pendingReplace.get(sectionKey)
|
|
254
|
+
const inflightMove = this.pendingMove?.key === sectionKey ? this.pendingMove : undefined
|
|
255
|
+
if (inflightReplace) {
|
|
256
|
+
this.zeroAndFreeSlot(currentSlot.start, currentSlot.count)
|
|
257
|
+
previousSlot = { start: inflightReplace.oldStart, count: inflightReplace.oldCount }
|
|
258
|
+
this.pendingReplace.delete(sectionKey)
|
|
259
|
+
} else if (inflightMove) {
|
|
260
|
+
this.zeroAndFreeSlot(currentSlot.start, currentSlot.count)
|
|
261
|
+
previousSlot = { start: inflightMove.oldStart, count: inflightMove.count }
|
|
262
|
+
this.pendingMove = null
|
|
263
|
+
} else {
|
|
264
|
+
previousSlot = currentSlot
|
|
265
|
+
}
|
|
200
266
|
}
|
|
201
267
|
|
|
202
268
|
if (quadCount > this.capacityQuads) {
|
|
@@ -240,29 +306,65 @@ export class GlobalLegacyBuffer {
|
|
|
240
306
|
}
|
|
241
307
|
|
|
242
308
|
this.sectionSlots.set(sectionKey, slot)
|
|
309
|
+
if (isRemesh && previousSlot) {
|
|
310
|
+
this.pendingReplace.set(sectionKey, { oldStart: previousSlot.start, oldCount: previousSlot.count })
|
|
311
|
+
}
|
|
243
312
|
this.markDirty(slot.start, slot.start + quadCount - 1)
|
|
244
313
|
this.syncDefaultDrawGroups()
|
|
245
314
|
this.layoutVersion++
|
|
246
315
|
return true
|
|
247
316
|
}
|
|
248
317
|
|
|
249
|
-
getLayoutVersion
|
|
318
|
+
getLayoutVersion(): number {
|
|
250
319
|
return this.layoutVersion
|
|
251
320
|
}
|
|
252
321
|
|
|
253
|
-
|
|
322
|
+
getUploadEpoch(): number {
|
|
323
|
+
return this.uploadEpoch
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
hasPendingReplace(): boolean {
|
|
327
|
+
return this.pendingReplace.size > 0
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
canUseFullDrawShortcut(): boolean {
|
|
331
|
+
return this.pendingRanges.length === 0 && this.interiorFreeQuads() === 0 && this.pendingMove === null && this.pendingReplace.size === 0
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
isRangeFullyUploaded(start: number, end: number): boolean {
|
|
335
|
+
return this.rangeFullyUploaded(start, end)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
getPendingDirtyRanges(): ReadonlyArray<DirtyRange> {
|
|
339
|
+
return this.pendingRanges
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
getSectionDrawStart(sectionKey: string): number | undefined {
|
|
254
343
|
const slot = this.sectionSlots.get(sectionKey)
|
|
255
344
|
if (!slot) return undefined
|
|
256
345
|
if (this.pendingMove?.key === sectionKey) return this.pendingMove.oldStart
|
|
346
|
+
const replace = this.pendingReplace.get(sectionKey)
|
|
347
|
+
if (replace) return replace.oldStart
|
|
348
|
+
if (!this.rangeFullyUploaded(slot.start, slot.start + slot.count - 1)) return undefined
|
|
257
349
|
return slot.start
|
|
258
350
|
}
|
|
259
351
|
|
|
260
|
-
|
|
352
|
+
getSectionDrawCount(sectionKey: string): number | undefined {
|
|
353
|
+
const slot = this.sectionSlots.get(sectionKey)
|
|
354
|
+
if (!slot) return undefined
|
|
355
|
+
if (this.pendingMove?.key === sectionKey) return this.pendingMove.count
|
|
356
|
+
const replace = this.pendingReplace.get(sectionKey)
|
|
357
|
+
if (replace) return replace.oldCount
|
|
358
|
+
if (!this.rangeFullyUploaded(slot.start, slot.start + slot.count - 1)) return undefined
|
|
359
|
+
return slot.count
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
getPendingMove(): PendingMove | null {
|
|
261
363
|
return this.pendingMove
|
|
262
364
|
}
|
|
263
365
|
|
|
264
366
|
/** One interior-hole move per frame when fragmentation exceeds threshold; deferred shrink. */
|
|
265
|
-
compactStep
|
|
367
|
+
compactStep(): void {
|
|
266
368
|
if (this.pendingMove) {
|
|
267
369
|
const { newStart, count } = this.pendingMove
|
|
268
370
|
if (this.rangeFullyUploaded(newStart, newStart + count - 1)) {
|
|
@@ -271,6 +373,14 @@ export class GlobalLegacyBuffer {
|
|
|
271
373
|
return
|
|
272
374
|
}
|
|
273
375
|
|
|
376
|
+
for (const key of [...this.pendingReplace.keys()]) {
|
|
377
|
+
const slot = this.sectionSlots.get(key)
|
|
378
|
+
if (!slot) continue
|
|
379
|
+
if (this.rangeFullyUploaded(slot.start, slot.start + slot.count - 1)) {
|
|
380
|
+
this.finalizePendingReplace(key)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
274
384
|
if (this.highWatermark === 0) return
|
|
275
385
|
const interiorFree = this.interiorFreeQuads()
|
|
276
386
|
if (interiorFree / this.highWatermark <= FRAGMENTATION_THRESHOLD) return
|
|
@@ -292,7 +402,7 @@ export class GlobalLegacyBuffer {
|
|
|
292
402
|
this.layoutVersion++
|
|
293
403
|
}
|
|
294
404
|
|
|
295
|
-
updateDrawSpans
|
|
405
|
+
updateDrawSpans(visible: VisibleSectionSpan[], mode: 'opaque' | 'sortedBlend'): void {
|
|
296
406
|
this.visibleIndexSpans = []
|
|
297
407
|
|
|
298
408
|
if (this.highWatermark === 0) {
|
|
@@ -305,10 +415,11 @@ export class GlobalLegacyBuffer {
|
|
|
305
415
|
|
|
306
416
|
for (const entry of visible) {
|
|
307
417
|
const drawStart = this.getSectionDrawStart(entry.key)
|
|
418
|
+
const drawCount = this.getSectionDrawCount(entry.key)
|
|
308
419
|
const slot = this.sectionSlots.get(entry.key)
|
|
309
|
-
if (drawStart === undefined || !slot) continue
|
|
310
|
-
spans.push({ start: drawStart, count:
|
|
311
|
-
visibleQuadCount +=
|
|
420
|
+
if (drawStart === undefined || drawCount === undefined || !slot) continue
|
|
421
|
+
spans.push({ start: drawStart, count: drawCount })
|
|
422
|
+
visibleQuadCount += drawCount
|
|
312
423
|
}
|
|
313
424
|
|
|
314
425
|
if (spans.length === 0) {
|
|
@@ -318,45 +429,47 @@ export class GlobalLegacyBuffer {
|
|
|
318
429
|
const pushIndexSpan = (quadStart: number, quadCount: number): void => {
|
|
319
430
|
this.visibleIndexSpans.push({
|
|
320
431
|
indexStart: quadStart * INDICES_PER_QUAD,
|
|
321
|
-
indexCount: quadCount * INDICES_PER_QUAD
|
|
432
|
+
indexCount: quadCount * INDICES_PER_QUAD
|
|
322
433
|
})
|
|
323
434
|
}
|
|
324
435
|
|
|
325
436
|
if (mode === 'opaque') {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
437
|
+
let finalQuads: Array<{ start: number; count: number }>
|
|
438
|
+
const liveDrawRanges = spans.map(s => ({ ...s }))
|
|
439
|
+
const usedFullDraw = this.canUseFullDrawShortcut() && visibleQuadCount >= this.highWatermark * FULL_DRAW_VISIBLE_FRACTION
|
|
440
|
+
if (usedFullDraw) {
|
|
441
|
+
finalQuads = [{ start: 0, count: this.highWatermark }]
|
|
442
|
+
} else {
|
|
443
|
+
spans.sort((a, b) => a.start - b.start)
|
|
444
|
+
this.mergeOpaqueSpans(spans)
|
|
445
|
+
finalQuads = spans
|
|
332
446
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
for (const span of spans) {
|
|
447
|
+
finalQuads = carveSpansAroundPendingRanges(finalQuads, this.pendingRanges)
|
|
448
|
+
if (!usedFullDraw) {
|
|
449
|
+
assertDrawSpansWithinLiveRanges(finalQuads, liveDrawRanges, this.mesh.name)
|
|
450
|
+
}
|
|
451
|
+
for (const span of finalQuads) {
|
|
339
452
|
pushIndexSpan(span.start, span.count)
|
|
340
453
|
}
|
|
341
454
|
} else {
|
|
342
455
|
visible.sort((a, b) => b.distSq - a.distSq)
|
|
343
456
|
for (const entry of visible) {
|
|
344
457
|
const drawStart = this.getSectionDrawStart(entry.key)
|
|
345
|
-
const
|
|
346
|
-
if (drawStart === undefined ||
|
|
347
|
-
pushIndexSpan(drawStart,
|
|
458
|
+
const drawCount = this.getSectionDrawCount(entry.key)
|
|
459
|
+
if (drawStart === undefined || drawCount === undefined) continue
|
|
460
|
+
pushIndexSpan(drawStart, drawCount)
|
|
348
461
|
}
|
|
349
462
|
}
|
|
350
463
|
}
|
|
351
464
|
|
|
352
|
-
|
|
465
|
+
/** Merge only physically adjacent section slots (gap === 0). Never bridge interior holes. */
|
|
466
|
+
private mergeOpaqueSpans(spans: Array<{ start: number; count: number }>): void {
|
|
353
467
|
if (spans.length < 2) return
|
|
354
468
|
let i = 0
|
|
355
469
|
while (i < spans.length - 1) {
|
|
356
470
|
const cur = spans[i]!
|
|
357
471
|
const next = spans[i + 1]!
|
|
358
|
-
|
|
359
|
-
if (gap <= SPAN_GAP_TOLERANCE_QUADS) {
|
|
472
|
+
if (cur.start + cur.count === next.start) {
|
|
360
473
|
cur.count = next.start + next.count - cur.start
|
|
361
474
|
spans.splice(i + 1, 1)
|
|
362
475
|
} else {
|
|
@@ -365,40 +478,22 @@ export class GlobalLegacyBuffer {
|
|
|
365
478
|
}
|
|
366
479
|
}
|
|
367
480
|
|
|
368
|
-
|
|
369
|
-
while (spans.length > MAX_OPAQUE_SPANS) {
|
|
370
|
-
let bestIdx = 0
|
|
371
|
-
let bestGap = Infinity
|
|
372
|
-
for (let i = 0; i < spans.length - 1; i++) {
|
|
373
|
-
const gap = spans[i + 1]!.start - (spans[i]!.start + spans[i]!.count)
|
|
374
|
-
if (gap < bestGap) {
|
|
375
|
-
bestGap = gap
|
|
376
|
-
bestIdx = i
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const cur = spans[bestIdx]!
|
|
380
|
-
const next = spans[bestIdx + 1]!
|
|
381
|
-
cur.count = next.start + next.count - cur.start
|
|
382
|
-
spans.splice(bestIdx + 1, 1)
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
hasSection (sectionKey: string): boolean {
|
|
481
|
+
hasSection(sectionKey: string): boolean {
|
|
387
482
|
return this.sectionSlots.has(sectionKey)
|
|
388
483
|
}
|
|
389
484
|
|
|
390
|
-
getSectionSlot
|
|
485
|
+
getSectionSlot(sectionKey: string): { start: number; count: number } | undefined {
|
|
391
486
|
return this.sectionSlots.get(sectionKey)
|
|
392
487
|
}
|
|
393
488
|
|
|
394
|
-
takeSectionData
|
|
489
|
+
takeSectionData(sectionKey: string): LegacySectionGeometryData | undefined {
|
|
395
490
|
const data = this.getSectionGeometryData(sectionKey)
|
|
396
491
|
if (!data) return undefined
|
|
397
492
|
this.removeSection(sectionKey)
|
|
398
493
|
return data
|
|
399
494
|
}
|
|
400
495
|
|
|
401
|
-
getSectionGeometryData
|
|
496
|
+
getSectionGeometryData(sectionKey: string): LegacySectionGeometryData | undefined {
|
|
402
497
|
const slot = this.sectionSlots.get(sectionKey)
|
|
403
498
|
if (!slot) return undefined
|
|
404
499
|
|
|
@@ -429,19 +524,19 @@ export class GlobalLegacyBuffer {
|
|
|
429
524
|
return { positions, colors, skyLights, blockLights, uvs, indices, sx, sy, sz }
|
|
430
525
|
}
|
|
431
526
|
|
|
432
|
-
removeSection
|
|
527
|
+
removeSection(sectionKey: string): void {
|
|
433
528
|
const slot = this.sectionSlots.get(sectionKey)
|
|
434
529
|
if (!slot) return
|
|
435
530
|
|
|
531
|
+
if (this.pendingReplace.has(sectionKey)) {
|
|
532
|
+
const pr = this.pendingReplace.get(sectionKey)!
|
|
533
|
+
this.zeroAndFreeSlot(pr.oldStart, pr.oldCount)
|
|
534
|
+
this.pendingReplace.delete(sectionKey)
|
|
535
|
+
}
|
|
536
|
+
|
|
436
537
|
if (this.pendingMove?.key === sectionKey) {
|
|
437
538
|
const { oldStart, count } = this.pendingMove
|
|
438
|
-
|
|
439
|
-
const oldIndexLen = count * INDICES_PER_QUAD
|
|
440
|
-
for (let i = 0; i < oldIndexLen; i++) {
|
|
441
|
-
this.indices[oldIndexBase + i] = 0
|
|
442
|
-
}
|
|
443
|
-
this.markDirty(oldStart, oldStart + count - 1)
|
|
444
|
-
this.insertFreeSlot({ start: oldStart, count })
|
|
539
|
+
this.zeroAndFreeSlot(oldStart, count)
|
|
445
540
|
this.pendingMove = null
|
|
446
541
|
}
|
|
447
542
|
|
|
@@ -459,11 +554,11 @@ export class GlobalLegacyBuffer {
|
|
|
459
554
|
this.layoutVersion++
|
|
460
555
|
}
|
|
461
556
|
|
|
462
|
-
hasPendingUploads
|
|
557
|
+
hasPendingUploads(): boolean {
|
|
463
558
|
return this.pendingRanges.length > 0
|
|
464
559
|
}
|
|
465
560
|
|
|
466
|
-
uploadDirtyRange
|
|
561
|
+
uploadDirtyRange(): void {
|
|
467
562
|
const r = this.pendingRanges[0]
|
|
468
563
|
if (!r) return
|
|
469
564
|
|
|
@@ -510,15 +605,19 @@ export class GlobalLegacyBuffer {
|
|
|
510
605
|
indexAttr.addUpdateRange(indexOffset, indexCount)
|
|
511
606
|
indexAttr.needsUpdate = true
|
|
512
607
|
|
|
513
|
-
if (quadOffset + quadCount > r.end)
|
|
514
|
-
|
|
608
|
+
if (quadOffset + quadCount > r.end) {
|
|
609
|
+
this.pendingRanges.shift()
|
|
610
|
+
} else {
|
|
611
|
+
r.start = quadOffset + quadCount
|
|
612
|
+
}
|
|
613
|
+
this.uploadEpoch++
|
|
515
614
|
}
|
|
516
615
|
|
|
517
|
-
setRenderOrigin
|
|
616
|
+
setRenderOrigin(renderOrigin: RenderOrigin): void {
|
|
518
617
|
this.renderOrigin = { ...renderOrigin }
|
|
519
618
|
}
|
|
520
619
|
|
|
521
|
-
rebase
|
|
620
|
+
rebase(delta: RenderOrigin): void {
|
|
522
621
|
if (this.highWatermark === 0) return
|
|
523
622
|
for (const slot of this.sectionSlots.values()) {
|
|
524
623
|
const dstVertBase = slot.start * VERTS_PER_QUAD
|
|
@@ -537,7 +636,7 @@ export class GlobalLegacyBuffer {
|
|
|
537
636
|
this.renderOrigin.z += delta.z
|
|
538
637
|
}
|
|
539
638
|
|
|
540
|
-
setCameraOrigin
|
|
639
|
+
setCameraOrigin(x: number, y: number, z: number): void {
|
|
541
640
|
const { originDelta, cameraOriginFrac } = computeCameraRelativeUniforms(this.renderOrigin, x, y, z)
|
|
542
641
|
const u = this.material.uniforms.u_originDelta
|
|
543
642
|
if (u?.value?.set) u.value.set(originDelta.x, originDelta.y, originDelta.z)
|
|
@@ -545,104 +644,53 @@ export class GlobalLegacyBuffer {
|
|
|
545
644
|
if (uf?.value?.set) uf.value.set(cameraOriginFrac.x, cameraOriginFrac.y, cameraOriginFrac.z)
|
|
546
645
|
}
|
|
547
646
|
|
|
548
|
-
|
|
549
|
-
raycaster: THREE.Raycaster,
|
|
550
|
-
sectionKeys: Iterable<string>,
|
|
551
|
-
out: THREE.Intersection[],
|
|
552
|
-
): THREE.Intersection[] {
|
|
553
|
-
const ray = raycaster.ray
|
|
554
|
-
const closest = raycaster.near
|
|
555
|
-
const far = raycaster.far
|
|
556
|
-
_raycastOrigin.copy(ray.origin).sub(_raycastRenderOrigin.set(
|
|
557
|
-
this.renderOrigin.x,
|
|
558
|
-
this.renderOrigin.y,
|
|
559
|
-
this.renderOrigin.z,
|
|
560
|
-
))
|
|
561
|
-
_raycastRay.origin.copy(_raycastOrigin)
|
|
562
|
-
_raycastRay.direction.copy(ray.direction)
|
|
563
|
-
|
|
564
|
-
for (const key of sectionKeys) {
|
|
565
|
-
const slot = this.sectionSlots.get(key)
|
|
566
|
-
if (!slot) continue
|
|
567
|
-
|
|
568
|
-
const dstVertBase = slot.start * VERTS_PER_QUAD
|
|
569
|
-
const dstFloatBase = dstVertBase * FLOATS_PER_VERT
|
|
570
|
-
const dstIndexBase = slot.start * INDICES_PER_QUAD
|
|
571
|
-
const indexLen = slot.count * INDICES_PER_QUAD
|
|
572
|
-
|
|
573
|
-
for (let i = 0; i < indexLen; i += 3) {
|
|
574
|
-
const i0 = this.indices[dstIndexBase + i]!
|
|
575
|
-
const i1 = this.indices[dstIndexBase + i + 1]!
|
|
576
|
-
const i2 = this.indices[dstIndexBase + i + 2]!
|
|
577
|
-
if (i0 === i1 && i1 === i2) continue
|
|
578
|
-
|
|
579
|
-
const hit = intersectTriangle(
|
|
580
|
-
_raycastRay,
|
|
581
|
-
this.positions, this.aOrigin, dstFloatBase,
|
|
582
|
-
i0, i1, i2,
|
|
583
|
-
closest, far,
|
|
584
|
-
)
|
|
585
|
-
if (hit !== null) {
|
|
586
|
-
out.push({
|
|
587
|
-
distance: hit,
|
|
588
|
-
point: ray.at(hit, new THREE.Vector3()),
|
|
589
|
-
object: this.mesh,
|
|
590
|
-
face: null,
|
|
591
|
-
faceIndex: Math.floor(i / 3),
|
|
592
|
-
})
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
out.sort((a, b) => a.distance - b.distance)
|
|
598
|
-
return out
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
getHighWatermark (): number {
|
|
647
|
+
getHighWatermark(): number {
|
|
602
648
|
return this.highWatermark
|
|
603
649
|
}
|
|
604
650
|
|
|
605
|
-
getCapacityQuads
|
|
651
|
+
getCapacityQuads(): number {
|
|
606
652
|
return this.capacityQuads
|
|
607
653
|
}
|
|
608
654
|
|
|
609
|
-
getSectionCount
|
|
655
|
+
getSectionCount(): number {
|
|
610
656
|
return this.sectionSlots.size
|
|
611
657
|
}
|
|
612
658
|
|
|
613
|
-
getMemoryBytes
|
|
659
|
+
getMemoryBytes(): number {
|
|
614
660
|
return this.capacityQuads * LEGACY_BYTES_PER_QUAD
|
|
615
661
|
}
|
|
616
662
|
|
|
617
|
-
getUsedMemoryBytes
|
|
663
|
+
getUsedMemoryBytes(): number {
|
|
618
664
|
return this.highWatermark * LEGACY_BYTES_PER_QUAD
|
|
619
665
|
}
|
|
620
666
|
|
|
621
|
-
reset
|
|
667
|
+
reset(): void {
|
|
622
668
|
this.sectionSlots.clear()
|
|
623
669
|
this.freeList.length = 0
|
|
624
670
|
this.highWatermark = 0
|
|
625
671
|
this.pendingRanges.length = 0
|
|
626
672
|
this.pendingMove = null
|
|
673
|
+
this.pendingReplace.clear()
|
|
674
|
+
this.uploadEpoch = 0
|
|
627
675
|
this.visibleIndexSpans = []
|
|
628
676
|
this.syncDefaultDrawGroups()
|
|
629
677
|
}
|
|
630
678
|
|
|
631
|
-
dispose
|
|
679
|
+
dispose(): void {
|
|
632
680
|
this.mesh.parent?.remove(this.mesh)
|
|
633
681
|
this.mesh.geometry.dispose()
|
|
634
682
|
this.reset()
|
|
635
683
|
}
|
|
636
684
|
|
|
637
|
-
private markDirty
|
|
685
|
+
private markDirty(start: number, end: number): void {
|
|
638
686
|
this.pendingRanges.push({ start, end })
|
|
639
687
|
this.pendingRanges.sort((a, b) => a.start - b.start)
|
|
640
688
|
this.mergePendingRanges()
|
|
641
689
|
}
|
|
642
690
|
|
|
643
|
-
private mergePendingRanges
|
|
691
|
+
private mergePendingRanges(): void {
|
|
644
692
|
if (this.pendingRanges.length < 2) return
|
|
645
|
-
const merged: Array<{ start: number
|
|
693
|
+
const merged: Array<{ start: number; end: number }> = []
|
|
646
694
|
let cur = this.pendingRanges[0]!
|
|
647
695
|
for (let i = 1; i < this.pendingRanges.length; i++) {
|
|
648
696
|
const next = this.pendingRanges[i]!
|
|
@@ -657,7 +705,7 @@ export class GlobalLegacyBuffer {
|
|
|
657
705
|
this.pendingRanges = merged
|
|
658
706
|
}
|
|
659
707
|
|
|
660
|
-
private takeFreeSlot
|
|
708
|
+
private takeFreeSlot(count: number): { start: number; count: number } | undefined {
|
|
661
709
|
for (let i = 0; i < this.freeList.length; i++) {
|
|
662
710
|
const slot = this.freeList[i]!
|
|
663
711
|
if (slot.count >= count) {
|
|
@@ -671,15 +719,15 @@ export class GlobalLegacyBuffer {
|
|
|
671
719
|
return undefined
|
|
672
720
|
}
|
|
673
721
|
|
|
674
|
-
private insertFreeSlot
|
|
722
|
+
private insertFreeSlot(slot: { start: number; count: number }): void {
|
|
675
723
|
this.freeList.push(slot)
|
|
676
724
|
this.freeList.sort((a, b) => a.start - b.start)
|
|
677
725
|
this.mergeFreeList()
|
|
678
726
|
}
|
|
679
727
|
|
|
680
|
-
private mergeFreeList
|
|
728
|
+
private mergeFreeList(): void {
|
|
681
729
|
if (this.freeList.length < 2) return
|
|
682
|
-
const merged: Array<{ start: number
|
|
730
|
+
const merged: Array<{ start: number; count: number }> = []
|
|
683
731
|
let cur = this.freeList[0]!
|
|
684
732
|
for (let i = 1; i < this.freeList.length; i++) {
|
|
685
733
|
const next = this.freeList[i]!
|
|
@@ -694,7 +742,7 @@ export class GlobalLegacyBuffer {
|
|
|
694
742
|
this.freeList = merged
|
|
695
743
|
}
|
|
696
744
|
|
|
697
|
-
private shrinkHighWatermark
|
|
745
|
+
private shrinkHighWatermark(): void {
|
|
698
746
|
while (this.highWatermark > 0) {
|
|
699
747
|
const tail = this.highWatermark - 1
|
|
700
748
|
const free = this.freeList.find(s => s.start <= tail && s.start + s.count > tail)
|
|
@@ -705,7 +753,7 @@ export class GlobalLegacyBuffer {
|
|
|
705
753
|
}
|
|
706
754
|
}
|
|
707
755
|
|
|
708
|
-
private interiorFreeQuads
|
|
756
|
+
private interiorFreeQuads(): number {
|
|
709
757
|
let total = 0
|
|
710
758
|
for (const slot of this.freeList) {
|
|
711
759
|
if (slot.start < this.highWatermark) total += slot.count
|
|
@@ -713,8 +761,8 @@ export class GlobalLegacyBuffer {
|
|
|
713
761
|
return total
|
|
714
762
|
}
|
|
715
763
|
|
|
716
|
-
private findMovableSection
|
|
717
|
-
const sections: Array<{ key: string
|
|
764
|
+
private findMovableSection(maxCount: number): { key: string; start: number; count: number } | undefined {
|
|
765
|
+
const sections: Array<{ key: string; start: number; count: number }> = []
|
|
718
766
|
for (const [key, slot] of this.sectionSlots) {
|
|
719
767
|
sections.push({ key, start: slot.start, count: slot.count })
|
|
720
768
|
}
|
|
@@ -722,7 +770,7 @@ export class GlobalLegacyBuffer {
|
|
|
722
770
|
|
|
723
771
|
sections.sort((a, b) => {
|
|
724
772
|
if (b.start !== a.start) return b.start - a.start
|
|
725
|
-
return
|
|
773
|
+
return b.start + b.count - (a.start + a.count)
|
|
726
774
|
})
|
|
727
775
|
|
|
728
776
|
const tailmost = sections[0]!
|
|
@@ -730,9 +778,7 @@ export class GlobalLegacyBuffer {
|
|
|
730
778
|
return tailmost
|
|
731
779
|
}
|
|
732
780
|
|
|
733
|
-
const candidates = sections
|
|
734
|
-
.filter(s => s.count <= maxCount)
|
|
735
|
-
.sort((a, b) => b.count - a.count)
|
|
781
|
+
const candidates = sections.filter(s => s.count <= maxCount).sort((a, b) => b.count - a.count)
|
|
736
782
|
|
|
737
783
|
for (const s of candidates) {
|
|
738
784
|
if (this.findLowestInteriorHole(s.start, s.count)) return s
|
|
@@ -740,10 +786,7 @@ export class GlobalLegacyBuffer {
|
|
|
740
786
|
return undefined
|
|
741
787
|
}
|
|
742
788
|
|
|
743
|
-
private findLowestInteriorHole
|
|
744
|
-
sectionStart: number,
|
|
745
|
-
count: number,
|
|
746
|
-
): { start: number, count: number, index: number } | undefined {
|
|
789
|
+
private findLowestInteriorHole(sectionStart: number, count: number): { start: number; count: number; index: number } | undefined {
|
|
747
790
|
for (let i = 0; i < this.freeList.length; i++) {
|
|
748
791
|
const slot = this.freeList[i]!
|
|
749
792
|
if (slot.start < sectionStart && slot.count >= count) {
|
|
@@ -753,7 +796,7 @@ export class GlobalLegacyBuffer {
|
|
|
753
796
|
return undefined
|
|
754
797
|
}
|
|
755
798
|
|
|
756
|
-
private reserveFreeSlotAt
|
|
799
|
+
private reserveFreeSlotAt(index: number, count: number): { start: number; count: number } {
|
|
757
800
|
const slot = this.freeList[index]!
|
|
758
801
|
this.freeList.splice(index, 1)
|
|
759
802
|
if (slot.count === count) return { start: slot.start, count }
|
|
@@ -762,7 +805,7 @@ export class GlobalLegacyBuffer {
|
|
|
762
805
|
return used
|
|
763
806
|
}
|
|
764
807
|
|
|
765
|
-
private copySectionRange
|
|
808
|
+
private copySectionRange(oldStart: number, newStart: number, quadCount: number): void {
|
|
766
809
|
const oldVertBase = oldStart * VERTS_PER_QUAD
|
|
767
810
|
const newVertBase = newStart * VERTS_PER_QUAD
|
|
768
811
|
const vertCount = quadCount * VERTS_PER_QUAD
|
|
@@ -794,35 +837,53 @@ export class GlobalLegacyBuffer {
|
|
|
794
837
|
}
|
|
795
838
|
}
|
|
796
839
|
|
|
797
|
-
private rangeFullyUploaded
|
|
840
|
+
private rangeFullyUploaded(start: number, end: number): boolean {
|
|
798
841
|
for (const r of this.pendingRanges) {
|
|
799
842
|
if (r.start <= end && r.end >= start) return false
|
|
800
843
|
}
|
|
801
844
|
return true
|
|
802
845
|
}
|
|
803
846
|
|
|
804
|
-
private
|
|
805
|
-
const
|
|
806
|
-
if (!move) return
|
|
807
|
-
|
|
808
|
-
const { oldStart, count } = move
|
|
809
|
-
const oldIndexBase = oldStart * INDICES_PER_QUAD
|
|
847
|
+
private zeroAndFreeSlot(start: number, count: number): void {
|
|
848
|
+
const oldIndexBase = start * INDICES_PER_QUAD
|
|
810
849
|
const oldIndexLen = count * INDICES_PER_QUAD
|
|
811
850
|
for (let i = 0; i < oldIndexLen; i++) {
|
|
812
851
|
this.indices[oldIndexBase + i] = 0
|
|
813
852
|
}
|
|
814
|
-
this.
|
|
853
|
+
this.markDirty(start, start + count - 1)
|
|
854
|
+
this.insertFreeSlot({ start, count })
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
private finalizePendingReplace(key: string): void {
|
|
858
|
+
const pr = this.pendingReplace.get(key)
|
|
859
|
+
if (!pr) return
|
|
860
|
+
|
|
861
|
+
this.zeroAndFreeSlot(pr.oldStart, pr.oldCount)
|
|
862
|
+
this.pendingReplace.delete(key)
|
|
863
|
+
this.shrinkHighWatermark()
|
|
864
|
+
this.syncDefaultDrawGroups()
|
|
865
|
+
this.layoutVersion++
|
|
866
|
+
this.uploadEpoch++
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
private finalizePendingMove(): void {
|
|
870
|
+
const move = this.pendingMove
|
|
871
|
+
if (!move) return
|
|
872
|
+
|
|
873
|
+
const { oldStart, count } = move
|
|
874
|
+
this.zeroAndFreeSlot(oldStart, count)
|
|
815
875
|
this.shrinkHighWatermark()
|
|
816
|
-
if (oldStart < this.highWatermark) {
|
|
817
|
-
this.markDirty(oldStart, oldStart + count - 1)
|
|
818
|
-
}
|
|
819
876
|
this.syncDefaultDrawGroups()
|
|
820
877
|
this.pendingMove = null
|
|
821
878
|
this.layoutVersion++
|
|
879
|
+
this.uploadEpoch++
|
|
822
880
|
}
|
|
823
881
|
|
|
824
|
-
private growCapacity
|
|
882
|
+
private growCapacity(minQuads: number): void {
|
|
825
883
|
if (this.pendingMove) this.finalizePendingMove()
|
|
884
|
+
for (const key of [...this.pendingReplace.keys()]) {
|
|
885
|
+
this.finalizePendingReplace(key)
|
|
886
|
+
}
|
|
826
887
|
|
|
827
888
|
let newCap = this.capacityQuads
|
|
828
889
|
while (newCap < minQuads) newCap += this.growthIncrementQuads
|
|
@@ -879,80 +940,3 @@ export class GlobalLegacyBuffer {
|
|
|
879
940
|
this.pendingRanges.length = 0
|
|
880
941
|
}
|
|
881
942
|
}
|
|
882
|
-
|
|
883
|
-
const _vA = new THREE.Vector3()
|
|
884
|
-
const _vB = new THREE.Vector3()
|
|
885
|
-
const _vC = new THREE.Vector3()
|
|
886
|
-
const _edge1 = new THREE.Vector3()
|
|
887
|
-
const _edge2 = new THREE.Vector3()
|
|
888
|
-
const _normal = new THREE.Vector3()
|
|
889
|
-
const _raycastOrigin = new THREE.Vector3()
|
|
890
|
-
const _raycastRenderOrigin = new THREE.Vector3()
|
|
891
|
-
const _raycastRay = new THREE.Ray()
|
|
892
|
-
|
|
893
|
-
function readWorldVertex (
|
|
894
|
-
positions: Float32Array,
|
|
895
|
-
aOrigin: Float32Array,
|
|
896
|
-
floatBase: number,
|
|
897
|
-
vertIndex: number,
|
|
898
|
-
target: THREE.Vector3,
|
|
899
|
-
): void {
|
|
900
|
-
const f = floatBase + vertIndex * FLOATS_PER_VERT
|
|
901
|
-
target.set(
|
|
902
|
-
aOrigin[f]! + positions[f]!,
|
|
903
|
-
aOrigin[f + 1]! + positions[f + 1]!,
|
|
904
|
-
aOrigin[f + 2]! + positions[f + 2]!,
|
|
905
|
-
)
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
function intersectTriangle (
|
|
909
|
-
ray: THREE.Ray,
|
|
910
|
-
positions: Float32Array,
|
|
911
|
-
aOrigin: Float32Array,
|
|
912
|
-
floatBase: number,
|
|
913
|
-
i0: number,
|
|
914
|
-
i1: number,
|
|
915
|
-
i2: number,
|
|
916
|
-
near: number,
|
|
917
|
-
far: number,
|
|
918
|
-
): number | null {
|
|
919
|
-
readWorldVertex(positions, aOrigin, floatBase, i0, _vA)
|
|
920
|
-
readWorldVertex(positions, aOrigin, floatBase, i1, _vB)
|
|
921
|
-
readWorldVertex(positions, aOrigin, floatBase, i2, _vC)
|
|
922
|
-
|
|
923
|
-
_edge1.subVectors(_vB, _vA)
|
|
924
|
-
_edge2.subVectors(_vC, _vA)
|
|
925
|
-
_normal.crossVectors(_edge1, _edge2)
|
|
926
|
-
|
|
927
|
-
const denom = _normal.dot(ray.direction)
|
|
928
|
-
if (Math.abs(denom) < 1e-8) return null
|
|
929
|
-
|
|
930
|
-
const t = _vA.clone().sub(ray.origin).dot(_normal) / denom
|
|
931
|
-
if (t < near || t > far) return null
|
|
932
|
-
|
|
933
|
-
const p = ray.at(t, new THREE.Vector3())
|
|
934
|
-
if (!pointInTriangle(p, _vA, _vB, _vC)) return null
|
|
935
|
-
return t
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
function pointInTriangle (p: THREE.Vector3, a: THREE.Vector3, b: THREE.Vector3, c: THREE.Vector3): boolean {
|
|
939
|
-
_edge1.subVectors(b, a)
|
|
940
|
-
_edge2.subVectors(c, a)
|
|
941
|
-
const n = _normal.crossVectors(_edge1, _edge2).normalize()
|
|
942
|
-
|
|
943
|
-
const ab = _edge1
|
|
944
|
-
const ac = _edge2
|
|
945
|
-
const ap = p.clone().sub(a)
|
|
946
|
-
|
|
947
|
-
const d00 = ab.dot(ab)
|
|
948
|
-
const d01 = ab.dot(ac)
|
|
949
|
-
const d11 = ac.dot(ac)
|
|
950
|
-
const d20 = ap.dot(ab)
|
|
951
|
-
const d21 = ap.dot(ac)
|
|
952
|
-
const denom = d00 * d11 - d01 * d01
|
|
953
|
-
if (Math.abs(denom) < 1e-12) return false
|
|
954
|
-
const v = (d11 * d20 - d01 * d21) / denom
|
|
955
|
-
const w = (d00 * d21 - d01 * d20) / denom
|
|
956
|
-
const u = 1 - v - w
|
|
957
|
-
return u >= -1e-4 && v >= -1e-4 && w >= -1e-4
|
|
958
|
-
}
|