minecraft-renderer 0.1.79 → 0.1.80
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 +29 -25
- package/dist/mesher.js +36 -36
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -217
- package/dist/minecraft-renderer.js +27 -27
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +133 -133
- 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 +338 -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/cameraShake.ts +15 -6
- package/src/three/chunkMeshManager.ts +239 -282
- 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 +257 -166
- 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 +30 -18
- 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 -34
- 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/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 +117 -129
- 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/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 +17 -4
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
- package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
- 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,19 +644,11 @@ export class GlobalLegacyBuffer {
|
|
|
545
644
|
if (uf?.value?.set) uf.value.set(cameraOriginFrac.x, cameraOriginFrac.y, cameraOriginFrac.z)
|
|
546
645
|
}
|
|
547
646
|
|
|
548
|
-
raycastSections
|
|
549
|
-
raycaster: THREE.Raycaster,
|
|
550
|
-
sectionKeys: Iterable<string>,
|
|
551
|
-
out: THREE.Intersection[],
|
|
552
|
-
): THREE.Intersection[] {
|
|
647
|
+
raycastSections(raycaster: THREE.Raycaster, sectionKeys: Iterable<string>, out: THREE.Intersection[]): THREE.Intersection[] {
|
|
553
648
|
const ray = raycaster.ray
|
|
554
649
|
const closest = raycaster.near
|
|
555
650
|
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
|
-
))
|
|
651
|
+
_raycastOrigin.copy(ray.origin).sub(_raycastRenderOrigin.set(this.renderOrigin.x, this.renderOrigin.y, this.renderOrigin.z))
|
|
561
652
|
_raycastRay.origin.copy(_raycastOrigin)
|
|
562
653
|
_raycastRay.direction.copy(ray.direction)
|
|
563
654
|
|
|
@@ -576,19 +667,14 @@ export class GlobalLegacyBuffer {
|
|
|
576
667
|
const i2 = this.indices[dstIndexBase + i + 2]!
|
|
577
668
|
if (i0 === i1 && i1 === i2) continue
|
|
578
669
|
|
|
579
|
-
const hit = intersectTriangle(
|
|
580
|
-
_raycastRay,
|
|
581
|
-
this.positions, this.aOrigin, dstFloatBase,
|
|
582
|
-
i0, i1, i2,
|
|
583
|
-
closest, far,
|
|
584
|
-
)
|
|
670
|
+
const hit = intersectTriangle(_raycastRay, this.positions, this.aOrigin, dstFloatBase, i0, i1, i2, closest, far)
|
|
585
671
|
if (hit !== null) {
|
|
586
672
|
out.push({
|
|
587
673
|
distance: hit,
|
|
588
674
|
point: ray.at(hit, new THREE.Vector3()),
|
|
589
675
|
object: this.mesh,
|
|
590
676
|
face: null,
|
|
591
|
-
faceIndex: Math.floor(i / 3)
|
|
677
|
+
faceIndex: Math.floor(i / 3)
|
|
592
678
|
})
|
|
593
679
|
}
|
|
594
680
|
}
|
|
@@ -598,51 +684,53 @@ export class GlobalLegacyBuffer {
|
|
|
598
684
|
return out
|
|
599
685
|
}
|
|
600
686
|
|
|
601
|
-
getHighWatermark
|
|
687
|
+
getHighWatermark(): number {
|
|
602
688
|
return this.highWatermark
|
|
603
689
|
}
|
|
604
690
|
|
|
605
|
-
getCapacityQuads
|
|
691
|
+
getCapacityQuads(): number {
|
|
606
692
|
return this.capacityQuads
|
|
607
693
|
}
|
|
608
694
|
|
|
609
|
-
getSectionCount
|
|
695
|
+
getSectionCount(): number {
|
|
610
696
|
return this.sectionSlots.size
|
|
611
697
|
}
|
|
612
698
|
|
|
613
|
-
getMemoryBytes
|
|
699
|
+
getMemoryBytes(): number {
|
|
614
700
|
return this.capacityQuads * LEGACY_BYTES_PER_QUAD
|
|
615
701
|
}
|
|
616
702
|
|
|
617
|
-
getUsedMemoryBytes
|
|
703
|
+
getUsedMemoryBytes(): number {
|
|
618
704
|
return this.highWatermark * LEGACY_BYTES_PER_QUAD
|
|
619
705
|
}
|
|
620
706
|
|
|
621
|
-
reset
|
|
707
|
+
reset(): void {
|
|
622
708
|
this.sectionSlots.clear()
|
|
623
709
|
this.freeList.length = 0
|
|
624
710
|
this.highWatermark = 0
|
|
625
711
|
this.pendingRanges.length = 0
|
|
626
712
|
this.pendingMove = null
|
|
713
|
+
this.pendingReplace.clear()
|
|
714
|
+
this.uploadEpoch = 0
|
|
627
715
|
this.visibleIndexSpans = []
|
|
628
716
|
this.syncDefaultDrawGroups()
|
|
629
717
|
}
|
|
630
718
|
|
|
631
|
-
dispose
|
|
719
|
+
dispose(): void {
|
|
632
720
|
this.mesh.parent?.remove(this.mesh)
|
|
633
721
|
this.mesh.geometry.dispose()
|
|
634
722
|
this.reset()
|
|
635
723
|
}
|
|
636
724
|
|
|
637
|
-
private markDirty
|
|
725
|
+
private markDirty(start: number, end: number): void {
|
|
638
726
|
this.pendingRanges.push({ start, end })
|
|
639
727
|
this.pendingRanges.sort((a, b) => a.start - b.start)
|
|
640
728
|
this.mergePendingRanges()
|
|
641
729
|
}
|
|
642
730
|
|
|
643
|
-
private mergePendingRanges
|
|
731
|
+
private mergePendingRanges(): void {
|
|
644
732
|
if (this.pendingRanges.length < 2) return
|
|
645
|
-
const merged: Array<{ start: number
|
|
733
|
+
const merged: Array<{ start: number; end: number }> = []
|
|
646
734
|
let cur = this.pendingRanges[0]!
|
|
647
735
|
for (let i = 1; i < this.pendingRanges.length; i++) {
|
|
648
736
|
const next = this.pendingRanges[i]!
|
|
@@ -657,7 +745,7 @@ export class GlobalLegacyBuffer {
|
|
|
657
745
|
this.pendingRanges = merged
|
|
658
746
|
}
|
|
659
747
|
|
|
660
|
-
private takeFreeSlot
|
|
748
|
+
private takeFreeSlot(count: number): { start: number; count: number } | undefined {
|
|
661
749
|
for (let i = 0; i < this.freeList.length; i++) {
|
|
662
750
|
const slot = this.freeList[i]!
|
|
663
751
|
if (slot.count >= count) {
|
|
@@ -671,15 +759,15 @@ export class GlobalLegacyBuffer {
|
|
|
671
759
|
return undefined
|
|
672
760
|
}
|
|
673
761
|
|
|
674
|
-
private insertFreeSlot
|
|
762
|
+
private insertFreeSlot(slot: { start: number; count: number }): void {
|
|
675
763
|
this.freeList.push(slot)
|
|
676
764
|
this.freeList.sort((a, b) => a.start - b.start)
|
|
677
765
|
this.mergeFreeList()
|
|
678
766
|
}
|
|
679
767
|
|
|
680
|
-
private mergeFreeList
|
|
768
|
+
private mergeFreeList(): void {
|
|
681
769
|
if (this.freeList.length < 2) return
|
|
682
|
-
const merged: Array<{ start: number
|
|
770
|
+
const merged: Array<{ start: number; count: number }> = []
|
|
683
771
|
let cur = this.freeList[0]!
|
|
684
772
|
for (let i = 1; i < this.freeList.length; i++) {
|
|
685
773
|
const next = this.freeList[i]!
|
|
@@ -694,7 +782,7 @@ export class GlobalLegacyBuffer {
|
|
|
694
782
|
this.freeList = merged
|
|
695
783
|
}
|
|
696
784
|
|
|
697
|
-
private shrinkHighWatermark
|
|
785
|
+
private shrinkHighWatermark(): void {
|
|
698
786
|
while (this.highWatermark > 0) {
|
|
699
787
|
const tail = this.highWatermark - 1
|
|
700
788
|
const free = this.freeList.find(s => s.start <= tail && s.start + s.count > tail)
|
|
@@ -705,7 +793,7 @@ export class GlobalLegacyBuffer {
|
|
|
705
793
|
}
|
|
706
794
|
}
|
|
707
795
|
|
|
708
|
-
private interiorFreeQuads
|
|
796
|
+
private interiorFreeQuads(): number {
|
|
709
797
|
let total = 0
|
|
710
798
|
for (const slot of this.freeList) {
|
|
711
799
|
if (slot.start < this.highWatermark) total += slot.count
|
|
@@ -713,8 +801,8 @@ export class GlobalLegacyBuffer {
|
|
|
713
801
|
return total
|
|
714
802
|
}
|
|
715
803
|
|
|
716
|
-
private findMovableSection
|
|
717
|
-
const sections: Array<{ key: string
|
|
804
|
+
private findMovableSection(maxCount: number): { key: string; start: number; count: number } | undefined {
|
|
805
|
+
const sections: Array<{ key: string; start: number; count: number }> = []
|
|
718
806
|
for (const [key, slot] of this.sectionSlots) {
|
|
719
807
|
sections.push({ key, start: slot.start, count: slot.count })
|
|
720
808
|
}
|
|
@@ -722,7 +810,7 @@ export class GlobalLegacyBuffer {
|
|
|
722
810
|
|
|
723
811
|
sections.sort((a, b) => {
|
|
724
812
|
if (b.start !== a.start) return b.start - a.start
|
|
725
|
-
return
|
|
813
|
+
return b.start + b.count - (a.start + a.count)
|
|
726
814
|
})
|
|
727
815
|
|
|
728
816
|
const tailmost = sections[0]!
|
|
@@ -730,9 +818,7 @@ export class GlobalLegacyBuffer {
|
|
|
730
818
|
return tailmost
|
|
731
819
|
}
|
|
732
820
|
|
|
733
|
-
const candidates = sections
|
|
734
|
-
.filter(s => s.count <= maxCount)
|
|
735
|
-
.sort((a, b) => b.count - a.count)
|
|
821
|
+
const candidates = sections.filter(s => s.count <= maxCount).sort((a, b) => b.count - a.count)
|
|
736
822
|
|
|
737
823
|
for (const s of candidates) {
|
|
738
824
|
if (this.findLowestInteriorHole(s.start, s.count)) return s
|
|
@@ -740,10 +826,7 @@ export class GlobalLegacyBuffer {
|
|
|
740
826
|
return undefined
|
|
741
827
|
}
|
|
742
828
|
|
|
743
|
-
private findLowestInteriorHole
|
|
744
|
-
sectionStart: number,
|
|
745
|
-
count: number,
|
|
746
|
-
): { start: number, count: number, index: number } | undefined {
|
|
829
|
+
private findLowestInteriorHole(sectionStart: number, count: number): { start: number; count: number; index: number } | undefined {
|
|
747
830
|
for (let i = 0; i < this.freeList.length; i++) {
|
|
748
831
|
const slot = this.freeList[i]!
|
|
749
832
|
if (slot.start < sectionStart && slot.count >= count) {
|
|
@@ -753,7 +836,7 @@ export class GlobalLegacyBuffer {
|
|
|
753
836
|
return undefined
|
|
754
837
|
}
|
|
755
838
|
|
|
756
|
-
private reserveFreeSlotAt
|
|
839
|
+
private reserveFreeSlotAt(index: number, count: number): { start: number; count: number } {
|
|
757
840
|
const slot = this.freeList[index]!
|
|
758
841
|
this.freeList.splice(index, 1)
|
|
759
842
|
if (slot.count === count) return { start: slot.start, count }
|
|
@@ -762,7 +845,7 @@ export class GlobalLegacyBuffer {
|
|
|
762
845
|
return used
|
|
763
846
|
}
|
|
764
847
|
|
|
765
|
-
private copySectionRange
|
|
848
|
+
private copySectionRange(oldStart: number, newStart: number, quadCount: number): void {
|
|
766
849
|
const oldVertBase = oldStart * VERTS_PER_QUAD
|
|
767
850
|
const newVertBase = newStart * VERTS_PER_QUAD
|
|
768
851
|
const vertCount = quadCount * VERTS_PER_QUAD
|
|
@@ -794,35 +877,53 @@ export class GlobalLegacyBuffer {
|
|
|
794
877
|
}
|
|
795
878
|
}
|
|
796
879
|
|
|
797
|
-
private rangeFullyUploaded
|
|
880
|
+
private rangeFullyUploaded(start: number, end: number): boolean {
|
|
798
881
|
for (const r of this.pendingRanges) {
|
|
799
882
|
if (r.start <= end && r.end >= start) return false
|
|
800
883
|
}
|
|
801
884
|
return true
|
|
802
885
|
}
|
|
803
886
|
|
|
804
|
-
private
|
|
805
|
-
const
|
|
806
|
-
if (!move) return
|
|
807
|
-
|
|
808
|
-
const { oldStart, count } = move
|
|
809
|
-
const oldIndexBase = oldStart * INDICES_PER_QUAD
|
|
887
|
+
private zeroAndFreeSlot(start: number, count: number): void {
|
|
888
|
+
const oldIndexBase = start * INDICES_PER_QUAD
|
|
810
889
|
const oldIndexLen = count * INDICES_PER_QUAD
|
|
811
890
|
for (let i = 0; i < oldIndexLen; i++) {
|
|
812
891
|
this.indices[oldIndexBase + i] = 0
|
|
813
892
|
}
|
|
814
|
-
this.
|
|
893
|
+
this.markDirty(start, start + count - 1)
|
|
894
|
+
this.insertFreeSlot({ start, count })
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
private finalizePendingReplace(key: string): void {
|
|
898
|
+
const pr = this.pendingReplace.get(key)
|
|
899
|
+
if (!pr) return
|
|
900
|
+
|
|
901
|
+
this.zeroAndFreeSlot(pr.oldStart, pr.oldCount)
|
|
902
|
+
this.pendingReplace.delete(key)
|
|
903
|
+
this.shrinkHighWatermark()
|
|
904
|
+
this.syncDefaultDrawGroups()
|
|
905
|
+
this.layoutVersion++
|
|
906
|
+
this.uploadEpoch++
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
private finalizePendingMove(): void {
|
|
910
|
+
const move = this.pendingMove
|
|
911
|
+
if (!move) return
|
|
912
|
+
|
|
913
|
+
const { oldStart, count } = move
|
|
914
|
+
this.zeroAndFreeSlot(oldStart, count)
|
|
815
915
|
this.shrinkHighWatermark()
|
|
816
|
-
if (oldStart < this.highWatermark) {
|
|
817
|
-
this.markDirty(oldStart, oldStart + count - 1)
|
|
818
|
-
}
|
|
819
916
|
this.syncDefaultDrawGroups()
|
|
820
917
|
this.pendingMove = null
|
|
821
918
|
this.layoutVersion++
|
|
919
|
+
this.uploadEpoch++
|
|
822
920
|
}
|
|
823
921
|
|
|
824
|
-
private growCapacity
|
|
922
|
+
private growCapacity(minQuads: number): void {
|
|
825
923
|
if (this.pendingMove) this.finalizePendingMove()
|
|
924
|
+
for (const key of [...this.pendingReplace.keys()]) {
|
|
925
|
+
this.finalizePendingReplace(key)
|
|
926
|
+
}
|
|
826
927
|
|
|
827
928
|
let newCap = this.capacityQuads
|
|
828
929
|
while (newCap < minQuads) newCap += this.growthIncrementQuads
|
|
@@ -890,22 +991,12 @@ const _raycastOrigin = new THREE.Vector3()
|
|
|
890
991
|
const _raycastRenderOrigin = new THREE.Vector3()
|
|
891
992
|
const _raycastRay = new THREE.Ray()
|
|
892
993
|
|
|
893
|
-
function readWorldVertex
|
|
894
|
-
positions: Float32Array,
|
|
895
|
-
aOrigin: Float32Array,
|
|
896
|
-
floatBase: number,
|
|
897
|
-
vertIndex: number,
|
|
898
|
-
target: THREE.Vector3,
|
|
899
|
-
): void {
|
|
994
|
+
function readWorldVertex(positions: Float32Array, aOrigin: Float32Array, floatBase: number, vertIndex: number, target: THREE.Vector3): void {
|
|
900
995
|
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
|
-
)
|
|
996
|
+
target.set(aOrigin[f]! + positions[f]!, aOrigin[f + 1]! + positions[f + 1]!, aOrigin[f + 2]! + positions[f + 2]!)
|
|
906
997
|
}
|
|
907
998
|
|
|
908
|
-
function intersectTriangle
|
|
999
|
+
function intersectTriangle(
|
|
909
1000
|
ray: THREE.Ray,
|
|
910
1001
|
positions: Float32Array,
|
|
911
1002
|
aOrigin: Float32Array,
|
|
@@ -914,7 +1005,7 @@ function intersectTriangle (
|
|
|
914
1005
|
i1: number,
|
|
915
1006
|
i2: number,
|
|
916
1007
|
near: number,
|
|
917
|
-
far: number
|
|
1008
|
+
far: number
|
|
918
1009
|
): number | null {
|
|
919
1010
|
readWorldVertex(positions, aOrigin, floatBase, i0, _vA)
|
|
920
1011
|
readWorldVertex(positions, aOrigin, floatBase, i1, _vB)
|
|
@@ -935,7 +1026,7 @@ function intersectTriangle (
|
|
|
935
1026
|
return t
|
|
936
1027
|
}
|
|
937
1028
|
|
|
938
|
-
function pointInTriangle
|
|
1029
|
+
function pointInTriangle(p: THREE.Vector3, a: THREE.Vector3, b: THREE.Vector3, c: THREE.Vector3): boolean {
|
|
939
1030
|
_edge1.subVectors(b, a)
|
|
940
1031
|
_edge2.subVectors(c, a)
|
|
941
1032
|
const n = _normal.crossVectors(_edge1, _edge2).normalize()
|