WEB-695 Batching Maintenance (#2182)
* Starting to tackle WBX-397 by taking a different approach on computing draw ranges * WIP * Range computation is more or less done. Material indices still need a more robust approach * Range material indices figured out mostly by trating them as edges in a graph. Also some profiling to max out pergf * Added forward and backwards material index edges in order to be able to directly look them up rather than searching for them in an array * Extended the new draw range integration approach to instanced batches * Added vitest and wrote a first test for the DrawRange integration approach. Fixed some cicular dependencie which were messing up vitest runtime. * A bunch of more tests * Removed unused dep * ci(viewer): test the viewer in CircleCI * Include test-viewer as a dependency of later jobs * Small updates * Removed old range integration from all three batches * Working on making the range update integration work on an array at a time * Update range integration now works on entire arrays at a time. Almost twice as fast this way. Updates tests * DrawRanges now also flattens the computed draw ranges, so we got rid of the old ugly way of flattening the ranges. Update MeshBatch, PointBatch and InstancedMeshBatch * More adjustment to point batch * Implemented a common PrimitiveBatch which can be used for any typical primitive based rendering (triangles, lines, points) as abstract. Our Mesh and Point batch will use most of the common implementation. Updated MeshBatch to extend PrimitiveBatch * Updated PointBatch to extend PrimitiveBatch * Tried making the instaned mesh batch extend the primitive batch but there was no point, they too different to make sense. Got rid of the pointless circular dependency between the instaned batch and mesh * fixed viewer build * Removed unused code and execution time measurements --------- Co-authored-by: Iain Sproat <68657+iainsproat@users.noreply.github.com> Co-authored-by: Kristaps Fabians Geikins <fabis94@live.com>
This commit is contained in:
Родитель
752a9197c2
Коммит
9c481a20f5
|
@ -25,6 +25,9 @@ workflows:
|
|||
- test-frontend-2:
|
||||
filters: *filters-allow-all
|
||||
|
||||
- test-viewer:
|
||||
filters: *filters-allow-all
|
||||
|
||||
- test-ui-components:
|
||||
filters: *filters-allow-all
|
||||
|
||||
|
@ -54,6 +57,7 @@ workflows:
|
|||
- pre-commit
|
||||
- deployment-testing-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
- docker-build-server
|
||||
- docker-build-frontend
|
||||
|
@ -72,6 +76,7 @@ workflows:
|
|||
- pre-commit
|
||||
- deployment-testing-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
- docker-build-server
|
||||
- docker-build-frontend
|
||||
|
@ -163,6 +168,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-frontend:
|
||||
|
@ -174,6 +180,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-frontend-2:
|
||||
|
@ -185,6 +192,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-webhooks:
|
||||
|
@ -196,6 +204,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-file-imports:
|
||||
|
@ -207,6 +216,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-previews:
|
||||
|
@ -218,6 +228,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-test-container:
|
||||
|
@ -229,6 +240,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-monitor-container:
|
||||
|
@ -240,6 +252,7 @@ workflows:
|
|||
- pre-commit
|
||||
- publish-approval
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-server
|
||||
|
||||
- docker-publish-docker-compose-ingress:
|
||||
|
@ -290,6 +303,7 @@ workflows:
|
|||
- test-server
|
||||
- test-ui-components
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
|
@ -496,6 +510,45 @@ jobs:
|
|||
command: yarn lint
|
||||
working_directory: 'packages/frontend-2'
|
||||
|
||||
test-viewer:
|
||||
docker: &docker-node-browsers-image
|
||||
- image: cimg/node:18.19.0-browsers
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-packages-server-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn
|
||||
|
||||
- run:
|
||||
name: Install Dependencies v2 (.node files missing bug)
|
||||
command: yarn
|
||||
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-server-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- .yarn/cache
|
||||
- .yarn/unplugged
|
||||
|
||||
- run:
|
||||
name: Build public packages
|
||||
command: yarn build:public
|
||||
|
||||
- run:
|
||||
name: Lint everything
|
||||
command: yarn lint
|
||||
working_directory: 'packages/viewer'
|
||||
|
||||
- run:
|
||||
name: Run tests
|
||||
command: yarn test
|
||||
working_directory: 'packages/viewer'
|
||||
|
||||
test-ui-components:
|
||||
docker: *docker-node-browsers-image
|
||||
resource_class: xlarge
|
||||
|
|
|
@ -5,7 +5,10 @@ import {
|
|||
SelectionEvent,
|
||||
ViewerEvent,
|
||||
DebugViewer,
|
||||
Viewer
|
||||
Viewer,
|
||||
Batch,
|
||||
DrawRanges,
|
||||
SpeckleBasicMaterial
|
||||
} from '@speckle/viewer'
|
||||
|
||||
import './style.css'
|
||||
|
@ -20,6 +23,10 @@ import {
|
|||
} from '@speckle/viewer'
|
||||
import { SectionTool } from '@speckle/viewer'
|
||||
import { SectionOutlines } from '@speckle/viewer'
|
||||
import { BoxSelection } from './Extensions/BoxSelection'
|
||||
import { GeometryType } from '@speckle/viewer'
|
||||
import { SpeckleStandardMaterial } from '@speckle/viewer'
|
||||
import { Color, FrontSide } from 'three'
|
||||
|
||||
const createViewer = async (containerName: string, stream: string) => {
|
||||
const container = document.querySelector<HTMLElement>(containerName)
|
||||
|
@ -51,7 +58,7 @@ const createViewer = async (containerName: string, stream: string) => {
|
|||
const filtering = viewer.createExtension(FilteringExtension)
|
||||
const explode = viewer.createExtension(ExplodeExtension)
|
||||
const diff = viewer.createExtension(DiffExtension)
|
||||
// const boxSelect = viewer.createExtension(BoxSelection)
|
||||
const boxSelect = viewer.createExtension(BoxSelection)
|
||||
// const rotateCamera = viewer.createExtension(RotateCamera)
|
||||
cameraController // use it
|
||||
selection // use it
|
||||
|
@ -91,6 +98,97 @@ const createViewer = async (containerName: string, stream: string) => {
|
|||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
|
||||
const meshBatch = viewer
|
||||
.getRenderer()
|
||||
.batcher.getBatches(undefined, GeometryType.MESH)
|
||||
.find((batch: Batch) => batch.renderViews.length > 2)
|
||||
// const geom = meshBatch.mesh.geometry
|
||||
// geom.groups.length = 0
|
||||
// geom.addGroup(0, 216, 0)
|
||||
// geom.addGroup(216, 1323, 0)
|
||||
// geom.addGroup(1539, 540, 0)
|
||||
// geom.addGroup(2079, 32268, 0)
|
||||
|
||||
// const material = new SpeckleStandardMaterial(
|
||||
// {
|
||||
// color: new Color('#00ff00'),
|
||||
// emissive: 0x0,
|
||||
// roughness: 1,
|
||||
// metalness: 0,
|
||||
// opacity: 1,
|
||||
// side: FrontSide
|
||||
// },
|
||||
// ['USE_RTE']
|
||||
// )
|
||||
// meshBatch.setDrawRanges(
|
||||
// {
|
||||
// offset: 36,
|
||||
// count: 36,
|
||||
// material
|
||||
// }
|
||||
// {
|
||||
// offset: 180,
|
||||
// count: 1395,
|
||||
// material
|
||||
// },
|
||||
// {
|
||||
// offset: 1581,
|
||||
// count: 32766,
|
||||
// material
|
||||
// }
|
||||
// )
|
||||
// const material = new SpeckleStandardMaterial(
|
||||
// {
|
||||
// color: new Color('#00ff00'),
|
||||
// emissive: 0x0,
|
||||
// roughness: 1,
|
||||
// metalness: 0,
|
||||
// opacity: 1,
|
||||
// side: FrontSide
|
||||
// },
|
||||
// ['USE_RTE']
|
||||
// )
|
||||
// meshBatch.setDrawRanges(
|
||||
// {
|
||||
// offset: 9018,
|
||||
// count: 36,
|
||||
// material
|
||||
// },
|
||||
// {
|
||||
// offset: 13878,
|
||||
// count: 36,
|
||||
// material
|
||||
// }
|
||||
// )
|
||||
// const material0 = new SpeckleBasicMaterial({ color: 0xff0000 })
|
||||
// const material1 = new SpeckleBasicMaterial({ color: 0x00ff00 })
|
||||
// let groups = [
|
||||
// {
|
||||
// start: 0,
|
||||
// count: 1350,
|
||||
// materialIndex: 0
|
||||
// }
|
||||
// ]
|
||||
|
||||
// const drawRange = new DrawRanges()
|
||||
|
||||
// groups = drawRange.integrateRanges(
|
||||
// groups,
|
||||
// [material0, material1],
|
||||
// [
|
||||
// {
|
||||
// offset: 0,
|
||||
// count: 258,
|
||||
// material: material1
|
||||
// },
|
||||
// {
|
||||
// offset: 258,
|
||||
// count: 1032,
|
||||
// material: material1
|
||||
// }
|
||||
// ]
|
||||
// )
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.UnloadComplete, () => {
|
||||
|
@ -249,7 +347,7 @@ const getStream = () => {
|
|||
// 'https://latest.speckle.dev/streams/f92e060177/commits/038a587267'
|
||||
// 'https://latest.speckle.dev/streams/3f895e614f/commits/8a3e424997'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/f51ee777d5'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/bbd821e3a1'
|
||||
'https://latest.speckle.dev/streams/f92e060177/commits/bbd821e3a1'
|
||||
// Big curves
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/afda4ffdf8'
|
||||
|
@ -296,6 +394,7 @@ const getStream = () => {
|
|||
// 'https://speckle.xyz/streams/88307505eb/objects/a232d760059046b81ff97e6c4530c985'
|
||||
// Airport
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/dfb9ca025d'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/objects/cf8838025d9963b342b09da8de0f8b6b'
|
||||
// 'Blocks with elements
|
||||
// 'https://latest.speckle.dev/streams/e258b0e8db/commits/00e165cc1c'
|
||||
// 'https://latest.speckle.dev/streams/e258b0e8db/commits/e48cf53add'
|
||||
|
@ -372,7 +471,18 @@ const getStream = () => {
|
|||
|
||||
// Rebar
|
||||
// 'https://speckle.xyz/streams/b4086833f8/commits/94df4c6d16?overlay=c5b9c260ea,e3dc287d61,eaedd7d0a5,7f126ce0dd,02fee34ce3,9bda31611f,110282c4db,533c311e29,bf6814d779,1ba52affcf,cc4e75125e,3fd628e4e3'
|
||||
'http://127.0.0.1:3000/streams/30b75f0dea/objects/db765ed44ae10176c0bf8ba60d1ce67d'
|
||||
// Nice towers
|
||||
// 'https://latest.speckle.dev/streams/f4efe4bd7f/objects/5083dffc2ce54ce64c1fc4fab48ca877'
|
||||
// 'http://127.0.0.1:3000/streams/30b75f0dea/objects/db765ed44ae10176c0bf8ba60d1ce67d'
|
||||
|
||||
// 'https://speckle.xyz/streams/7b253e5c4c/commits/025fcbb9cf'
|
||||
// BIG railway
|
||||
// 'https://latest.speckle.dev/streams/a64b432b34/commits/cf7725e404'
|
||||
// 'https://latest.speckle.dev/streams/a64b432b34/objects/1806cb8082a4202b01d97601b6e19af8'
|
||||
// 'https://latest.speckle.dev/streams/a64b432b34/objects/a7ab2388948594e89f838f3026b89839'
|
||||
// 'https://latest.speckle.dev/streams/a64b432b34/commits/99d809460a'
|
||||
// Bunch a doors
|
||||
// 'https://latest.speckle.dev/streams/a64b432b34/commits/c184ba7d88'
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,10 @@
|
|||
"build:dev": "rollup --config",
|
||||
"dev": "rollup --config --watch",
|
||||
"prepack": "yarn build",
|
||||
"lint": "eslint . --ext .js,.ts"
|
||||
"lint": "eslint . --ext .js,.ts",
|
||||
"test": "vitest",
|
||||
"test:ui": "vitest --ui",
|
||||
"test:run": "vitest run"
|
||||
},
|
||||
"author": "AEC Systems",
|
||||
"license": "Apache-2.0",
|
||||
|
@ -74,16 +77,19 @@
|
|||
"@types/three": "^0.136.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
||||
"@typescript-eslint/parser": "^5.39.0",
|
||||
"@vitest/ui": "^1.4.0",
|
||||
"core-js": "^3.21.1",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"jsdom": "^24.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"rollup": "^2.70.1",
|
||||
"rollup-plugin-delete": "^2.0.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-typescript2": "^0.31.2",
|
||||
"typescript": "^4.5.4"
|
||||
"typescript": "^4.5.4",
|
||||
"vitest": "^1.4.0"
|
||||
},
|
||||
"gitHead": "5627e490f9a3ecadf19cc4686ad15f344d9ad2d3"
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ const config = {
|
|||
typescript2({
|
||||
tsconfigOverride: {
|
||||
sourceMap: sourcemap
|
||||
}
|
||||
},
|
||||
tsconfig: './tsconfig.build.json'
|
||||
}),
|
||||
babel({
|
||||
extensions: [...DEFAULT_EXTENSIONS, '.ts', '.tsx'],
|
||||
|
|
|
@ -125,6 +125,17 @@ export enum UpdateFlags {
|
|||
CLIPPING_PLANES = 0b100
|
||||
}
|
||||
|
||||
export interface MaterialOptions {
|
||||
stencilOutlines?: StencilOutlineType
|
||||
pointSize?: number
|
||||
depthWrite?: number
|
||||
}
|
||||
export enum StencilOutlineType {
|
||||
NONE,
|
||||
OVERLAY,
|
||||
OUTLINE_ONLY
|
||||
}
|
||||
|
||||
export interface IViewer {
|
||||
get input(): Input
|
||||
get Utils(): Utils
|
||||
|
|
|
@ -64,7 +64,7 @@ import { LegacyViewer } from './modules/LegacyViewer'
|
|||
import { SpeckleType } from './modules/loaders/GeometryConverter'
|
||||
import Input, { InputEvent } from './modules/input/Input'
|
||||
import { GeometryType } from './modules/batching/Batch'
|
||||
import MeshBatch from './modules/batching/MeshBatch'
|
||||
import { MeshBatch } from './modules/batching/MeshBatch'
|
||||
import SpeckleStandardMaterial from './modules/materials/SpeckleStandardMaterial'
|
||||
import SpeckleTextMaterial from './modules/materials/SpeckleTextMaterial'
|
||||
import { SpeckleText } from './modules/objects/SpeckleText'
|
||||
|
|
|
@ -1,40 +1,42 @@
|
|||
import { MathUtils } from 'three'
|
||||
import {
|
||||
Viewer,
|
||||
BatchObject,
|
||||
PropertyInfo,
|
||||
DataTree,
|
||||
WorldTree,
|
||||
QueryResult,
|
||||
SunLightConfiguration,
|
||||
SpeckleView,
|
||||
CanonicalView,
|
||||
InlineView,
|
||||
VisualDiffMode,
|
||||
DiffResult,
|
||||
MeasurementOptions,
|
||||
CameraController,
|
||||
DiffExtension,
|
||||
ExplodeExtension,
|
||||
MeasurementsExtension,
|
||||
SectionOutlines,
|
||||
SectionTool,
|
||||
SelectionExtension,
|
||||
TreeNode,
|
||||
SpeckleLoader,
|
||||
DefaultViewerParams,
|
||||
ViewerParams,
|
||||
SelectionEvent,
|
||||
IViewer
|
||||
} from '..'
|
||||
import { FilteringExtension, FilteringState } from './extensions/FilteringExtension'
|
||||
import { ICameraProvider, PolarView } from './extensions/core-extensions/Providers'
|
||||
import {
|
||||
CanonicalView,
|
||||
ICameraProvider,
|
||||
InlineView,
|
||||
PolarView
|
||||
} from './extensions/core-extensions/Providers'
|
||||
import { SpeckleType } from './loaders/GeometryConverter'
|
||||
import { Queries } from './queries/Queries'
|
||||
import { Query, QueryArgsResultMap } from './queries/Query'
|
||||
import { DataTreeBuilder } from './tree/DataTree'
|
||||
import { SelectionExtensionOptions } from './extensions/SelectionExtension'
|
||||
import { StencilOutlineType } from './materials/Materials'
|
||||
import { Query, QueryArgsResultMap, QueryResult } from './queries/Query'
|
||||
import { DataTree, DataTreeBuilder } from './tree/DataTree'
|
||||
import {
|
||||
SelectionExtension,
|
||||
SelectionExtensionOptions
|
||||
} from './extensions/SelectionExtension'
|
||||
import { StencilOutlineType } from '../IViewer'
|
||||
import {
|
||||
DefaultViewerParams,
|
||||
IViewer,
|
||||
SelectionEvent,
|
||||
SpeckleView,
|
||||
SunLightConfiguration,
|
||||
ViewerParams
|
||||
} from '../IViewer'
|
||||
import { TreeNode, WorldTree } from './tree/WorldTree'
|
||||
import { Viewer } from './Viewer'
|
||||
import { CameraController } from './extensions/core-extensions/CameraController'
|
||||
import { SectionTool } from './extensions/SectionTool'
|
||||
import { SectionOutlines } from './extensions/SectionOutlines'
|
||||
import {
|
||||
MeasurementOptions,
|
||||
MeasurementsExtension
|
||||
} from './extensions/measurements/MeasurementsExtension'
|
||||
import { ExplodeExtension } from './extensions/ExplodeExtension'
|
||||
import { DiffExtension, DiffResult, VisualDiffMode } from './extensions/DiffExtension'
|
||||
import { PropertyInfo } from './filtering/PropertyManager'
|
||||
import { BatchObject } from './batching/BatchObject'
|
||||
import { SpeckleLoader } from './loaders/Speckle/SpeckleLoader'
|
||||
|
||||
class LegacySelectionExtension extends SelectionExtension {
|
||||
/** FE2 'manually' selects objects pon it's own, so we're disabling the extension's event handler
|
||||
|
|
|
@ -39,7 +39,6 @@ import {
|
|||
ViewerEvent
|
||||
} from '../IViewer'
|
||||
import { DefaultPipelineOptions, Pipeline, PipelineOptions } from './pipeline/Pipeline'
|
||||
import MeshBatch from './batching/MeshBatch'
|
||||
import { Shadowcatcher } from './Shadowcatcher'
|
||||
import SpeckleMesh from './objects/SpeckleMesh'
|
||||
import { ExtendedIntersection } from './objects/SpeckleRaycaster'
|
||||
|
@ -51,15 +50,16 @@ import {
|
|||
import Materials, {
|
||||
RenderMaterial,
|
||||
DisplayStyle,
|
||||
MaterialOptions,
|
||||
FilterMaterial
|
||||
} from './materials/Materials'
|
||||
import { MaterialOptions } from './materials/MaterialOptions'
|
||||
import { SpeckleMaterial } from './materials/SpeckleMaterial'
|
||||
import { SpeckleWebGLRenderer } from './objects/SpeckleWebGLRenderer'
|
||||
import { SpeckleTypeAllRenderables } from './loaders/GeometryConverter'
|
||||
import SpeckleInstancedMesh from './objects/SpeckleInstancedMesh'
|
||||
import { BaseSpecklePass } from './pipeline/SpecklePass'
|
||||
import { CameraController } from './extensions/core-extensions/CameraController'
|
||||
import { MeshBatch } from './batching/MeshBatch'
|
||||
|
||||
export class RenderingStats {
|
||||
private renderTimeAcc = 0
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Box3, Material, Object3D, WebGLRenderer } from 'three'
|
||||
import { FilterMaterialOptions } from '../materials/Materials'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { DrawGroup } from './InstancedMeshBatch'
|
||||
|
||||
export enum GeometryType {
|
||||
MESH,
|
||||
|
@ -26,6 +25,8 @@ export interface Batch {
|
|||
get materials(): Material[]
|
||||
get groups(): DrawGroup[]
|
||||
get triCount(): number
|
||||
get pointCount(): number
|
||||
get lineCount(): number
|
||||
get vertCount(): number
|
||||
|
||||
getCount(): number
|
||||
|
@ -44,7 +45,7 @@ export interface Batch {
|
|||
getStencil(): BatchUpdateRange
|
||||
getDepth(): BatchUpdateRange
|
||||
onUpdate(deltaTime: number)
|
||||
onRender(renderer: WebGLRenderer)
|
||||
onRender?(renderer: WebGLRenderer)
|
||||
purge()
|
||||
}
|
||||
|
||||
|
@ -64,3 +65,16 @@ export const AllBatchUpdateRange = {
|
|||
offset: 0,
|
||||
count: Infinity
|
||||
} as BatchUpdateRange
|
||||
export interface DrawGroup {
|
||||
start: number
|
||||
count: number
|
||||
materialIndex?: number
|
||||
}
|
||||
export interface DrawGroup {
|
||||
start: number
|
||||
count: number
|
||||
materialIndex?: number
|
||||
}
|
||||
|
||||
export const INSTANCE_TRANSFORM_BUFFER_STRIDE = 16
|
||||
export const INSTANCE_GRADIENT_BUFFER_STRIDE = 1
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { MathUtils } from 'three'
|
||||
import MeshBatch from './MeshBatch'
|
||||
import LineBatch from './LineBatch'
|
||||
import Materials, { FilterMaterialType } from '../materials/Materials'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Batch, BatchUpdateRange, GeometryType, NoneBatchUpdateRange } from './Batch'
|
||||
import PointBatch from './PointBatch'
|
||||
import { Material, WebGLRenderer } from 'three'
|
||||
import Logger from 'js-logger'
|
||||
import { AsyncPause } from '../World'
|
||||
|
@ -13,8 +11,10 @@ import TextBatch from './TextBatch'
|
|||
import SpeckleMesh, { TransformStorage } from '../objects/SpeckleMesh'
|
||||
import { SpeckleType } from '../loaders/GeometryConverter'
|
||||
import { TreeNode, WorldTree } from '../..'
|
||||
import InstancedMeshBatch from './InstancedMeshBatch'
|
||||
import { InstancedMeshBatch } from './InstancedMeshBatch'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import { MeshBatch } from './MeshBatch'
|
||||
import { PointBatch } from './PointBatch'
|
||||
|
||||
export default class Batcher {
|
||||
private maxHardwareUniformCount = 0
|
||||
|
@ -206,13 +206,6 @@ export default class Batcher {
|
|||
average / materialHashes.length
|
||||
}`
|
||||
)
|
||||
Logger.warn('Buffer setup -> ', MeshBatch.bufferSetup)
|
||||
Logger.warn('Array work -> ', MeshBatch.arrayWork)
|
||||
Logger.warn('Object BVH -> ', MeshBatch.objectBvh)
|
||||
Logger.warn('Compute normals -> ', MeshBatch.computeNormals)
|
||||
Logger.warn('Compute box and sphere -> ', MeshBatch.computeBoxAndSphere)
|
||||
Logger.warn('Compute RTE -> ', MeshBatch.computeRTE)
|
||||
Logger.warn('Batch BVH -> ', MeshBatch.batchBVH)
|
||||
Logger.warn('Total instanced -> ', totalInstanced)
|
||||
Logger.warn('Instance gathering -> ', instancedGathering)
|
||||
Logger.warn('De-instancing -> ', deInstancing)
|
||||
|
@ -372,7 +365,7 @@ export default class Batcher {
|
|||
|
||||
public render(renderer: WebGLRenderer) {
|
||||
for (const batchId in this.batches) {
|
||||
this.batches[batchId].onRender(renderer)
|
||||
if (this.batches[batchId].onRender) this.batches[batchId].onRender(renderer)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
import { Material } from 'three'
|
||||
import { BatchUpdateRange } from './Batch'
|
||||
import { DrawGroup } from './Batch'
|
||||
|
||||
export class DrawRanges {
|
||||
public integrateRanges(
|
||||
groups: Array<DrawGroup>,
|
||||
materials: Array<Material>,
|
||||
ranges: BatchUpdateRange[]
|
||||
): Array<DrawGroup> {
|
||||
let _flatRanges: Array<number> = []
|
||||
groups.sort((a, b) => a.start - b.start)
|
||||
ranges.sort((a, b) => a.offset - b.offset)
|
||||
|
||||
const edgesForward = {}
|
||||
const edgesBackwards = {}
|
||||
for (let k = 0, l = groups.length - 1; k < groups.length; k++, l--) {
|
||||
const groupForward = groups[k]
|
||||
const groupBackwards = groups[l]
|
||||
edgesForward[groupForward.start] = groupForward.materialIndex
|
||||
edgesBackwards[groupBackwards.start + groupBackwards.count] =
|
||||
groupBackwards.materialIndex
|
||||
}
|
||||
|
||||
_flatRanges = groups.map((group: DrawGroup) => {
|
||||
return group.start + group.count
|
||||
})
|
||||
_flatRanges.unshift(0)
|
||||
|
||||
for (let k = 0; k < ranges.length; k++) {
|
||||
const range = ranges[k]
|
||||
const r0 = range.offset
|
||||
const r0Index = _flatRanges.findIndex((value) => value > r0)
|
||||
const next = _flatRanges[r0Index]
|
||||
_flatRanges.splice(r0Index, 0, r0)
|
||||
|
||||
const r1 = range.offset + range.count
|
||||
const r1Index = _flatRanges.findIndex((value) => value > r1)
|
||||
_flatRanges.splice(r1Index, 0, r1)
|
||||
|
||||
_flatRanges = _flatRanges.filter((value) => {
|
||||
return !(value > r0 && value < r1)
|
||||
})
|
||||
_flatRanges = [...new Set(_flatRanges)]
|
||||
|
||||
const materialIndex = materials.indexOf(range.material)
|
||||
edgesForward[r0] = materialIndex
|
||||
edgesForward[r1] =
|
||||
edgesForward[next] !== undefined ? edgesForward[next] : edgesBackwards[next]
|
||||
}
|
||||
|
||||
const drawRanges = []
|
||||
let groupStart = -1
|
||||
let count = 0
|
||||
for (let k = 0; k < _flatRanges.length - 1; k++) {
|
||||
const start = _flatRanges[k]
|
||||
const end = _flatRanges[k + 1]
|
||||
count += end - start
|
||||
const materialIndex = edgesForward[start]
|
||||
const lastGroup = k === _flatRanges.length - 2
|
||||
if (edgesForward[_flatRanges[k + 1]] === materialIndex || lastGroup) {
|
||||
if (groupStart === -1) {
|
||||
groupStart = start
|
||||
}
|
||||
if (!lastGroup) continue
|
||||
}
|
||||
|
||||
drawRanges.push({
|
||||
start: groupStart === -1 ? start : groupStart,
|
||||
count,
|
||||
materialIndex
|
||||
})
|
||||
groupStart = -1
|
||||
count = 0
|
||||
}
|
||||
|
||||
return drawRanges
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ import {
|
|||
Batch,
|
||||
BatchUpdateRange,
|
||||
GeometryType,
|
||||
INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
NoneBatchUpdateRange
|
||||
} from './Batch'
|
||||
import SpeckleInstancedMesh from '../objects/SpeckleInstancedMesh'
|
||||
|
@ -28,22 +29,18 @@ import {
|
|||
import { InstancedBatchObject } from './InstancedBatchObject'
|
||||
import Logger from 'js-logger'
|
||||
import Materials from '../materials/Materials'
|
||||
import { DrawRanges } from './DrawRanges'
|
||||
import SpeckleStandardColoredMaterial from '../materials/SpeckleStandardColoredMaterial'
|
||||
import { DrawGroup } from './Batch'
|
||||
|
||||
export interface DrawGroup {
|
||||
start: number
|
||||
count: number
|
||||
materialIndex?: number
|
||||
}
|
||||
|
||||
export default class InstancedMeshBatch implements Batch {
|
||||
public static readonly INSTANCE_TRANSFORM_BUFFER_STRIDE = 16
|
||||
public static readonly INSTANCE_GRADIENT_BUFFER_STRIDE = 1
|
||||
export class InstancedMeshBatch implements Batch {
|
||||
public id: string
|
||||
public subtreeId: string
|
||||
public renderViews: NodeRenderView[]
|
||||
private geometry: BufferGeometry
|
||||
public batchMaterial: Material
|
||||
public mesh: SpeckleInstancedMesh
|
||||
private drawRanges: DrawRanges = new DrawRanges()
|
||||
|
||||
private instanceTransformBuffer0: Float32Array = null
|
||||
private instanceTransformBuffer1: Float32Array = null
|
||||
|
@ -51,7 +48,6 @@ export default class InstancedMeshBatch implements Batch {
|
|||
private instanceGradientBuffer: Float32Array = null
|
||||
|
||||
private needsShuffle = false
|
||||
private needsFlatten = false
|
||||
|
||||
public get bounds(): Box3 {
|
||||
return this.mesh.TAS.getBoundingBox(new Box3())
|
||||
|
@ -78,10 +74,12 @@ export default class InstancedMeshBatch implements Batch {
|
|||
return this.geometry.attributes.position.count * this.renderViews.length
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
this.renderViews = renderViews
|
||||
public get pointCount(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public get lineCount(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public get geometryType(): GeometryType {
|
||||
|
@ -104,16 +102,18 @@ export default class InstancedMeshBatch implements Batch {
|
|||
return this.mesh.groups
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
this.renderViews = renderViews
|
||||
}
|
||||
|
||||
public setBatchMaterial(material: Material) {
|
||||
this.batchMaterial = material
|
||||
}
|
||||
|
||||
public onUpdate(deltaTime: number) {
|
||||
deltaTime
|
||||
if (this.needsFlatten) {
|
||||
this.flattenDrawGroups()
|
||||
this.needsFlatten = false
|
||||
}
|
||||
if (this.needsShuffle) {
|
||||
this.shuffleDrawGroups()
|
||||
this.needsShuffle = false
|
||||
|
@ -261,94 +261,14 @@ export default class InstancedMeshBatch implements Batch {
|
|||
0.5 / range[k].materialOptions.rampWidth
|
||||
this.updateGradientIndexBufferData(start / 16, shiftedIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private integrateUpdateRange(range: BatchUpdateRange) {
|
||||
const materialIndex = this.materials.indexOf(range.material)
|
||||
const collidingGroup = this.getDrawRangeCollision(range)
|
||||
if (collidingGroup) {
|
||||
collidingGroup.materialIndex = this.materials.indexOf(range.material)
|
||||
} else {
|
||||
const includingGroup = this.geDrawRangeInclusion(range)
|
||||
if (includingGroup) {
|
||||
if (includingGroup.materialIndex === materialIndex) return
|
||||
this.geometry.groups.splice(this.geometry.groups.indexOf(includingGroup), 1)
|
||||
if (includingGroup.start === range.offset) {
|
||||
this.geometry.addGroup(range.offset, range.count, materialIndex)
|
||||
this.geometry.addGroup(
|
||||
range.offset + range.count,
|
||||
includingGroup.count - range.count,
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
} else if (
|
||||
range.offset + range.count ===
|
||||
includingGroup.start + includingGroup.count
|
||||
) {
|
||||
this.geometry.addGroup(
|
||||
includingGroup.start,
|
||||
includingGroup.count - range.count,
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
this.geometry.addGroup(range.offset, range.count, materialIndex)
|
||||
} else {
|
||||
this.geometry.addGroup(
|
||||
includingGroup.start,
|
||||
range.offset - includingGroup.start,
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
this.geometry.addGroup(range.offset, range.count, materialIndex)
|
||||
this.geometry.addGroup(
|
||||
range.offset + range.count,
|
||||
includingGroup.count - (range.count + range.offset - includingGroup.start),
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const engulfedGroups = this.getDrawRangeEngulfing(range)
|
||||
if (engulfedGroups) {
|
||||
for (let k = 0; k < engulfedGroups.length; k++) {
|
||||
this.geometry.groups.splice(this.groups.indexOf(engulfedGroups[k]), 1)
|
||||
}
|
||||
this.integrateUpdateRange(range)
|
||||
} else {
|
||||
const intersectedGroupLeft = this.getDrawRangeIntersectionLeft(range)
|
||||
if (
|
||||
intersectedGroupLeft &&
|
||||
intersectedGroupLeft.materialIndex !== materialIndex
|
||||
) {
|
||||
this.geometry.groups.splice(
|
||||
this.geometry.groups.indexOf(intersectedGroupLeft),
|
||||
1
|
||||
/** We need to update the texture here, because each batch uses it's own clone for any material we use on it
|
||||
* because otherwise three.js won't properly update our custom uniforms
|
||||
*/
|
||||
if (range[k].materialOptions.rampTexture !== undefined) {
|
||||
if (range[k].material instanceof SpeckleStandardColoredMaterial) {
|
||||
;(range[k].material as SpeckleStandardColoredMaterial).setGradientTexture(
|
||||
range[k].materialOptions.rampTexture
|
||||
)
|
||||
this.geometry.addGroup(range.offset, range.count, materialIndex)
|
||||
this.geometry.addGroup(
|
||||
range.offset + range.count,
|
||||
intersectedGroupLeft.start +
|
||||
intersectedGroupLeft.count -
|
||||
(range.offset + range.count),
|
||||
intersectedGroupLeft.materialIndex
|
||||
)
|
||||
} else {
|
||||
const intersectedGroupRight = this.getDrawRangeIntersectionRight(range)
|
||||
if (
|
||||
intersectedGroupRight &&
|
||||
intersectedGroupRight.materialIndex !== materialIndex
|
||||
) {
|
||||
this.geometry.groups.splice(
|
||||
this.geometry.groups.indexOf(intersectedGroupRight),
|
||||
1
|
||||
)
|
||||
this.geometry.addGroup(
|
||||
intersectedGroupRight.start,
|
||||
range.offset - intersectedGroupRight.start,
|
||||
intersectedGroupRight.materialIndex
|
||||
)
|
||||
this.geometry.addGroup(range.offset, range.count, materialIndex)
|
||||
} else {
|
||||
this.geometry.addGroup(range.offset, range.count, materialIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -372,13 +292,11 @@ export default class InstancedMeshBatch implements Batch {
|
|||
this.materials.push(uniqueMaterials[k])
|
||||
}
|
||||
|
||||
const sortedRanges = ranges.sort((a, b) => {
|
||||
return a.offset - b.offset
|
||||
})
|
||||
|
||||
for (let i = 0; i < sortedRanges.length; i++) {
|
||||
this.integrateUpdateRange(sortedRanges[i])
|
||||
}
|
||||
this.mesh.groups = this.drawRanges.integrateRanges(
|
||||
this.groups,
|
||||
this.materials,
|
||||
ranges
|
||||
)
|
||||
|
||||
let count = 0
|
||||
this.groups.forEach((value) => (count += value.count))
|
||||
|
@ -386,93 +304,18 @@ export default class InstancedMeshBatch implements Batch {
|
|||
Logger.error(`Draw groups invalid on ${this.id}`)
|
||||
}
|
||||
this.setBatchBuffers(...ranges)
|
||||
this.needsFlatten = true
|
||||
this.cleanMaterials()
|
||||
/** We shuffle only when above a certain fragmentation threshold. We don't want to be shuffling every single time */
|
||||
if (this.drawCalls > this.maxDrawCalls) {
|
||||
this.needsShuffle = true
|
||||
} else
|
||||
this.mesh.updateDrawGroups(
|
||||
this.getCurrentTransformBuffer(),
|
||||
this.getCurrentGradientBuffer()
|
||||
)
|
||||
}
|
||||
|
||||
private getDrawRangeCollision(range: BatchUpdateRange): DrawGroup {
|
||||
if (this.groups.length > 0) {
|
||||
for (let i = 0; i < this.groups.length; i++) {
|
||||
if (
|
||||
range.offset === this.groups[i].start &&
|
||||
range.count === this.groups[i].count
|
||||
) {
|
||||
return this.groups[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private geDrawRangeInclusion(range: BatchUpdateRange): DrawGroup {
|
||||
range
|
||||
if (this.groups.length > 0) {
|
||||
for (let i = 0; i < this.groups.length; i++) {
|
||||
if (
|
||||
range.offset >= this.groups[i].start &&
|
||||
range.offset + range.count <= this.groups[i].start + this.groups[i].count
|
||||
) {
|
||||
return this.groups[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private getDrawRangeEngulfing(range: BatchUpdateRange): DrawGroup[] | null {
|
||||
const groups = []
|
||||
if (this.geometry.groups.length > 0) {
|
||||
for (let i = 0; i < this.geometry.groups.length; i++) {
|
||||
if (
|
||||
range.offset <= this.geometry.groups[i].start &&
|
||||
range.offset + range.count >=
|
||||
this.geometry.groups[i].start + this.geometry.groups[i].count
|
||||
) {
|
||||
groups.push(this.geometry.groups[i])
|
||||
}
|
||||
}
|
||||
return groups.length ? groups : null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private getDrawRangeIntersectionLeft(range: BatchUpdateRange): DrawGroup {
|
||||
if (this.geometry.groups.length > 0) {
|
||||
for (let i = 0; i < this.geometry.groups.length; i++) {
|
||||
if (
|
||||
range.offset < this.geometry.groups[i].start &&
|
||||
range.offset + range.count > this.geometry.groups[i].start &&
|
||||
range.offset + range.count <
|
||||
this.geometry.groups[i].start + this.geometry.groups[i].count
|
||||
) {
|
||||
return this.geometry.groups[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private getDrawRangeIntersectionRight(range: BatchUpdateRange): DrawGroup {
|
||||
if (this.geometry.groups.length > 0) {
|
||||
for (let i = 0; i < this.geometry.groups.length; i++) {
|
||||
if (
|
||||
range.offset > this.geometry.groups[i].start &&
|
||||
this.geometry.groups[i].start + this.geometry.groups[i].count >
|
||||
range.offset &&
|
||||
range.offset + range.count >
|
||||
this.geometry.groups[i].start + this.geometry.groups[i].count
|
||||
) {
|
||||
return this.geometry.groups[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private flattenDrawGroups() {
|
||||
private cleanMaterials() {
|
||||
const materialsInUse = [
|
||||
...Array.from(
|
||||
new Set(this.groups.map((value) => this.materials[value.materialIndex]))
|
||||
|
@ -490,65 +333,6 @@ export default class InstancedMeshBatch implements Batch {
|
|||
}
|
||||
k++
|
||||
}
|
||||
const materialOrder = []
|
||||
this.groups.reduce((previousValue, currentValue) => {
|
||||
if (previousValue.indexOf(currentValue.materialIndex) === -1) {
|
||||
previousValue.push(currentValue.materialIndex)
|
||||
}
|
||||
return previousValue
|
||||
}, materialOrder)
|
||||
const grouped = []
|
||||
for (let k = 0; k < materialOrder.length; k++) {
|
||||
grouped.push(
|
||||
this.groups.filter((val) => {
|
||||
return val.materialIndex === materialOrder[k]
|
||||
})
|
||||
)
|
||||
}
|
||||
this.groups.length = 0
|
||||
for (let matIndex = 0; matIndex < grouped.length; matIndex++) {
|
||||
const matGroup = grouped[matIndex].sort((a, b) => {
|
||||
return a.start - b.start
|
||||
})
|
||||
for (let k = 0; k < matGroup.length; ) {
|
||||
let offset = matGroup[k].start
|
||||
let count = matGroup[k].count
|
||||
let runningCount = matGroup[k].count
|
||||
let n = k + 1
|
||||
for (; n < matGroup.length; n++) {
|
||||
if (offset + count === matGroup[n].start) {
|
||||
offset = matGroup[n].start
|
||||
count = matGroup[n].count
|
||||
runningCount += matGroup[n].count
|
||||
} else {
|
||||
const group = {
|
||||
start: matGroup[k].start,
|
||||
count: runningCount,
|
||||
materialIndex: matGroup[k].materialIndex
|
||||
}
|
||||
this.groups.push(group)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (n === matGroup.length) {
|
||||
const group = {
|
||||
start: matGroup[k].start,
|
||||
count: runningCount,
|
||||
materialIndex: matGroup[k].materialIndex
|
||||
}
|
||||
this.groups.push(group)
|
||||
}
|
||||
k = n
|
||||
}
|
||||
}
|
||||
/** We shuffle only when above a certain fragmentation threshold. We don't want to be shuffling every single time */
|
||||
if (this.drawCalls > this.maxDrawCalls) {
|
||||
this.needsShuffle = true
|
||||
} else
|
||||
this.mesh.updateDrawGroups(
|
||||
this.getCurrentTransformBuffer(),
|
||||
this.getCurrentGradientBuffer()
|
||||
)
|
||||
}
|
||||
|
||||
private shuffleDrawGroups() {
|
||||
|
@ -609,12 +393,12 @@ export default class InstancedMeshBatch implements Batch {
|
|||
let subArray = sourceTransformBuffer.subarray(start, start + count)
|
||||
targetTransformBuffer.set(subArray, targetBufferOffset)
|
||||
subArray = sourceGradientBuffer.subarray(
|
||||
start / InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
(start + count) / InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
start / INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
(start + count) / INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
targetGradientBuffer.set(
|
||||
subArray,
|
||||
targetBufferOffset / InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
targetBufferOffset / INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
let rvElemCount = 0
|
||||
for (let m = 0; m < scratchRvs.length; m++) {
|
||||
|
@ -669,8 +453,7 @@ export default class InstancedMeshBatch implements Batch {
|
|||
this.materials.length = 0
|
||||
this.groups.push({
|
||||
start: 0,
|
||||
count:
|
||||
this.renderViews.length * InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
count: this.renderViews.length * INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
materialIndex: 0
|
||||
})
|
||||
this.materials.push(this.batchMaterial)
|
||||
|
@ -701,22 +484,22 @@ export default class InstancedMeshBatch implements Batch {
|
|||
const batchObjects = []
|
||||
let instanceBVH = null
|
||||
this.instanceTransformBuffer0 = new Float32Array(
|
||||
this.renderViews.length * InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
this.renderViews.length * INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
this.instanceTransformBuffer1 = new Float32Array(
|
||||
this.renderViews.length * InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
this.renderViews.length * INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
const targetInstanceTransformBuffer = this.getCurrentTransformBuffer()
|
||||
|
||||
for (let k = 0; k < this.renderViews.length; k++) {
|
||||
this.renderViews[k].renderData.geometry.transform.toArray(
|
||||
targetInstanceTransformBuffer,
|
||||
k * InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
k * INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
this.renderViews[k].setBatchData(
|
||||
this.id,
|
||||
k * InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
k * INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
const batchObject = new InstancedBatchObject(this.renderViews[k], k)
|
||||
if (!instanceBVH) {
|
||||
|
@ -772,8 +555,7 @@ export default class InstancedMeshBatch implements Batch {
|
|||
|
||||
this.groups.push({
|
||||
start: 0,
|
||||
count:
|
||||
this.renderViews.length * InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
count: this.renderViews.length * INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
materialIndex: 0
|
||||
})
|
||||
this.mesh.updateDrawGroups(
|
||||
|
@ -784,13 +566,13 @@ export default class InstancedMeshBatch implements Batch {
|
|||
|
||||
public getRenderView(index: number): NodeRenderView {
|
||||
index
|
||||
Logger.warn('Deprecated! Do not call this anymore')
|
||||
Logger.warn('Deprecated! Use InstancedBatchObject')
|
||||
return null
|
||||
}
|
||||
|
||||
public getMaterialAtIndex(index: number): Material {
|
||||
index
|
||||
Logger.warn('Deprecated! Do not call this anymore')
|
||||
Logger.warn('Deprecated! Use InstancedBatchObject')
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
NoneBatchUpdateRange
|
||||
} from './Batch'
|
||||
import { ObjectLayers } from '../../IViewer'
|
||||
import { DrawGroup } from './InstancedMeshBatch'
|
||||
import { DrawGroup } from './Batch'
|
||||
import Materials from '../materials/Materials'
|
||||
|
||||
export default class LineBatch implements Batch {
|
||||
|
@ -49,7 +49,7 @@ export default class LineBatch implements Batch {
|
|||
}
|
||||
|
||||
public get triCount(): number {
|
||||
return (this.geometry.index.count / 3) * this.geometry['_maxInstanceCount']
|
||||
return 0
|
||||
}
|
||||
|
||||
public get vertCount(): number {
|
||||
|
@ -61,6 +61,12 @@ export default class LineBatch implements Batch {
|
|||
this.subtreeId = subtreeId
|
||||
this.renderViews = renderViews
|
||||
}
|
||||
public get pointCount(): number {
|
||||
return 0
|
||||
}
|
||||
public get lineCount(): number {
|
||||
return (this.geometry.index.count / 3) * this.geometry['_maxInstanceCount']
|
||||
}
|
||||
|
||||
public get renderObject(): Object3D {
|
||||
return this.mesh
|
||||
|
@ -142,13 +148,16 @@ export default class LineBatch implements Batch {
|
|||
if (Materials.isOpaque(this.batchMaterial)) return AllBatchUpdateRange
|
||||
return NoneBatchUpdateRange
|
||||
}
|
||||
|
||||
public getDepth(): BatchUpdateRange {
|
||||
return this.getOpaque()
|
||||
}
|
||||
|
||||
public getTransparent(): BatchUpdateRange {
|
||||
if (Materials.isTransparent(this.batchMaterial)) return AllBatchUpdateRange
|
||||
return NoneBatchUpdateRange
|
||||
}
|
||||
|
||||
public getStencil(): BatchUpdateRange {
|
||||
if (this.batchMaterial.stencilWrite === true) return AllBatchUpdateRange
|
||||
return NoneBatchUpdateRange
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,261 +1,57 @@
|
|||
import {
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
DynamicDrawUsage,
|
||||
Float32BufferAttribute,
|
||||
Material,
|
||||
Object3D,
|
||||
Box3,
|
||||
BufferAttribute,
|
||||
Points,
|
||||
Uint16BufferAttribute,
|
||||
BufferGeometry,
|
||||
Float32BufferAttribute,
|
||||
Uint32BufferAttribute,
|
||||
WebGLRenderer
|
||||
Uint16BufferAttribute,
|
||||
DynamicDrawUsage
|
||||
} from 'three'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
BatchUpdateRange,
|
||||
GeometryType,
|
||||
NoneBatchUpdateRange
|
||||
} from './Batch'
|
||||
import { NodeRenderView } from '../..'
|
||||
import { GeometryType, BatchUpdateRange } from './Batch'
|
||||
import { DrawGroup } from './Batch'
|
||||
import { PrimitiveBatch } from './PrimitiveBatch'
|
||||
import { DrawRanges } from './DrawRanges'
|
||||
import Logger from 'js-logger'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import { ObjectLayers } from '../../IViewer'
|
||||
import { DrawGroup } from './InstancedMeshBatch'
|
||||
import Materials from '../materials/Materials'
|
||||
|
||||
export default class PointBatch implements Batch {
|
||||
public id: string
|
||||
public subtreeId: string
|
||||
public renderViews: NodeRenderView[]
|
||||
private geometry: BufferGeometry
|
||||
public batchMaterial: Material
|
||||
public mesh: Points
|
||||
private needsFlatten = false
|
||||
private needsShuffle = false
|
||||
|
||||
private gradientIndexBuffer: BufferAttribute
|
||||
|
||||
public get bounds() {
|
||||
if (!this.geometry.boundingBox) this.geometry.computeBoundingBox()
|
||||
return this.geometry.boundingBox
|
||||
}
|
||||
|
||||
public get drawCalls(): number {
|
||||
return this.geometry.groups.length
|
||||
}
|
||||
|
||||
public get minDrawCalls(): number {
|
||||
return (this.mesh.material as Material[]).length
|
||||
}
|
||||
|
||||
public get triCount(): number {
|
||||
return this.getCount()
|
||||
}
|
||||
|
||||
public get vertCount(): number {
|
||||
return this.geometry.attributes.position.count
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
this.renderViews = renderViews
|
||||
}
|
||||
|
||||
public get renderObject(): Object3D {
|
||||
return this.mesh
|
||||
}
|
||||
export class PointBatch extends PrimitiveBatch {
|
||||
protected primitive: Points
|
||||
protected drawRanges: DrawRanges = new DrawRanges()
|
||||
|
||||
public get geometryType(): GeometryType {
|
||||
return this.renderViews[0].geometryType
|
||||
}
|
||||
|
||||
public get materials(): Material[] {
|
||||
return this.mesh.material as Material[]
|
||||
public get bounds(): Box3 {
|
||||
if (!this.primitive.geometry.boundingBox)
|
||||
this.primitive.geometry.computeBoundingBox()
|
||||
return this.primitive.geometry.boundingBox
|
||||
}
|
||||
|
||||
public get groups(): DrawGroup[] {
|
||||
return this.geometry.groups
|
||||
public get minDrawCalls(): number {
|
||||
return this.materials.length
|
||||
}
|
||||
|
||||
public getCount() {
|
||||
return this.geometry.attributes.position.array.length / 3
|
||||
public get triCount(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public setBatchMaterial(material: Material) {
|
||||
this.batchMaterial = material
|
||||
public get pointCount(): number {
|
||||
return this.getCount()
|
||||
}
|
||||
|
||||
public onUpdate(deltaTime: number) {
|
||||
deltaTime
|
||||
if (this.needsFlatten) {
|
||||
this.flattenDrawGroups()
|
||||
this.needsFlatten = false
|
||||
}
|
||||
if (this.needsShuffle) {
|
||||
this.shuffleDrawGroups()
|
||||
this.needsShuffle = false
|
||||
}
|
||||
public get lineCount(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public onRender(renderer: WebGLRenderer) {
|
||||
renderer
|
||||
}
|
||||
|
||||
public setVisibleRange(...ranges: BatchUpdateRange[]) {
|
||||
/** Entire batch needs to NOT be drawn */
|
||||
if (ranges.length === 1 && ranges[0] === NoneBatchUpdateRange) {
|
||||
this.geometry.setDrawRange(0, 0)
|
||||
/** We unset the 'visible' flag, otherwise three.js will still run pointless buffer binding commands*/
|
||||
this.mesh.visible = false
|
||||
return
|
||||
}
|
||||
/** Entire batch needs to BE drawn */
|
||||
if (ranges.length === 1 && ranges[0] === AllBatchUpdateRange) {
|
||||
this.geometry.setDrawRange(0, this.getCount())
|
||||
this.mesh.visible = true
|
||||
return
|
||||
}
|
||||
|
||||
/** Parts of the batch need to be visible. We get the min/max offset and total count */
|
||||
let minOffset = Infinity
|
||||
let maxOffset = 0
|
||||
ranges.forEach((range) => {
|
||||
minOffset = Math.min(minOffset, range.offset)
|
||||
maxOffset = Math.max(maxOffset, range.offset)
|
||||
})
|
||||
|
||||
this.geometry.setDrawRange(
|
||||
minOffset,
|
||||
maxOffset - minOffset + ranges.find((val) => val.offset === maxOffset).count
|
||||
)
|
||||
this.mesh.visible = true
|
||||
}
|
||||
|
||||
public getVisibleRange(): BatchUpdateRange {
|
||||
/** Entire batch is visible */
|
||||
if (this.geometry.groups.length === 1 && this.mesh.visible)
|
||||
return AllBatchUpdateRange
|
||||
/** Entire batch is hidden */
|
||||
if (!this.mesh.visible) return NoneBatchUpdateRange
|
||||
/** Parts of the batch are visible */
|
||||
return {
|
||||
offset: this.geometry.drawRange.start,
|
||||
count: this.geometry.drawRange.count
|
||||
}
|
||||
}
|
||||
|
||||
public getOpaque(): BatchUpdateRange {
|
||||
/** If there is any transparent or hidden group return the update range up to it's offset */
|
||||
const transparentOrHiddenGroup = this.groups.find((value) => {
|
||||
return (
|
||||
Materials.isTransparent(this.materials[value.materialIndex]) ||
|
||||
this.materials[value.materialIndex].visible === false
|
||||
)
|
||||
})
|
||||
|
||||
if (transparentOrHiddenGroup) {
|
||||
return {
|
||||
offset: 0,
|
||||
count: transparentOrHiddenGroup.start
|
||||
}
|
||||
}
|
||||
/** Entire batch is opaque */
|
||||
return AllBatchUpdateRange
|
||||
}
|
||||
|
||||
public getDepth(): BatchUpdateRange {
|
||||
/** If there is any transparent or hidden group return the update range up to it's offset */
|
||||
const transparentOrHiddenGroup = this.groups.find((value) => {
|
||||
return (
|
||||
Materials.isTransparent(this.materials[value.materialIndex]) ||
|
||||
this.materials[value.materialIndex].visible === false ||
|
||||
this.materials[value.materialIndex].colorWrite === false
|
||||
)
|
||||
})
|
||||
|
||||
if (transparentOrHiddenGroup) {
|
||||
return {
|
||||
offset: 0,
|
||||
count: transparentOrHiddenGroup.start
|
||||
}
|
||||
}
|
||||
/** Entire batch is opaque */
|
||||
return AllBatchUpdateRange
|
||||
}
|
||||
|
||||
public getTransparent(): BatchUpdateRange {
|
||||
/** Look for a transparent group */
|
||||
const transparentGroup = this.groups.find((value) => {
|
||||
return Materials.isTransparent(this.materials[value.materialIndex])
|
||||
})
|
||||
/** Look for a hidden group */
|
||||
const hiddenGroup = this.groups.find((value) => {
|
||||
return this.materials[value.materialIndex].visible === false
|
||||
})
|
||||
/** If there is a transparent group return it's range */
|
||||
if (transparentGroup) {
|
||||
return {
|
||||
offset: transparentGroup.start,
|
||||
count:
|
||||
hiddenGroup !== undefined
|
||||
? hiddenGroup.start
|
||||
: this.getCount() - transparentGroup.start
|
||||
}
|
||||
}
|
||||
/** Entire batch is not transparent */
|
||||
return NoneBatchUpdateRange
|
||||
}
|
||||
|
||||
public getStencil(): BatchUpdateRange {
|
||||
/** If there is a single group and it's material writes to stencil, return all */
|
||||
if (this.groups.length === 1) {
|
||||
if (this.materials[0].stencilWrite === true) return AllBatchUpdateRange
|
||||
}
|
||||
const stencilGroup = this.groups.find((value) => {
|
||||
return this.materials[value.materialIndex].stencilWrite === true
|
||||
})
|
||||
if (stencilGroup) {
|
||||
return {
|
||||
offset: stencilGroup.start,
|
||||
count: stencilGroup.count
|
||||
}
|
||||
}
|
||||
/** No stencil group */
|
||||
return NoneBatchUpdateRange
|
||||
}
|
||||
|
||||
public setBatchBuffers(...range: BatchUpdateRange[]): void {
|
||||
let minGradientIndex = Infinity
|
||||
let maxGradientIndex = 0
|
||||
for (let k = 0; k < range.length; k++) {
|
||||
if (range[k].materialOptions) {
|
||||
if (range[k].materialOptions.rampIndex !== undefined) {
|
||||
const start = range[k].offset
|
||||
const len = range[k].offset + range[k].count
|
||||
/** The ramp indices specify the *begining* of each ramp color. When sampling with Nearest filter (since we don't want filtering)
|
||||
* we'll always be sampling right at the edge between texels. Most GPUs will sample consistently, but some won't and we end up with
|
||||
* a ton of artifacts. To avoid this, we are shifting the sampling indices so they're right on the center of each texel, so no inconsistent
|
||||
* sampling can occur.
|
||||
*/
|
||||
const shiftedIndex =
|
||||
range[k].materialOptions.rampIndex +
|
||||
0.5 / range[k].materialOptions.rampWidth
|
||||
const minMaxIndices = this.updateGradientIndexBufferData(
|
||||
start,
|
||||
range[k].count === Infinity
|
||||
? this.geometry.attributes['gradientIndex'].array.length
|
||||
: len,
|
||||
shiftedIndex
|
||||
)
|
||||
minGradientIndex = Math.min(minGradientIndex, minMaxIndices.minIndex)
|
||||
maxGradientIndex = Math.max(maxGradientIndex, minMaxIndices.maxIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minGradientIndex < Infinity && maxGradientIndex > 0)
|
||||
this.updateGradientIndexBuffer()
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
super()
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
this.renderViews = renderViews
|
||||
}
|
||||
|
||||
public setDrawRanges(...ranges: BatchUpdateRange[]) {
|
||||
|
@ -269,185 +65,35 @@ export default class PointBatch implements Batch {
|
|||
this.materials.push(uniqueMaterials[k])
|
||||
}
|
||||
|
||||
const sortedRanges = ranges.sort((a, b) => {
|
||||
return a.offset - b.offset
|
||||
})
|
||||
this.primitive.geometry.groups = this.drawRanges.integrateRanges(
|
||||
this.groups,
|
||||
this.materials,
|
||||
ranges
|
||||
)
|
||||
|
||||
for (let i = 0; i < sortedRanges.length; i++) {
|
||||
const materialIndex = this.materials.indexOf(sortedRanges[i].material)
|
||||
const collidingGroup = this.getDrawRangeCollision(sortedRanges[i])
|
||||
if (collidingGroup) {
|
||||
collidingGroup.materialIndex = this.materials.indexOf(sortedRanges[i].material)
|
||||
} else {
|
||||
const includingGroup = this.geDrawRangeInclusion(sortedRanges[i])
|
||||
if (includingGroup && includingGroup.materialIndex !== materialIndex) {
|
||||
this.geometry.groups.splice(this.geometry.groups.indexOf(includingGroup), 1)
|
||||
if (includingGroup.start === sortedRanges[i].offset) {
|
||||
this.geometry.addGroup(
|
||||
sortedRanges[i].offset,
|
||||
sortedRanges[i].count,
|
||||
materialIndex
|
||||
)
|
||||
this.geometry.addGroup(
|
||||
sortedRanges[i].offset + sortedRanges[i].count,
|
||||
includingGroup.count - sortedRanges[i].count,
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
} else if (
|
||||
sortedRanges[i].offset + sortedRanges[i].count ===
|
||||
includingGroup.start + includingGroup.count
|
||||
) {
|
||||
this.geometry.addGroup(
|
||||
includingGroup.start,
|
||||
includingGroup.count - sortedRanges[i].count,
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
this.geometry.addGroup(
|
||||
sortedRanges[i].offset,
|
||||
sortedRanges[i].count,
|
||||
materialIndex
|
||||
)
|
||||
} else {
|
||||
this.geometry.addGroup(
|
||||
includingGroup.start,
|
||||
sortedRanges[i].offset - includingGroup.start,
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
this.geometry.addGroup(
|
||||
sortedRanges[i].offset,
|
||||
sortedRanges[i].count,
|
||||
materialIndex
|
||||
)
|
||||
this.geometry.addGroup(
|
||||
sortedRanges[i].offset + sortedRanges[i].count,
|
||||
includingGroup.count -
|
||||
(sortedRanges[i].count + sortedRanges[i].offset - includingGroup.start),
|
||||
includingGroup.materialIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let count = 0
|
||||
this.geometry.groups.forEach((value) => (count += value.count))
|
||||
this.groups.forEach((value) => (count += value.count))
|
||||
if (count !== this.getCount()) {
|
||||
Logger.error(`Draw groups invalid on ${this.id}`)
|
||||
}
|
||||
this.setBatchBuffers(...ranges)
|
||||
this.needsFlatten = true
|
||||
}
|
||||
this.cleanMaterials()
|
||||
|
||||
private getDrawRangeCollision(range: BatchUpdateRange): {
|
||||
start: number
|
||||
count: number
|
||||
materialIndex?: number
|
||||
} {
|
||||
if (this.geometry.groups.length > 0) {
|
||||
for (let i = 0; i < this.geometry.groups.length; i++) {
|
||||
if (
|
||||
range.offset === this.geometry.groups[i].start &&
|
||||
range.count === this.geometry.groups[i].count
|
||||
) {
|
||||
return this.geometry.groups[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private geDrawRangeInclusion(range: BatchUpdateRange): {
|
||||
start: number
|
||||
count: number
|
||||
materialIndex?: number
|
||||
} {
|
||||
if (this.geometry.groups.length > 0) {
|
||||
for (let i = 0; i < this.geometry.groups.length; i++) {
|
||||
if (
|
||||
range.offset >= this.geometry.groups[i].start &&
|
||||
range.offset + range.count <=
|
||||
this.geometry.groups[i].start + this.geometry.groups[i].count
|
||||
) {
|
||||
return this.geometry.groups[i]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private flattenDrawGroups() {
|
||||
const materialOrder = []
|
||||
this.geometry.groups.reduce((previousValue, currentValue) => {
|
||||
if (previousValue.indexOf(currentValue.materialIndex) === -1) {
|
||||
previousValue.push(currentValue.materialIndex)
|
||||
}
|
||||
return previousValue
|
||||
}, materialOrder)
|
||||
const grouped = []
|
||||
for (let k = 0; k < materialOrder.length; k++) {
|
||||
grouped.push(
|
||||
this.geometry.groups.filter((val) => {
|
||||
return val.materialIndex === materialOrder[k]
|
||||
})
|
||||
)
|
||||
}
|
||||
this.geometry.groups = []
|
||||
for (let matIndex = 0; matIndex < grouped.length; matIndex++) {
|
||||
const matGroup = grouped[matIndex].sort((a, b) => {
|
||||
return a.start - b.start
|
||||
})
|
||||
for (let k = 0; k < matGroup.length; ) {
|
||||
let offset = matGroup[k].start
|
||||
let count = matGroup[k].count
|
||||
let runningCount = matGroup[k].count
|
||||
let n = k + 1
|
||||
for (; n < matGroup.length; n++) {
|
||||
if (offset + count === matGroup[n].start) {
|
||||
offset = matGroup[n].start
|
||||
count = matGroup[n].count
|
||||
runningCount += matGroup[n].count
|
||||
} else {
|
||||
const group = {
|
||||
start: matGroup[k].start,
|
||||
count: runningCount,
|
||||
materialIndex: matGroup[k].materialIndex,
|
||||
id: matGroup[k].id
|
||||
}
|
||||
this.geometry.groups.push(group)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (n === matGroup.length) {
|
||||
const group = {
|
||||
start: matGroup[k].start,
|
||||
count: runningCount,
|
||||
materialIndex: matGroup[k].materialIndex,
|
||||
id: matGroup[k].id
|
||||
}
|
||||
this.geometry.groups.push(group)
|
||||
}
|
||||
k = n
|
||||
}
|
||||
}
|
||||
if (this.drawCalls > this.minDrawCalls + 2) {
|
||||
this.needsShuffle = true
|
||||
} else {
|
||||
this.geometry.groups.sort((a, b) => {
|
||||
return a.start - b.start
|
||||
})
|
||||
const transparentOrHiddenGroup = this.geometry.groups.find(
|
||||
const transparentOrHiddenGroup = this.groups.find(
|
||||
(value) =>
|
||||
this.materials[value.materialIndex].transparent === true ||
|
||||
this.materials[value.materialIndex].visible === false
|
||||
)
|
||||
if (transparentOrHiddenGroup) {
|
||||
for (
|
||||
let k = this.geometry.groups.indexOf(transparentOrHiddenGroup);
|
||||
k < this.geometry.groups.length;
|
||||
let k = this.groups.indexOf(transparentOrHiddenGroup);
|
||||
k < this.groups.length;
|
||||
k++
|
||||
) {
|
||||
const material = this.materials[this.geometry.groups[k].materialIndex]
|
||||
const material = this.materials[this.groups[k].materialIndex]
|
||||
if (material.transparent !== true && material.visible !== false) {
|
||||
this.needsShuffle = true
|
||||
break
|
||||
|
@ -457,123 +103,50 @@ export default class PointBatch implements Batch {
|
|||
}
|
||||
}
|
||||
|
||||
private shuffleDrawGroups() {
|
||||
const groups = this.geometry.groups
|
||||
.sort((a, b) => {
|
||||
return a.start - b.start
|
||||
})
|
||||
.slice()
|
||||
|
||||
this.geometry.groups.sort((a, b) => {
|
||||
const materialA: Material = (this.mesh.material as Array<Material>)[
|
||||
a.materialIndex
|
||||
]
|
||||
const materialB: Material = (this.mesh.material as Array<Material>)[
|
||||
b.materialIndex
|
||||
]
|
||||
const visibleOrder = +materialB.visible - +materialA.visible
|
||||
const transparentOrder = +materialA.transparent - +materialB.transparent
|
||||
if (visibleOrder !== 0) return visibleOrder
|
||||
return transparentOrder
|
||||
})
|
||||
|
||||
const materialOrder = []
|
||||
groups.reduce((previousValue, currentValue) => {
|
||||
if (previousValue.indexOf(currentValue.materialIndex) === -1) {
|
||||
previousValue.push(currentValue.materialIndex)
|
||||
}
|
||||
return previousValue
|
||||
}, materialOrder)
|
||||
|
||||
const grouped = []
|
||||
for (let k = 0; k < materialOrder.length; k++) {
|
||||
grouped.push(
|
||||
groups.filter((val) => {
|
||||
return val.materialIndex === materialOrder[k]
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const sourceIBO: BufferAttribute = this.geometry.index
|
||||
const targetIBOData: Uint16Array | Uint32Array = (
|
||||
sourceIBO.array as Uint16Array | Uint32Array
|
||||
).slice()
|
||||
|
||||
const newGroups = []
|
||||
const scratchRvs = this.renderViews.slice()
|
||||
scratchRvs.sort((a, b) => {
|
||||
return a.batchStart - b.batchStart
|
||||
})
|
||||
let targetIBOOffset = 0
|
||||
for (let k = 0; k < grouped.length; k++) {
|
||||
const materialGroup = grouped[k]
|
||||
const materialGroupStart = targetIBOOffset
|
||||
let materialGroupCount = 0
|
||||
for (let i = 0; i < (materialGroup as []).length; i++) {
|
||||
const start = materialGroup[i].start
|
||||
const count = materialGroup[i].count
|
||||
const subArray = (sourceIBO.array as Uint16Array | Uint32Array).subarray(
|
||||
start,
|
||||
start + count
|
||||
)
|
||||
targetIBOData.set(subArray, targetIBOOffset)
|
||||
let rvTrisCount = 0
|
||||
for (let m = 0; m < scratchRvs.length; m++) {
|
||||
if (
|
||||
scratchRvs[m].batchStart >= start &&
|
||||
scratchRvs[m].batchEnd <= start + count
|
||||
) {
|
||||
scratchRvs[m].setBatchData(
|
||||
this.id,
|
||||
targetIBOOffset + rvTrisCount,
|
||||
scratchRvs[m].batchCount
|
||||
)
|
||||
rvTrisCount += scratchRvs[m].batchCount
|
||||
scratchRvs.splice(m, 1)
|
||||
m--
|
||||
}
|
||||
}
|
||||
targetIBOOffset += count
|
||||
materialGroupCount += count
|
||||
}
|
||||
newGroups.push({
|
||||
offset: materialGroupStart,
|
||||
count: materialGroupCount,
|
||||
materialIndex: materialGroup[0].materialIndex
|
||||
})
|
||||
}
|
||||
this.geometry.groups = []
|
||||
for (let i = 0; i < newGroups.length; i++) {
|
||||
this.geometry.addGroup(
|
||||
newGroups[i].offset,
|
||||
newGroups[i].count,
|
||||
newGroups[i].materialIndex
|
||||
)
|
||||
}
|
||||
|
||||
;(this.geometry.index.array as Uint16Array | Uint32Array).set(targetIBOData)
|
||||
this.geometry.index.needsUpdate = true
|
||||
|
||||
const hiddenGroup = this.geometry.groups.find((value) => {
|
||||
return this.mesh.material[value.materialIndex].visible === false
|
||||
})
|
||||
if (hiddenGroup) {
|
||||
this.setVisibleRange({
|
||||
offset: 0,
|
||||
count: hiddenGroup.start
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public resetDrawRanges() {
|
||||
this.mesh.material = [this.batchMaterial]
|
||||
this.mesh.visible = true
|
||||
this.geometry.clearGroups()
|
||||
this.geometry.addGroup(0, this.getCount(), 0)
|
||||
this.geometry.setDrawRange(0, Infinity)
|
||||
this.primitive.material = [this.batchMaterial]
|
||||
}
|
||||
|
||||
public buildBatch() {
|
||||
protected getCurrentIndexBuffer(): BufferAttribute {
|
||||
return this.primitive.geometry.index
|
||||
}
|
||||
|
||||
protected getNextIndexBuffer(): BufferAttribute {
|
||||
return new BufferAttribute(
|
||||
(this.primitive.geometry.index.array as Uint16Array | Uint32Array).slice(),
|
||||
this.primitive.geometry.index.itemSize
|
||||
)
|
||||
}
|
||||
|
||||
protected shuffleMaterialOrder(a: DrawGroup, b: DrawGroup): number {
|
||||
const materialA: Material = this.materials[a.materialIndex]
|
||||
const materialB: Material = this.materials[b.materialIndex]
|
||||
const visibleOrder = +materialB.visible - +materialA.visible
|
||||
const transparentOrder = +materialA.transparent - +materialB.transparent
|
||||
if (visibleOrder !== 0) return visibleOrder
|
||||
return transparentOrder
|
||||
}
|
||||
|
||||
protected updateGradientIndexBufferData(
|
||||
start: number,
|
||||
end: number,
|
||||
value: number
|
||||
): { minIndex: number; maxIndex: number } {
|
||||
const data = this.gradientIndexBuffer
|
||||
;(data.array as Float32Array).fill(value, start, end)
|
||||
this.gradientIndexBuffer.updateRange = {
|
||||
offset: start,
|
||||
count: end - start
|
||||
}
|
||||
this.gradientIndexBuffer.needsUpdate = true
|
||||
this.primitive.geometry.attributes['gradientIndex'].needsUpdate = true
|
||||
return {
|
||||
minIndex: start,
|
||||
maxIndex: end
|
||||
}
|
||||
}
|
||||
|
||||
public buildBatch(): void {
|
||||
let attributeCount = 0
|
||||
for (let k = 0; k < this.renderViews.length; k++) {
|
||||
attributeCount +=
|
||||
|
@ -605,18 +178,46 @@ export default class PointBatch implements Batch {
|
|||
|
||||
this.renderViews[k].disposeGeometry()
|
||||
}
|
||||
this.makePointGeometry(index, position, color)
|
||||
this.mesh = new Points(this.geometry, this.batchMaterial)
|
||||
this.mesh.material = [this.batchMaterial]
|
||||
this.mesh.geometry.addGroup(0, this.getCount(), 0)
|
||||
this.mesh.uuid = this.id
|
||||
this.mesh.layers.set(
|
||||
const geometry = this.makePointGeometry(index, position, color)
|
||||
this.primitive = new Points(geometry, this.batchMaterial)
|
||||
this.primitive.material = [this.batchMaterial]
|
||||
this.primitive.geometry.addGroup(0, this.getCount(), 0)
|
||||
this.primitive.uuid = this.id
|
||||
this.primitive.layers.set(
|
||||
this.renderViews[0].geometryType === GeometryType.POINT
|
||||
? ObjectLayers.STREAM_CONTENT_POINT
|
||||
: ObjectLayers.STREAM_CONTENT_POINT_CLOUD
|
||||
)
|
||||
}
|
||||
|
||||
protected makePointGeometry(
|
||||
index: Int32Array,
|
||||
position: Float64Array,
|
||||
color: Float32Array
|
||||
): BufferGeometry {
|
||||
const geometry = new BufferGeometry()
|
||||
|
||||
geometry.setAttribute('position', new Float32BufferAttribute(position, 3))
|
||||
geometry.setAttribute('color', new Float32BufferAttribute(color, 3))
|
||||
if (position.length >= 65535 || index.length >= 65535) {
|
||||
geometry.setIndex(new Uint32BufferAttribute(index, 1))
|
||||
} else {
|
||||
geometry.setIndex(new Uint16BufferAttribute(index, 1))
|
||||
}
|
||||
|
||||
const buffer = new Float32Array(position.length / 3)
|
||||
this.gradientIndexBuffer = new Float32BufferAttribute(buffer, 1)
|
||||
this.gradientIndexBuffer.setUsage(DynamicDrawUsage)
|
||||
geometry.setAttribute('gradientIndex', this.gradientIndexBuffer)
|
||||
|
||||
geometry.computeBoundingSphere()
|
||||
geometry.computeBoundingBox()
|
||||
|
||||
Geometry.updateRTEGeometry(geometry, position)
|
||||
|
||||
return geometry
|
||||
}
|
||||
|
||||
public getRenderView(index: number): NodeRenderView {
|
||||
for (let k = 0; k < this.renderViews.length; k++) {
|
||||
if (
|
||||
|
@ -627,7 +228,6 @@ export default class PointBatch implements Batch {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getMaterialAtIndex(index: number): Material {
|
||||
for (let k = 0; k < this.renderViews.length; k++) {
|
||||
if (
|
||||
|
@ -635,103 +235,18 @@ export default class PointBatch implements Batch {
|
|||
index < this.renderViews[k].batchEnd
|
||||
) {
|
||||
const rv = this.renderViews[k]
|
||||
const group = this.geometry.groups.find((value) => {
|
||||
const group = this.groups.find((value) => {
|
||||
return (
|
||||
rv.batchStart >= value.start &&
|
||||
rv.batchStart + rv.batchCount <= value.count + value.start
|
||||
)
|
||||
})
|
||||
if (!Array.isArray(this.mesh.material)) {
|
||||
return this.mesh.material
|
||||
} else {
|
||||
if (!group) {
|
||||
Logger.warn(`Malformed material index!`)
|
||||
return null
|
||||
}
|
||||
return this.mesh.material[group.materialIndex]
|
||||
if (!group) {
|
||||
Logger.warn(`Malformed material index!`)
|
||||
return null
|
||||
}
|
||||
return this.materials[group.materialIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getMaterial(rv: NodeRenderView): Material {
|
||||
for (let k = 0; k < this.geometry.groups.length; k++) {
|
||||
try {
|
||||
if (
|
||||
rv.batchStart >= this.geometry.groups[k].start &&
|
||||
rv.batchEnd <= this.geometry.groups[k].start + this.geometry.groups[k].count
|
||||
) {
|
||||
return this.materials[this.geometry.groups[k].materialIndex]
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error('Failed to get material')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private makePointGeometry(
|
||||
index: Int32Array,
|
||||
position: Float64Array,
|
||||
color: Float32Array
|
||||
): BufferGeometry {
|
||||
this.geometry = new BufferGeometry()
|
||||
|
||||
this.geometry.setAttribute('position', new Float32BufferAttribute(position, 3))
|
||||
this.geometry.setAttribute('color', new Float32BufferAttribute(color, 3))
|
||||
if (position.length >= 65535 || index.length >= 65535) {
|
||||
this.geometry.setIndex(new Uint32BufferAttribute(index, 1))
|
||||
} else {
|
||||
this.geometry.setIndex(new Uint16BufferAttribute(index, 1))
|
||||
}
|
||||
|
||||
const buffer = new Float32Array(position.length / 3)
|
||||
this.gradientIndexBuffer = new Float32BufferAttribute(buffer, 1)
|
||||
this.gradientIndexBuffer.setUsage(DynamicDrawUsage)
|
||||
this.geometry.setAttribute('gradientIndex', this.gradientIndexBuffer)
|
||||
this.updateGradientIndexBufferData(0, buffer.length, 0)
|
||||
this.updateGradientIndexBuffer()
|
||||
|
||||
this.geometry.computeBoundingSphere()
|
||||
this.geometry.computeBoundingBox()
|
||||
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
|
||||
return this.geometry
|
||||
}
|
||||
|
||||
private updateGradientIndexBufferData(
|
||||
start: number,
|
||||
end: number,
|
||||
value: number
|
||||
): { minIndex: number; maxIndex: number } {
|
||||
const data = this.gradientIndexBuffer
|
||||
;(data.array as Float32Array).fill(value, start, end)
|
||||
this.gradientIndexBuffer.updateRange = {
|
||||
offset: start,
|
||||
count: end - start
|
||||
}
|
||||
this.gradientIndexBuffer.needsUpdate = true
|
||||
this.geometry.attributes['gradientIndex'].needsUpdate = true
|
||||
return {
|
||||
minIndex: start,
|
||||
maxIndex: end
|
||||
}
|
||||
}
|
||||
|
||||
private updateGradientIndexBuffer(rangeMin?: number, rangeMax?: number) {
|
||||
this.gradientIndexBuffer.updateRange = {
|
||||
offset: rangeMin !== undefined ? rangeMin : 0,
|
||||
count:
|
||||
rangeMin !== undefined && rangeMax !== undefined ? rangeMax - rangeMin + 1 : -1
|
||||
}
|
||||
this.gradientIndexBuffer.needsUpdate = true
|
||||
this.geometry.attributes['gradientIndex'].needsUpdate = true
|
||||
}
|
||||
|
||||
public purge() {
|
||||
this.renderViews.length = 0
|
||||
this.geometry.dispose()
|
||||
this.batchMaterial.dispose()
|
||||
this.mesh = null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,410 @@
|
|||
import { Material, Object3D, BufferGeometry, BufferAttribute, Box3 } from 'three'
|
||||
import { NodeRenderView } from '../..'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
BatchUpdateRange,
|
||||
GeometryType,
|
||||
NoneBatchUpdateRange
|
||||
} from './Batch'
|
||||
import { DrawGroup } from './Batch'
|
||||
import Materials from '../materials/Materials'
|
||||
import SpeckleStandardColoredMaterial from '../materials/SpeckleStandardColoredMaterial'
|
||||
import Logger from 'js-logger'
|
||||
|
||||
export abstract class Primitive<
|
||||
TGeometry extends BufferGeometry = BufferGeometry,
|
||||
TMaterial extends Material | Material[] = Material | Material[]
|
||||
> extends Object3D {
|
||||
geometry: TGeometry
|
||||
material: TMaterial
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
export abstract class PrimitiveBatch implements Batch {
|
||||
public id: string
|
||||
public subtreeId: string
|
||||
public renderViews: NodeRenderView[]
|
||||
public batchMaterial: Material
|
||||
|
||||
protected abstract primitive: Primitive
|
||||
protected gradientIndexBuffer: BufferAttribute
|
||||
protected needsShuffle: boolean = false
|
||||
|
||||
abstract get geometryType(): GeometryType
|
||||
abstract get bounds(): Box3
|
||||
abstract get minDrawCalls(): number
|
||||
abstract get triCount(): number
|
||||
abstract get pointCount(): number
|
||||
abstract get lineCount(): number
|
||||
|
||||
public get materials(): Material[] {
|
||||
return this.primitive.material as Material[]
|
||||
}
|
||||
|
||||
public get groups(): DrawGroup[] {
|
||||
return this.primitive.geometry.groups
|
||||
}
|
||||
|
||||
public get renderObject(): Object3D {
|
||||
return this.primitive
|
||||
}
|
||||
|
||||
public get drawCalls(): number {
|
||||
return this.groups.length
|
||||
}
|
||||
|
||||
public get vertCount(): number {
|
||||
return this.primitive.geometry.attributes.position.count
|
||||
}
|
||||
|
||||
public getCount(): number {
|
||||
return this.primitive.geometry.index.count
|
||||
}
|
||||
|
||||
public setBatchMaterial(material: Material): void {
|
||||
this.batchMaterial = material
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public onUpdate(deltaTime: number) {
|
||||
if (this.needsShuffle) {
|
||||
this.shuffleDrawGroups()
|
||||
this.needsShuffle = false
|
||||
}
|
||||
}
|
||||
|
||||
public setVisibleRange(...ranges: BatchUpdateRange[]) {
|
||||
/** Entire batch needs to NOT be drawn */
|
||||
if (ranges.length === 1 && ranges[0] === NoneBatchUpdateRange) {
|
||||
this.primitive.geometry.setDrawRange(0, 0)
|
||||
/** We unset the 'visible' flag, otherwise three.js will still run pointless buffer binding commands*/
|
||||
this.primitive.visible = false
|
||||
return
|
||||
}
|
||||
/** Entire batch needs to BE drawn */
|
||||
if (ranges.length === 1 && ranges[0] === AllBatchUpdateRange) {
|
||||
this.primitive.geometry.setDrawRange(0, this.getCount())
|
||||
this.primitive.visible = true
|
||||
return
|
||||
}
|
||||
|
||||
/** Parts of the batch need to be visible. We get the min/max offset and total count */
|
||||
let minOffset = Infinity
|
||||
let maxOffset = 0
|
||||
ranges.forEach((range) => {
|
||||
minOffset = Math.min(minOffset, range.offset)
|
||||
maxOffset = Math.max(maxOffset, range.offset)
|
||||
})
|
||||
|
||||
this.primitive.geometry.setDrawRange(
|
||||
minOffset,
|
||||
maxOffset - minOffset + ranges.find((val) => val.offset === maxOffset).count
|
||||
)
|
||||
this.primitive.visible = true
|
||||
}
|
||||
|
||||
public getVisibleRange(): BatchUpdateRange {
|
||||
/** Entire batch is visible */
|
||||
if (this.primitive.geometry.groups.length === 1 && this.primitive.visible)
|
||||
return AllBatchUpdateRange
|
||||
/** Entire batch is hidden */
|
||||
if (!this.primitive.visible) return NoneBatchUpdateRange
|
||||
/** Parts of the batch are visible */
|
||||
return {
|
||||
offset: this.primitive.geometry.drawRange.start,
|
||||
count: this.primitive.geometry.drawRange.count
|
||||
}
|
||||
}
|
||||
|
||||
public getOpaque(): BatchUpdateRange {
|
||||
/** If there is any transparent or hidden group return the update range up to it's offset */
|
||||
const transparentOrHiddenGroup = this.groups.find((value) => {
|
||||
return (
|
||||
Materials.isTransparent(this.materials[value.materialIndex]) ||
|
||||
this.materials[value.materialIndex].visible === false
|
||||
)
|
||||
})
|
||||
|
||||
if (transparentOrHiddenGroup) {
|
||||
return {
|
||||
offset: 0,
|
||||
count: transparentOrHiddenGroup.start
|
||||
}
|
||||
}
|
||||
/** Entire batch is opaque */
|
||||
return AllBatchUpdateRange
|
||||
}
|
||||
|
||||
public getDepth(): BatchUpdateRange {
|
||||
/** If there is any transparent or hidden group return the update range up to it's offset */
|
||||
const transparentOrHiddenGroup = this.groups.find((value) => {
|
||||
return (
|
||||
Materials.isTransparent(this.materials[value.materialIndex]) ||
|
||||
this.materials[value.materialIndex].visible === false ||
|
||||
this.materials[value.materialIndex].colorWrite === false
|
||||
)
|
||||
})
|
||||
|
||||
if (transparentOrHiddenGroup) {
|
||||
return {
|
||||
offset: 0,
|
||||
count: transparentOrHiddenGroup.start
|
||||
}
|
||||
}
|
||||
/** Entire batch is opaque */
|
||||
return AllBatchUpdateRange
|
||||
}
|
||||
|
||||
public getTransparent(): BatchUpdateRange {
|
||||
/** Look for a transparent group */
|
||||
const transparentGroup = this.groups.find((value) => {
|
||||
return Materials.isTransparent(this.materials[value.materialIndex])
|
||||
})
|
||||
/** Look for a hidden group */
|
||||
const hiddenGroup = this.groups.find((value) => {
|
||||
return this.materials[value.materialIndex].visible === false
|
||||
})
|
||||
/** If there is a transparent group return it's range */
|
||||
if (transparentGroup) {
|
||||
return {
|
||||
offset: transparentGroup.start,
|
||||
count:
|
||||
hiddenGroup !== undefined
|
||||
? hiddenGroup.start
|
||||
: this.getCount() - transparentGroup.start
|
||||
}
|
||||
}
|
||||
/** Entire batch is not transparent */
|
||||
return NoneBatchUpdateRange
|
||||
}
|
||||
|
||||
public getStencil(): BatchUpdateRange {
|
||||
/** If there is a single group and it's material writes to stencil, return all */
|
||||
if (this.groups.length === 1) {
|
||||
if (this.materials[0].stencilWrite === true) return AllBatchUpdateRange
|
||||
}
|
||||
const stencilGroup = this.groups.find((value) => {
|
||||
return this.materials[value.materialIndex].stencilWrite === true
|
||||
})
|
||||
if (stencilGroup) {
|
||||
return {
|
||||
offset: stencilGroup.start,
|
||||
count: stencilGroup.count
|
||||
}
|
||||
}
|
||||
/** No stencil group */
|
||||
return NoneBatchUpdateRange
|
||||
}
|
||||
|
||||
public setBatchBuffers(...range: BatchUpdateRange[]): void {
|
||||
let minGradientIndex = Infinity
|
||||
let maxGradientIndex = 0
|
||||
for (let k = 0; k < range.length; k++) {
|
||||
if (range[k].materialOptions) {
|
||||
if (range[k].materialOptions.rampIndex !== undefined) {
|
||||
const start = range[k].offset
|
||||
const len = range[k].offset + range[k].count
|
||||
/** The ramp indices specify the *begining* of each ramp color. When sampling with Nearest filter (since we don't want filtering)
|
||||
* we'll always be sampling right at the edge between texels. Most GPUs will sample consistently, but some won't and we end up with
|
||||
* a ton of artifacts. To avoid this, we are shifting the sampling indices so they're right on the center of each texel, so no inconsistent
|
||||
* sampling can occur.
|
||||
*/
|
||||
const shiftedIndex =
|
||||
range[k].materialOptions.rampIndex +
|
||||
0.5 / range[k].materialOptions.rampWidth
|
||||
const minMaxIndices = this.updateGradientIndexBufferData(
|
||||
start,
|
||||
range[k].count === Infinity
|
||||
? this.primitive.geometry.attributes['gradientIndex'].array.length
|
||||
: len,
|
||||
shiftedIndex
|
||||
)
|
||||
minGradientIndex = Math.min(minGradientIndex, minMaxIndices.minIndex)
|
||||
maxGradientIndex = Math.max(maxGradientIndex, minMaxIndices.maxIndex)
|
||||
}
|
||||
/** We need to update the texture here, because each batch uses it's own clone for any material we use on it
|
||||
* because otherwise three.js won't properly update our custom uniforms
|
||||
*/
|
||||
if (range[k].materialOptions.rampTexture !== undefined) {
|
||||
if (range[k].material instanceof SpeckleStandardColoredMaterial) {
|
||||
;(range[k].material as SpeckleStandardColoredMaterial).setGradientTexture(
|
||||
range[k].materialOptions.rampTexture
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minGradientIndex < Infinity && maxGradientIndex > 0)
|
||||
this.updateGradientIndexBuffer()
|
||||
}
|
||||
|
||||
protected cleanMaterials() {
|
||||
const materialsInUse = [
|
||||
...Array.from(
|
||||
new Set(this.groups.map((value) => this.materials[value.materialIndex]))
|
||||
)
|
||||
]
|
||||
let k = 0
|
||||
while (this.materials.length > materialsInUse.length) {
|
||||
if (!materialsInUse.includes(this.materials[k])) {
|
||||
this.materials.splice(k, 1)
|
||||
this.groups.forEach((value: DrawGroup) => {
|
||||
if (value.materialIndex > k) value.materialIndex--
|
||||
})
|
||||
k = 0
|
||||
continue
|
||||
}
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract getCurrentIndexBuffer(): BufferAttribute
|
||||
protected abstract getNextIndexBuffer(): BufferAttribute
|
||||
protected abstract shuffleMaterialOrder(a: DrawGroup, b: DrawGroup): number
|
||||
|
||||
private shuffleDrawGroups() {
|
||||
const groups = this.primitive.geometry.groups.slice()
|
||||
groups.sort(this.shuffleMaterialOrder.bind(this))
|
||||
|
||||
const materialOrder = []
|
||||
groups.reduce((previousValue, currentValue) => {
|
||||
if (previousValue.indexOf(currentValue.materialIndex) === -1) {
|
||||
previousValue.push(currentValue.materialIndex)
|
||||
}
|
||||
return previousValue
|
||||
}, materialOrder)
|
||||
|
||||
const grouped = []
|
||||
for (let k = 0; k < materialOrder.length; k++) {
|
||||
grouped.push(
|
||||
groups.filter((val) => {
|
||||
return val.materialIndex === materialOrder[k]
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const sourceIBO: BufferAttribute = this.getCurrentIndexBuffer()
|
||||
const targetIBO: BufferAttribute = this.getNextIndexBuffer()
|
||||
const sourceIBOData: Uint16Array | Uint32Array = sourceIBO.array as
|
||||
| Uint16Array
|
||||
| Uint32Array
|
||||
const targetIBOData: Uint16Array | Uint32Array = targetIBO.array as
|
||||
| Uint16Array
|
||||
| Uint32Array
|
||||
const newGroups = []
|
||||
const scratchRvs = this.renderViews.slice()
|
||||
scratchRvs.sort((a, b) => {
|
||||
return a.batchStart - b.batchStart
|
||||
})
|
||||
let targetIBOOffset = 0
|
||||
for (let k = 0; k < grouped.length; k++) {
|
||||
const materialGroup = grouped[k]
|
||||
const materialGroupStart = targetIBOOffset
|
||||
let materialGroupCount = 0
|
||||
for (let i = 0; i < (materialGroup as []).length; i++) {
|
||||
const start = materialGroup[i].start
|
||||
const count = materialGroup[i].count
|
||||
const subArray = sourceIBOData.subarray(start, start + count)
|
||||
targetIBOData.set(subArray, targetIBOOffset)
|
||||
let rvTrisCount = 0
|
||||
for (let m = 0; m < scratchRvs.length; m++) {
|
||||
if (
|
||||
scratchRvs[m].batchStart >= start &&
|
||||
scratchRvs[m].batchEnd <= start + count
|
||||
) {
|
||||
scratchRvs[m].setBatchData(
|
||||
this.id,
|
||||
targetIBOOffset + rvTrisCount,
|
||||
scratchRvs[m].batchCount
|
||||
)
|
||||
rvTrisCount += scratchRvs[m].batchCount
|
||||
scratchRvs.splice(m, 1)
|
||||
m--
|
||||
}
|
||||
}
|
||||
targetIBOOffset += count
|
||||
materialGroupCount += count
|
||||
}
|
||||
newGroups.push({
|
||||
offset: materialGroupStart,
|
||||
count: materialGroupCount,
|
||||
materialIndex: materialGroup[0].materialIndex
|
||||
})
|
||||
}
|
||||
this.primitive.geometry.groups = []
|
||||
for (let i = 0; i < newGroups.length; i++) {
|
||||
this.primitive.geometry.addGroup(
|
||||
newGroups[i].offset,
|
||||
newGroups[i].count,
|
||||
newGroups[i].materialIndex
|
||||
)
|
||||
}
|
||||
|
||||
this.primitive.geometry.setIndex(targetIBO)
|
||||
this.primitive.geometry.index.needsUpdate = true
|
||||
|
||||
const hiddenGroup = this.primitive.geometry.groups.find((value) => {
|
||||
return this.primitive.material[value.materialIndex].visible === false
|
||||
})
|
||||
if (hiddenGroup) {
|
||||
this.setVisibleRange({
|
||||
offset: 0,
|
||||
count: hiddenGroup.start
|
||||
})
|
||||
}
|
||||
// console.log('Final -> ', this.id, this.groups.slice())
|
||||
}
|
||||
|
||||
protected abstract updateGradientIndexBufferData(
|
||||
start: number,
|
||||
end: number,
|
||||
value: number
|
||||
): { minIndex: number; maxIndex: number }
|
||||
|
||||
protected updateGradientIndexBuffer(rangeMin?: number, rangeMax?: number): void {
|
||||
this.gradientIndexBuffer.updateRange = {
|
||||
offset: rangeMin !== undefined ? rangeMin : 0,
|
||||
count:
|
||||
rangeMin !== undefined && rangeMax !== undefined ? rangeMax - rangeMin + 1 : -1
|
||||
}
|
||||
this.gradientIndexBuffer.needsUpdate = true
|
||||
this.primitive.geometry.attributes['gradientIndex'].needsUpdate = true
|
||||
}
|
||||
|
||||
public abstract setDrawRanges(...ranges: BatchUpdateRange[])
|
||||
|
||||
public resetDrawRanges(): void {
|
||||
this.primitive.visible = true
|
||||
this.primitive.geometry.clearGroups()
|
||||
this.primitive.geometry.addGroup(0, this.getCount(), 0)
|
||||
this.primitive.geometry.setDrawRange(0, Infinity)
|
||||
}
|
||||
|
||||
public abstract buildBatch(): void
|
||||
public abstract getRenderView(index: number): NodeRenderView
|
||||
public abstract getMaterialAtIndex(index: number): Material
|
||||
public getMaterial(rv: NodeRenderView): Material {
|
||||
for (let k = 0; k < this.primitive.geometry.groups.length; k++) {
|
||||
try {
|
||||
if (
|
||||
rv.batchStart >= this.primitive.geometry.groups[k].start &&
|
||||
rv.batchEnd <=
|
||||
this.primitive.geometry.groups[k].start +
|
||||
this.primitive.geometry.groups[k].count
|
||||
) {
|
||||
return this.materials[this.primitive.geometry.groups[k].materialIndex]
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error('Failed to get material')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public purge(): void {
|
||||
this.renderViews.length = 0
|
||||
this.primitive.geometry.dispose()
|
||||
this.batchMaterial.dispose()
|
||||
this.primitive = null
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import {
|
|||
|
||||
import { SpeckleText } from '../objects/SpeckleText'
|
||||
import { ObjectLayers } from '../../IViewer'
|
||||
import { DrawGroup } from './InstancedMeshBatch'
|
||||
import { DrawGroup } from './Batch'
|
||||
import Materials from '../materials/Materials'
|
||||
|
||||
export default class TextBatch implements Batch {
|
||||
|
@ -50,6 +50,12 @@ export default class TextBatch implements Batch {
|
|||
this.subtreeId = subtreeId
|
||||
this.renderViews = renderViews
|
||||
}
|
||||
public get pointCount(): number {
|
||||
return 0
|
||||
}
|
||||
public get lineCount(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
public get geometryType(): GeometryType {
|
||||
return GeometryType.TEXT
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Vector3 } from 'three'
|
||||
import { Extension } from './core-extensions/Extension'
|
||||
import { UpdateFlags } from '../..'
|
||||
import { UpdateFlags } from '../../IViewer'
|
||||
|
||||
export class ExplodeExtension extends Extension {
|
||||
private explodeTime = -1
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
} from 'three'
|
||||
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js'
|
||||
import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js'
|
||||
import MeshBatch from '../batching/MeshBatch'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import SpeckleGhostMaterial from '../materials/SpeckleGhostMaterial'
|
||||
import SpeckleLineMaterial from '../materials/SpeckleLineMaterial'
|
||||
|
@ -21,6 +20,7 @@ import { ISectionProvider } from './core-extensions/Providers'
|
|||
import { SectionToolEvent } from './SectionTool'
|
||||
import { GeometryType } from '../batching/Batch'
|
||||
import { ObjectLayers } from '../../IViewer'
|
||||
import { MeshBatch } from '../batching/MeshBatch'
|
||||
import Logger from 'js-logger'
|
||||
|
||||
export enum PlaneId {
|
||||
|
|
|
@ -12,12 +12,9 @@ import {
|
|||
UpdateFlags,
|
||||
ViewerEvent
|
||||
} from '../../IViewer'
|
||||
import Materials, {
|
||||
DisplayStyle,
|
||||
MaterialOptions,
|
||||
RenderMaterial,
|
||||
StencilOutlineType
|
||||
} from '../materials/Materials'
|
||||
import Materials, { DisplayStyle, RenderMaterial } from '../materials/Materials'
|
||||
import { StencilOutlineType } from '../../IViewer'
|
||||
import { MaterialOptions } from '../materials/MaterialOptions'
|
||||
import { TreeNode } from '../tree/WorldTree'
|
||||
|
||||
export interface SelectionExtensionOptions {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { StencilOutlineType } from '../../IViewer'
|
||||
|
||||
export interface MaterialOptions {
|
||||
stencilOutlines?: StencilOutlineType
|
||||
pointSize?: number
|
||||
depthWrite?: number
|
||||
}
|
|
@ -13,6 +13,7 @@ import SpeckleGhostMaterial from './SpeckleGhostMaterial'
|
|||
import SpeckleTextMaterial from './SpeckleTextMaterial'
|
||||
import { SpeckleMaterial } from './SpeckleMaterial'
|
||||
import SpecklePointColouredMaterial from './SpecklePointColouredMaterial'
|
||||
import { MaterialOptions } from '../../IViewer'
|
||||
|
||||
export interface RenderMaterial {
|
||||
id: string
|
||||
|
@ -30,18 +31,6 @@ export interface DisplayStyle {
|
|||
opacity?: number
|
||||
}
|
||||
|
||||
export interface MaterialOptions {
|
||||
stencilOutlines?: StencilOutlineType
|
||||
pointSize?: number
|
||||
depthWrite?: number
|
||||
}
|
||||
|
||||
export enum StencilOutlineType {
|
||||
NONE,
|
||||
OVERLAY,
|
||||
OUTLINE_ONLY
|
||||
}
|
||||
|
||||
export enum FilterMaterialType {
|
||||
GHOST,
|
||||
GRADIENT,
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
import { speckleLineVert } from './shaders/speckle-line-vert'
|
||||
import { speckleLineFrag } from './shaders/speckle-line-frag'
|
||||
import { ShaderLib, Vector3, IUniform, Material } from 'three'
|
||||
import { Matrix4 } from 'three'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import { ExtendedLineMaterial, Uniforms } from './SpeckleMaterial'
|
||||
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ import {
|
|||
UniformsUtils
|
||||
} from 'three'
|
||||
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
|
||||
import { MaterialOptions, StencilOutlineType } from './Materials'
|
||||
import { StencilOutlineType } from '../../IViewer'
|
||||
import { MaterialOptions } from './MaterialOptions'
|
||||
|
||||
class SpeckleUserData {
|
||||
toJSON() {
|
||||
|
|
|
@ -17,7 +17,11 @@ import {
|
|||
import { BatchObject } from '../batching/BatchObject'
|
||||
import Materials from '../materials/Materials'
|
||||
import { TopLevelAccelerationStructure } from './TopLevelAccelerationStructure'
|
||||
import InstancedMeshBatch, { DrawGroup } from '../batching/InstancedMeshBatch'
|
||||
import {
|
||||
DrawGroup,
|
||||
INSTANCE_GRADIENT_BUFFER_STRIDE,
|
||||
INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
} from '../batching/Batch'
|
||||
import { ObjectLayers } from '../../IViewer'
|
||||
import Logger from 'js-logger'
|
||||
|
||||
|
@ -152,21 +156,20 @@ export default class SpeckleInstancedMesh extends Group {
|
|||
this.groups[k].start,
|
||||
this.groups[k].start + this.groups[k].count
|
||||
),
|
||||
InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
)
|
||||
group.geometry.setAttribute(
|
||||
'gradientIndex',
|
||||
new InstancedBufferAttribute(
|
||||
gradientBuffer.subarray(
|
||||
this.groups[k].start / InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
this.groups[k].start / INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
(this.groups[k].start + this.groups[k].count) /
|
||||
InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
),
|
||||
InstancedMeshBatch.INSTANCE_GRADIENT_BUFFER_STRIDE
|
||||
INSTANCE_GRADIENT_BUFFER_STRIDE
|
||||
)
|
||||
)
|
||||
group.count =
|
||||
this.groups[k].count / InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
group.count = this.groups[k].count / INSTANCE_TRANSFORM_BUFFER_STRIDE
|
||||
group.instanceMatrix.needsUpdate = true
|
||||
group.layers.set(ObjectLayers.STREAM_CONTENT_MESH)
|
||||
group.frustumCulled = false
|
||||
|
@ -193,8 +196,7 @@ export default class SpeckleInstancedMesh extends Group {
|
|||
if (group) {
|
||||
const instance: InstancedMesh = this.instances[this.groups.indexOf(group)]
|
||||
instance.setMatrixAt(
|
||||
(rv.batchStart - group.start) /
|
||||
InstancedMeshBatch.INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
(rv.batchStart - group.start) / INSTANCE_TRANSFORM_BUFFER_STRIDE,
|
||||
batchObject.transform
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Draw Ranges > Boundary Ranges 1`] = `
|
||||
[
|
||||
{
|
||||
"count": 2095,
|
||||
"materialIndex": 1,
|
||||
"start": 0,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Draw Ranges > Boundary Ranges 2`] = `
|
||||
[
|
||||
{
|
||||
"count": 2094,
|
||||
"materialIndex": 0,
|
||||
"start": 0,
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"materialIndex": 1,
|
||||
"start": 2094,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Draw Ranges > Boundary Ranges 3`] = `
|
||||
[
|
||||
{
|
||||
"count": 2094,
|
||||
"materialIndex": 0,
|
||||
"start": 0,
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"materialIndex": 1,
|
||||
"start": 2094,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Draw Ranges > Mixed Ranges 1`] = `
|
||||
[
|
||||
{
|
||||
"count": 36,
|
||||
"materialIndex": 0,
|
||||
"start": 0,
|
||||
},
|
||||
{
|
||||
"count": 36,
|
||||
"materialIndex": 1,
|
||||
"start": 36,
|
||||
},
|
||||
{
|
||||
"count": 108,
|
||||
"materialIndex": 0,
|
||||
"start": 72,
|
||||
},
|
||||
{
|
||||
"count": 1395,
|
||||
"materialIndex": 1,
|
||||
"start": 180,
|
||||
},
|
||||
{
|
||||
"count": 6,
|
||||
"materialIndex": 0,
|
||||
"start": 1575,
|
||||
},
|
||||
{
|
||||
"count": 32766,
|
||||
"materialIndex": 1,
|
||||
"start": 1581,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Draw Ranges > Multiple Materials 1`] = `
|
||||
[
|
||||
{
|
||||
"count": 36,
|
||||
"materialIndex": 3,
|
||||
"start": 0,
|
||||
},
|
||||
{
|
||||
"count": 257,
|
||||
"materialIndex": 4,
|
||||
"start": 36,
|
||||
},
|
||||
{
|
||||
"count": 1246,
|
||||
"materialIndex": 1,
|
||||
"start": 293,
|
||||
},
|
||||
{
|
||||
"count": 540,
|
||||
"materialIndex": 0,
|
||||
"start": 1539,
|
||||
},
|
||||
{
|
||||
"count": 32268,
|
||||
"materialIndex": 2,
|
||||
"start": 2079,
|
||||
},
|
||||
]
|
||||
`;
|
|
@ -0,0 +1,155 @@
|
|||
import { expect, describe, it } from 'vitest'
|
||||
import { DrawRanges } from '../src/modules/batching/DrawRanges'
|
||||
import SpeckleBasicMaterial from '../src/modules/materials/SpeckleBasicMaterial'
|
||||
import { DrawGroup } from '../src/modules/batching/Batch'
|
||||
|
||||
const material0 = new SpeckleBasicMaterial({ color: 0xff0000 })
|
||||
const material1 = new SpeckleBasicMaterial({ color: 0x00ff00 })
|
||||
|
||||
describe('Draw Ranges', () => {
|
||||
it('Boundary Ranges', () => {
|
||||
const drawRange = new DrawRanges()
|
||||
let groups = [
|
||||
{
|
||||
start: 0,
|
||||
count: 2095,
|
||||
materialIndex: 0
|
||||
} as DrawGroup
|
||||
]
|
||||
groups = drawRange.integrateRanges(
|
||||
groups,
|
||||
[material0, material1],
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
count: 2095,
|
||||
material: material1
|
||||
}
|
||||
]
|
||||
)
|
||||
expect(groups).toMatchSnapshot()
|
||||
|
||||
groups = drawRange.integrateRanges(
|
||||
groups,
|
||||
[material0, material1],
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
count: 2094,
|
||||
material: material0
|
||||
}
|
||||
]
|
||||
)
|
||||
expect(groups).toMatchSnapshot()
|
||||
|
||||
groups = [
|
||||
{
|
||||
start: 0,
|
||||
count: 2095,
|
||||
materialIndex: 0
|
||||
} as DrawGroup
|
||||
]
|
||||
groups = drawRange.integrateRanges(
|
||||
groups,
|
||||
[material0, material1],
|
||||
[
|
||||
{
|
||||
offset: 2094,
|
||||
count: 1,
|
||||
material: material1
|
||||
}
|
||||
]
|
||||
)
|
||||
expect(groups).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('Mixed Ranges', () => {
|
||||
let groups = [
|
||||
{
|
||||
start: 0,
|
||||
count: 216,
|
||||
materialIndex: 0
|
||||
} as DrawGroup,
|
||||
{
|
||||
start: 216,
|
||||
count: 1323,
|
||||
materialIndex: 0
|
||||
} as DrawGroup,
|
||||
{
|
||||
start: 1539,
|
||||
count: 540,
|
||||
materialIndex: 0
|
||||
} as DrawGroup,
|
||||
{
|
||||
start: 2079,
|
||||
count: 32268,
|
||||
materialIndex: 0
|
||||
} as DrawGroup
|
||||
]
|
||||
|
||||
const drawRange = new DrawRanges()
|
||||
|
||||
groups = drawRange.integrateRanges(
|
||||
groups,
|
||||
[material0, material1],
|
||||
[
|
||||
{ offset: 36, count: 36, material: material1 },
|
||||
{
|
||||
offset: 180,
|
||||
count: 1395,
|
||||
material: material1
|
||||
},
|
||||
{
|
||||
offset: 1581,
|
||||
count: 32766,
|
||||
material: material1
|
||||
}
|
||||
]
|
||||
)
|
||||
expect(groups).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('Multiple Materials', () => {
|
||||
const material2 = new SpeckleBasicMaterial({ color: 0x0000ff })
|
||||
const material3 = new SpeckleBasicMaterial({ color: 0x0000ff })
|
||||
const material4 = new SpeckleBasicMaterial({ color: 0x0000ff })
|
||||
|
||||
let groups = [
|
||||
{
|
||||
start: 0,
|
||||
count: 216,
|
||||
materialIndex: 3
|
||||
} as DrawGroup,
|
||||
{
|
||||
start: 216,
|
||||
count: 1323,
|
||||
materialIndex: 1
|
||||
} as DrawGroup,
|
||||
{
|
||||
start: 1539,
|
||||
count: 540,
|
||||
materialIndex: 0
|
||||
} as DrawGroup,
|
||||
{
|
||||
start: 2079,
|
||||
count: 32268,
|
||||
materialIndex: 2
|
||||
} as DrawGroup
|
||||
]
|
||||
|
||||
const drawRange = new DrawRanges()
|
||||
|
||||
groups = drawRange.integrateRanges(
|
||||
groups,
|
||||
[material0, material1, material2, material3, material4],
|
||||
[
|
||||
{
|
||||
offset: 36,
|
||||
count: 257,
|
||||
material: material4
|
||||
}
|
||||
]
|
||||
)
|
||||
expect(groups).toMatchSnapshot()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist", "test"]
|
||||
}
|
|
@ -17,6 +17,6 @@
|
|||
"checkJs": false,
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"include": ["./src/**/*", "test"],
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference types="vitest" />
|
||||
|
||||
// Configure Vitest (https://vitest.dev/config/)
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: 'jsdom'
|
||||
// globals: true,
|
||||
}
|
||||
})
|
479
yarn.lock
479
yarn.lock
|
@ -10607,6 +10607,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/schemas@npm:^29.6.3":
|
||||
version: 29.6.3
|
||||
resolution: "@jest/schemas@npm:29.6.3"
|
||||
dependencies:
|
||||
"@sinclair/typebox": ^0.27.8
|
||||
checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/source-map@npm:^27.5.1":
|
||||
version: 27.5.1
|
||||
resolution: "@jest/source-map@npm:27.5.1"
|
||||
|
@ -13772,6 +13781,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sinclair/typebox@npm:^0.27.8":
|
||||
version: 0.27.8
|
||||
resolution: "@sinclair/typebox@npm:0.27.8"
|
||||
checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sindresorhus/is@npm:^4.0.0":
|
||||
version: 4.6.0
|
||||
resolution: "@sindresorhus/is@npm:4.6.0"
|
||||
|
@ -14568,6 +14584,7 @@ __metadata:
|
|||
"@types/three": ^0.136.0
|
||||
"@typescript-eslint/eslint-plugin": ^5.39.0
|
||||
"@typescript-eslint/parser": ^5.39.0
|
||||
"@vitest/ui": ^1.4.0
|
||||
camera-controls: ^1.33.1
|
||||
core-js: ^3.21.1
|
||||
eslint: ^8.11.0
|
||||
|
@ -14575,6 +14592,7 @@ __metadata:
|
|||
flat: ^5.0.2
|
||||
hold-event: ^0.1.0
|
||||
js-logger: 1.6.1
|
||||
jsdom: ^24.0.0
|
||||
lodash-es: ^4.17.21
|
||||
prettier: ^2.5.1
|
||||
rainbowvis.js: ^1.0.1
|
||||
|
@ -14590,6 +14608,7 @@ __metadata:
|
|||
troika-three-text: 0.47.2
|
||||
typescript: ^4.5.4
|
||||
underscore: 1.13.6
|
||||
vitest: ^1.4.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
|
@ -18467,6 +18486,77 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/expect@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/expect@npm:1.4.0"
|
||||
dependencies:
|
||||
"@vitest/spy": 1.4.0
|
||||
"@vitest/utils": 1.4.0
|
||||
chai: ^4.3.10
|
||||
checksum: aca8b0b592bc020febb08767a230a2f4118453904972df06b2a34c76a669e8eb260ddfd8b0cdc152e93dbf21e0d7ae98bdf09fa80477b21145ac21c01fc5a0d3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/runner@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/runner@npm:1.4.0"
|
||||
dependencies:
|
||||
"@vitest/utils": 1.4.0
|
||||
p-limit: ^5.0.0
|
||||
pathe: ^1.1.1
|
||||
checksum: 41a847d1ba916c64e482a69342222a40b81014ad06da7ccb7d8cd4119c5718564c22b00367574803642e6ca6ab5678509073b5c460bedc2b385d4e990351012f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/snapshot@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/snapshot@npm:1.4.0"
|
||||
dependencies:
|
||||
magic-string: ^0.30.5
|
||||
pathe: ^1.1.1
|
||||
pretty-format: ^29.7.0
|
||||
checksum: fe495661d682534b41f3ac373c017ac84c04263087a715307715bb41a69c307d6f237b18cc8195bc22d82bf38a1a1a773b0c99715d5de5f40c6169e916b8f4a4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/spy@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/spy@npm:1.4.0"
|
||||
dependencies:
|
||||
tinyspy: ^2.2.0
|
||||
checksum: 3b1c422760e5840e9e4aa804de7619f3d14e0b364b29f8f030df528206b84c5706792c5d680ac668077d5663f8648a17a783df11cd90ddf2a11000359f1a6286
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/ui@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/ui@npm:1.4.0"
|
||||
dependencies:
|
||||
"@vitest/utils": 1.4.0
|
||||
fast-glob: ^3.3.2
|
||||
fflate: ^0.8.1
|
||||
flatted: ^3.2.9
|
||||
pathe: ^1.1.1
|
||||
picocolors: ^1.0.0
|
||||
sirv: ^2.0.4
|
||||
peerDependencies:
|
||||
vitest: 1.4.0
|
||||
checksum: 5a508fd80fcdf87acf4697ae8836cf4dcdd5300fd1574a400a62f5242a6bb4028b3002d60db20f84c3e3e4b4ae110b33194c31219330fffe205e5d9fbf1c65c8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/utils@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/utils@npm:1.4.0"
|
||||
dependencies:
|
||||
diff-sequences: ^29.6.3
|
||||
estree-walker: ^3.0.3
|
||||
loupe: ^2.3.7
|
||||
pretty-format: ^29.7.0
|
||||
checksum: 5b54e36e5ad236da1da548d31e3b080d1798179f787cfb9ac512d03e59401f8baaa96fec15b6de6b969ee0e057660289109a69a39bd988e89aa72625b5f78484
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@volar/language-core@npm:1.10.1, @volar/language-core@npm:~1.10.0":
|
||||
version: 1.10.1
|
||||
resolution: "@volar/language-core@npm:1.10.1"
|
||||
|
@ -20264,6 +20354,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"acorn-walk@npm:^8.3.2":
|
||||
version: 8.3.2
|
||||
resolution: "acorn-walk@npm:8.3.2"
|
||||
checksum: 3626b9d26a37b1b427796feaa5261faf712307a8920392c8dce9a5739fb31077667f4ad2ec71c7ac6aaf9f61f04a9d3d67ff56f459587206fc04aa31c27ef392
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"acorn@npm:8.10.0, acorn@npm:^8.9.0":
|
||||
version: 8.10.0
|
||||
resolution: "acorn@npm:8.10.0"
|
||||
|
@ -22723,6 +22820,21 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chai@npm:^4.3.10":
|
||||
version: 4.4.1
|
||||
resolution: "chai@npm:4.4.1"
|
||||
dependencies:
|
||||
assertion-error: ^1.1.0
|
||||
check-error: ^1.0.3
|
||||
deep-eql: ^4.1.3
|
||||
get-func-name: ^2.0.2
|
||||
loupe: ^2.3.6
|
||||
pathval: ^1.1.1
|
||||
type-detect: ^4.0.8
|
||||
checksum: 9ab84f36eb8e0b280c56c6c21ca4da5933132cd8a0c89c384f1497f77953640db0bc151edd47f81748240a9fab57b78f7d925edfeedc8e8fc98016d71f40c36e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^2.0.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2":
|
||||
version: 2.4.2
|
||||
resolution: "chalk@npm:2.4.2"
|
||||
|
@ -22868,6 +22980,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"check-error@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "check-error@npm:1.0.3"
|
||||
dependencies:
|
||||
get-func-name: ^2.0.2
|
||||
checksum: e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cheerio-select@npm:^1.5.0":
|
||||
version: 1.6.0
|
||||
resolution: "cheerio-select@npm:1.6.0"
|
||||
|
@ -24514,6 +24635,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssstyle@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "cssstyle@npm:4.0.1"
|
||||
dependencies:
|
||||
rrweb-cssom: ^0.6.0
|
||||
checksum: 4b2fdd81c565b1f8f24a792f85d3a19269a2f201e731c3fe3531d7fc78b4bc6b31906ed17aba7edba7b1c8b7672574fc6c09fe925556da3a9a9458dbf8c4fa22
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"csstype@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "csstype@npm:3.1.0"
|
||||
|
@ -24748,6 +24878,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"data-urls@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "data-urls@npm:5.0.0"
|
||||
dependencies:
|
||||
whatwg-mimetype: ^4.0.0
|
||||
whatwg-url: ^14.0.0
|
||||
checksum: 5c40568c31b02641a70204ff233bc4e42d33717485d074244a98661e5f2a1e80e38fe05a5755dfaf2ee549f2ab509d6a3af2a85f4b2ad2c984e5d176695eaf46
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dataloader@npm:2.1.0, dataloader@npm:^2.0.0":
|
||||
version: 2.1.0
|
||||
resolution: "dataloader@npm:2.1.0"
|
||||
|
@ -24913,6 +25053,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decimal.js@npm:^10.4.3":
|
||||
version: 10.4.3
|
||||
resolution: "decimal.js@npm:10.4.3"
|
||||
checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decompress-response@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "decompress-response@npm:6.0.0"
|
||||
|
@ -24938,6 +25085,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"deep-eql@npm:^4.1.3":
|
||||
version: 4.1.3
|
||||
resolution: "deep-eql@npm:4.1.3"
|
||||
dependencies:
|
||||
type-detect: ^4.0.0
|
||||
checksum: 7f6d30cb41c713973dc07eaadded848b2ab0b835e518a88b91bea72f34e08c4c71d167a722a6f302d3a6108f05afd8e6d7650689a84d5d29ec7fe6220420397f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"deep-equal-in-any-order@npm:^1.1.15":
|
||||
version: 1.1.17
|
||||
resolution: "deep-equal-in-any-order@npm:1.1.17"
|
||||
|
@ -25445,6 +25601,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"diff-sequences@npm:^29.6.3":
|
||||
version: 29.6.3
|
||||
resolution: "diff-sequences@npm:29.6.3"
|
||||
checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"diff@npm:5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "diff@npm:5.0.0"
|
||||
|
@ -26059,7 +26222,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"entities@npm:^4.5.0":
|
||||
"entities@npm:^4.4.0, entities@npm:^4.5.0":
|
||||
version: 4.5.0
|
||||
resolution: "entities@npm:4.5.0"
|
||||
checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7
|
||||
|
@ -27669,6 +27832,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fflate@npm:^0.8.1":
|
||||
version: 0.8.2
|
||||
resolution: "fflate@npm:0.8.2"
|
||||
checksum: 29470337b85d3831826758e78f370e15cda3169c5cd4477c9b5eea2402261a74b2975bae816afabe1c15d21d98591e0d30a574f7103aa117bff60756fa3035d4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"figures@npm:^3.0.0":
|
||||
version: 3.2.0
|
||||
resolution: "figures@npm:3.2.0"
|
||||
|
@ -28343,7 +28513,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-func-name@npm:^2.0.0":
|
||||
"get-func-name@npm:^2.0.0, get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "get-func-name@npm:2.0.2"
|
||||
checksum: 3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b
|
||||
|
@ -29585,6 +29755,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-encoding-sniffer@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "html-encoding-sniffer@npm:4.0.0"
|
||||
dependencies:
|
||||
whatwg-encoding: ^3.1.1
|
||||
checksum: 3339b71dab2723f3159a56acf541ae90a408ce2d11169f00fe7e0c4663d31d6398c8a4408b504b4eec157444e47b084df09b3cb039c816660f0dd04846b8957d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-entities@npm:^2.3.2":
|
||||
version: 2.3.3
|
||||
resolution: "html-entities@npm:2.3.3"
|
||||
|
@ -32789,6 +32968,40 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jsdom@npm:^24.0.0":
|
||||
version: 24.0.0
|
||||
resolution: "jsdom@npm:24.0.0"
|
||||
dependencies:
|
||||
cssstyle: ^4.0.1
|
||||
data-urls: ^5.0.0
|
||||
decimal.js: ^10.4.3
|
||||
form-data: ^4.0.0
|
||||
html-encoding-sniffer: ^4.0.0
|
||||
http-proxy-agent: ^7.0.0
|
||||
https-proxy-agent: ^7.0.2
|
||||
is-potential-custom-element-name: ^1.0.1
|
||||
nwsapi: ^2.2.7
|
||||
parse5: ^7.1.2
|
||||
rrweb-cssom: ^0.6.0
|
||||
saxes: ^6.0.0
|
||||
symbol-tree: ^3.2.4
|
||||
tough-cookie: ^4.1.3
|
||||
w3c-xmlserializer: ^5.0.0
|
||||
webidl-conversions: ^7.0.0
|
||||
whatwg-encoding: ^3.1.1
|
||||
whatwg-mimetype: ^4.0.0
|
||||
whatwg-url: ^14.0.0
|
||||
ws: ^8.16.0
|
||||
xml-name-validator: ^5.0.0
|
||||
peerDependencies:
|
||||
canvas: ^2.11.2
|
||||
peerDependenciesMeta:
|
||||
canvas:
|
||||
optional: true
|
||||
checksum: 180cf672c1f5e4375fd831b6990c453b4c22b540619abe7a0a3ed0d18eca1171dea9f25739bc06dfea26d1c0d71c7ac26e62fc9a2d9b1657003fc8fd1bf6f9f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jsesc@npm:^2.5.1":
|
||||
version: 2.5.2
|
||||
resolution: "jsesc@npm:2.5.2"
|
||||
|
@ -33983,6 +34196,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^2.3.6, loupe@npm:^2.3.7":
|
||||
version: 2.3.7
|
||||
resolution: "loupe@npm:2.3.7"
|
||||
dependencies:
|
||||
get-func-name: ^2.0.1
|
||||
checksum: 96c058ec7167598e238bb7fb9def2f9339215e97d6685d9c1e3e4bdb33d14600e11fe7a812cf0c003dfb73ca2df374f146280b2287cae9e8d989e9d7a69a203b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lower-case-first@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "lower-case-first@npm:2.0.2"
|
||||
|
@ -37258,6 +37480,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nwsapi@npm:^2.2.7":
|
||||
version: 2.2.7
|
||||
resolution: "nwsapi@npm:2.2.7"
|
||||
checksum: cab25f7983acec7e23490fec3ef7be608041b460504229770e3bfcf9977c41d6fe58f518994d3bd9aa3a101f501089a3d4a63536f4ff8ae4b8c4ca23bdbfda4e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nyc@npm:^15.0.1, nyc@npm:^15.1.0":
|
||||
version: 15.1.0
|
||||
resolution: "nyc@npm:15.1.0"
|
||||
|
@ -37810,6 +38039,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-limit@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "p-limit@npm:5.0.0"
|
||||
dependencies:
|
||||
yocto-queue: ^1.0.0
|
||||
checksum: 87bf5837dee6942f0dbeff318436179931d9a97848d1b07dbd86140a477a5d2e6b90d9701b210b4e21fe7beaea2979dfde366e4f576fa644a59bd4d6a6371da7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-locate@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "p-locate@npm:3.0.0"
|
||||
|
@ -38141,6 +38379,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse5@npm:^7.1.2":
|
||||
version: 7.1.2
|
||||
resolution: "parse5@npm:7.1.2"
|
||||
dependencies:
|
||||
entities: ^4.4.0
|
||||
checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parseurl@npm:^1.3.2, parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3":
|
||||
version: 1.3.3
|
||||
resolution: "parseurl@npm:1.3.3"
|
||||
|
@ -40060,6 +40307,17 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pretty-format@npm:^29.7.0":
|
||||
version: 29.7.0
|
||||
resolution: "pretty-format@npm:29.7.0"
|
||||
dependencies:
|
||||
"@jest/schemas": ^29.6.3
|
||||
ansi-styles: ^5.0.0
|
||||
react-is: ^18.0.0
|
||||
checksum: 032c1602383e71e9c0c02a01bbd25d6759d60e9c7cf21937dde8357aa753da348fcec5def5d1002c9678a8524d5fe099ad98861286550ef44de8808cc61e43b6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pretty-hrtime@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "pretty-hrtime@npm:1.0.3"
|
||||
|
@ -40739,6 +40997,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"punycode@npm:^2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "punycode@npm:2.3.1"
|
||||
checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"puppeteer-core@npm:^2.1.1":
|
||||
version: 2.1.1
|
||||
resolution: "puppeteer-core@npm:2.1.1"
|
||||
|
@ -42403,6 +42668,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rrweb-cssom@npm:^0.6.0":
|
||||
version: 0.6.0
|
||||
resolution: "rrweb-cssom@npm:0.6.0"
|
||||
checksum: 182312f6e4f41d18230ccc34f14263bc8e8a6b9d30ee3ec0d2d8e643c6f27964cd7a8d638d4a00e988d93e8dc55369f4ab5a473ccfeff7a8bab95b36d2b5499c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"run-applescript@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "run-applescript@npm:7.0.0"
|
||||
|
@ -42549,6 +42821,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"saxes@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "saxes@npm:6.0.0"
|
||||
dependencies:
|
||||
xmlchars: ^2.2.0
|
||||
checksum: d3fa3e2aaf6c65ed52ee993aff1891fc47d5e47d515164b5449cbf5da2cbdc396137e55590472e64c5c436c14ae64a8a03c29b9e7389fc6f14035cf4e982ef3b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scheduler@npm:^0.23.0":
|
||||
version: 0.23.0
|
||||
resolution: "scheduler@npm:0.23.0"
|
||||
|
@ -42912,6 +43193,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"siginfo@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "siginfo@npm:2.0.0"
|
||||
checksum: 8aa5a98640ca09fe00d74416eca97551b3e42991614a3d1b824b115fc1401543650914f651ab1311518177e4d297e80b953f4cd4cd7ea1eabe824e8f2091de01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sigmund@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "sigmund@npm:1.0.1"
|
||||
|
@ -43551,6 +43839,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"stackback@npm:0.0.2":
|
||||
version: 0.0.2
|
||||
resolution: "stackback@npm:0.0.2"
|
||||
checksum: 2d4dc4e64e2db796de4a3c856d5943daccdfa3dd092e452a1ce059c81e9a9c29e0b9badba91b43ef0d5ff5c04ee62feb3bcc559a804e16faf447bac2d883aa99
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"standard-as-callback@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "standard-as-callback@npm:2.1.0"
|
||||
|
@ -44892,6 +45187,27 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinybench@npm:^2.5.1":
|
||||
version: 2.6.0
|
||||
resolution: "tinybench@npm:2.6.0"
|
||||
checksum: a621ac66ac17ec5da7e9ac10b3c27040e58c3cd843ccedd8e1e3fab5702d6337b80d02b7bfbf420ab5f029dcb7895657fb80ce21181896e170fa4e6d2c2eebc4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinypool@npm:^0.8.2":
|
||||
version: 0.8.2
|
||||
resolution: "tinypool@npm:0.8.2"
|
||||
checksum: b0993207b89ab8ab565e1eb03287aa3f15bc648c2e1da889bcfad003244271a5efe5c215d8074c3b8798ae7ea9c54678b6c9b09e7e5c8e82285177792e7ac30a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinyspy@npm:^2.2.0":
|
||||
version: 2.2.1
|
||||
resolution: "tinyspy@npm:2.2.1"
|
||||
checksum: 170d6232e87f9044f537b50b406a38fbfd6f79a261cd12b92879947bd340939a833a678632ce4f5c4a6feab4477e9c21cd43faac3b90b68b77dd0536c4149736
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tippy.js@npm:^6.3.7":
|
||||
version: 6.3.7
|
||||
resolution: "tippy.js@npm:6.3.7"
|
||||
|
@ -45012,6 +45328,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tr46@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "tr46@npm:5.0.0"
|
||||
dependencies:
|
||||
punycode: ^2.3.1
|
||||
checksum: 8d8b021f8e17675ebf9e672c224b6b6cfdb0d5b92141349e9665c14a2501c54a298d11264bbb0b17b447581e1e83d4fc3c038c929f3d210e3964d4be47460288
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tr46@npm:~0.0.3":
|
||||
version: 0.0.3
|
||||
resolution: "tr46@npm:0.0.3"
|
||||
|
@ -45367,7 +45692,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5":
|
||||
"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5, type-detect@npm:^4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "type-detect@npm:4.0.8"
|
||||
checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15
|
||||
|
@ -46889,6 +47214,21 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-node@npm:1.4.0, vite-node@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "vite-node@npm:1.4.0"
|
||||
dependencies:
|
||||
cac: ^6.7.14
|
||||
debug: ^4.3.4
|
||||
pathe: ^1.1.1
|
||||
picocolors: ^1.0.0
|
||||
vite: ^5.0.0
|
||||
bin:
|
||||
vite-node: vite-node.mjs
|
||||
checksum: 1abbeac935a5e1e3b6161974ae28b6a3ec88766b06bc082ab3f2883345ee74f5643f3004df1c7808c2b52d445ffbd067bb79a1a3920c2eaa7ca8084b11b7de46
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-node@npm:^0.33.0":
|
||||
version: 0.33.0
|
||||
resolution: "vite-node@npm:0.33.0"
|
||||
|
@ -46905,21 +47245,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-node@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "vite-node@npm:1.4.0"
|
||||
dependencies:
|
||||
cac: ^6.7.14
|
||||
debug: ^4.3.4
|
||||
pathe: ^1.1.1
|
||||
picocolors: ^1.0.0
|
||||
vite: ^5.0.0
|
||||
bin:
|
||||
vite-node: vite-node.mjs
|
||||
checksum: 1abbeac935a5e1e3b6161974ae28b6a3ec88766b06bc082ab3f2883345ee74f5643f3004df1c7808c2b52d445ffbd067bb79a1a3920c2eaa7ca8084b11b7de46
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-plugin-checker@npm:^0.6.1":
|
||||
version: 0.6.1
|
||||
resolution: "vite-plugin-checker@npm:0.6.1"
|
||||
|
@ -47245,6 +47570,56 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vitest@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "vitest@npm:1.4.0"
|
||||
dependencies:
|
||||
"@vitest/expect": 1.4.0
|
||||
"@vitest/runner": 1.4.0
|
||||
"@vitest/snapshot": 1.4.0
|
||||
"@vitest/spy": 1.4.0
|
||||
"@vitest/utils": 1.4.0
|
||||
acorn-walk: ^8.3.2
|
||||
chai: ^4.3.10
|
||||
debug: ^4.3.4
|
||||
execa: ^8.0.1
|
||||
local-pkg: ^0.5.0
|
||||
magic-string: ^0.30.5
|
||||
pathe: ^1.1.1
|
||||
picocolors: ^1.0.0
|
||||
std-env: ^3.5.0
|
||||
strip-literal: ^2.0.0
|
||||
tinybench: ^2.5.1
|
||||
tinypool: ^0.8.2
|
||||
vite: ^5.0.0
|
||||
vite-node: 1.4.0
|
||||
why-is-node-running: ^2.2.2
|
||||
peerDependencies:
|
||||
"@edge-runtime/vm": "*"
|
||||
"@types/node": ^18.0.0 || >=20.0.0
|
||||
"@vitest/browser": 1.4.0
|
||||
"@vitest/ui": 1.4.0
|
||||
happy-dom: "*"
|
||||
jsdom: "*"
|
||||
peerDependenciesMeta:
|
||||
"@edge-runtime/vm":
|
||||
optional: true
|
||||
"@types/node":
|
||||
optional: true
|
||||
"@vitest/browser":
|
||||
optional: true
|
||||
"@vitest/ui":
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
bin:
|
||||
vitest: vitest.mjs
|
||||
checksum: e7141c0ecc629c350d8c718051fb19219ca88a100d335fedbe481c4320f285380e3235316a69a330514c34663fcafa37c801151162d0a538e92821e7faad71a6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"void-elements@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "void-elements@npm:3.1.0"
|
||||
|
@ -47778,6 +48153,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"w3c-xmlserializer@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "w3c-xmlserializer@npm:5.0.0"
|
||||
dependencies:
|
||||
xml-name-validator: ^5.0.0
|
||||
checksum: 593acc1fdab3f3207ec39d851e6df0f3fa41a36b5809b0ace364c7a6d92e351938c53424a7618ce8e0fbaffee8be2e8e070a5734d05ee54666a8bdf1a376cc40
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wait-on@npm:>=7.2.0":
|
||||
version: 7.2.0
|
||||
resolution: "wait-on@npm:7.2.0"
|
||||
|
@ -47946,6 +48330,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webidl-conversions@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "webidl-conversions@npm:7.0.0"
|
||||
checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webpack-cli@npm:^4.6.0":
|
||||
version: 4.9.2
|
||||
resolution: "webpack-cli@npm:4.9.2"
|
||||
|
@ -48145,6 +48536,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-encoding@npm:^3.1.1":
|
||||
version: 3.1.1
|
||||
resolution: "whatwg-encoding@npm:3.1.1"
|
||||
dependencies:
|
||||
iconv-lite: 0.6.3
|
||||
checksum: f75a61422421d991e4aec775645705beaf99a16a88294d68404866f65e92441698a4f5b9fa11dd609017b132d7b286c3c1534e2de5b3e800333856325b549e3c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-fetch@npm:^3.4.1":
|
||||
version: 3.6.2
|
||||
resolution: "whatwg-fetch@npm:3.6.2"
|
||||
|
@ -48166,6 +48566,23 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-mimetype@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "whatwg-mimetype@npm:4.0.0"
|
||||
checksum: f97edd4b4ee7e46a379f3fb0e745de29fe8b839307cc774300fd49059fcdd560d38cb8fe21eae5575b8f39b022f23477cc66e40b0355c2851ce84760339cef30
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-url@npm:^14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "whatwg-url@npm:14.0.0"
|
||||
dependencies:
|
||||
tr46: ^5.0.0
|
||||
webidl-conversions: ^7.0.0
|
||||
checksum: 4b5887e50f786583bead70916413e67a381d2126899b9eb5c67ce664bba1e7ec07cdff791404581ce73c6190d83c359c9ca1d50711631217905db3877dec075c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-url@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "whatwg-url@npm:5.0.0"
|
||||
|
@ -48301,6 +48718,18 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"why-is-node-running@npm:^2.2.2":
|
||||
version: 2.2.2
|
||||
resolution: "why-is-node-running@npm:2.2.2"
|
||||
dependencies:
|
||||
siginfo: ^2.0.0
|
||||
stackback: 0.0.2
|
||||
bin:
|
||||
why-is-node-running: cli.js
|
||||
checksum: 50820428f6a82dfc3cbce661570bcae9b658723217359b6037b67e495255409b4c8bc7931745f5c175df71210450464517cab32b2f7458ac9c40b4925065200a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wide-align@npm:^1.1.2, wide-align@npm:^1.1.5":
|
||||
version: 1.1.5
|
||||
resolution: "wide-align@npm:1.1.5"
|
||||
|
@ -48598,6 +49027,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml-name-validator@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "xml-name-validator@npm:5.0.0"
|
||||
checksum: 86effcc7026f437701252fcc308b877b4bc045989049cfc79b0cc112cb365cf7b009f4041fab9fb7cd1795498722c3e9fe9651afc66dfa794c16628a639a4c45
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml@npm:^1.0.0, xml@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "xml@npm:1.0.1"
|
||||
|
@ -48911,6 +49347,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yocto-queue@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "yocto-queue@npm:1.0.0"
|
||||
checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"z-schema@npm:~5.0.2":
|
||||
version: 5.0.5
|
||||
resolution: "z-schema@npm:5.0.5"
|
||||
|
|
Загрузка…
Ссылка в новой задаче