@woosh/meep-engine 3.14.4 → 3.14.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/editor/Editor.d.ts +162 -0
- package/editor/Editor.d.ts.map +1 -0
- package/editor/EditorCameraNavigation.d.ts +22 -0
- package/editor/EditorCameraNavigation.d.ts.map +1 -0
- package/editor/EditorKeyMap.d.ts +28 -0
- package/editor/EditorKeyMap.d.ts.map +1 -0
- package/editor/SelectionVisualizer.d.ts +37 -0
- package/editor/SelectionVisualizer.d.ts.map +1 -0
- package/editor/actions/concrete/ActionInvalidateSampler.d.ts +18 -0
- package/editor/actions/concrete/ActionInvalidateSampler.d.ts.map +1 -0
- package/editor/actions/concrete/ActionUpdateTexture.d.ts +12 -0
- package/editor/actions/concrete/ActionUpdateTexture.d.ts.map +1 -0
- package/editor/actions/concrete/ActionUpdateTexture.js +1 -1
- package/editor/actions/concrete/ArrayCopyAction.d.ts +20 -0
- package/editor/actions/concrete/ArrayCopyAction.d.ts.map +1 -0
- package/editor/actions/concrete/ComponentAddAction.d.ts +15 -0
- package/editor/actions/concrete/ComponentAddAction.d.ts.map +1 -0
- package/editor/actions/concrete/ComponentRemoveAction.d.ts +11 -0
- package/editor/actions/concrete/ComponentRemoveAction.d.ts.map +1 -0
- package/editor/actions/concrete/EntityCreateAction.d.ts +18 -0
- package/editor/actions/concrete/EntityCreateAction.d.ts.map +1 -0
- package/editor/actions/concrete/EntityRemoveAction.d.ts +11 -0
- package/editor/actions/concrete/EntityRemoveAction.d.ts.map +1 -0
- package/editor/actions/concrete/ModifyPatchSampler2DAction.d.ts +47 -0
- package/editor/actions/concrete/ModifyPatchSampler2DAction.d.ts.map +1 -0
- package/editor/actions/concrete/ModifyPatchTextureArray2DAction.d.ts +38 -0
- package/editor/actions/concrete/ModifyPatchTextureArray2DAction.d.ts.map +1 -0
- package/editor/actions/concrete/PaintTerrainOverlayAction.d.ts +23 -0
- package/editor/actions/concrete/PaintTerrainOverlayAction.d.ts.map +1 -0
- package/editor/actions/concrete/PatchTerrainHeightAction.d.ts +32 -0
- package/editor/actions/concrete/PatchTerrainHeightAction.d.ts.map +1 -0
- package/editor/actions/concrete/SelectionAddAction.d.ts +19 -0
- package/editor/actions/concrete/SelectionAddAction.d.ts.map +1 -0
- package/editor/actions/concrete/SelectionClearAction.d.ts +9 -0
- package/editor/actions/concrete/SelectionClearAction.d.ts.map +1 -0
- package/editor/actions/concrete/SelectionRemoveAction.d.ts +10 -0
- package/editor/actions/concrete/SelectionRemoveAction.d.ts.map +1 -0
- package/editor/actions/concrete/TransformModifyAction.d.ts +17 -0
- package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -0
- package/editor/actions/concrete/WriteGridValueAction.d.ts +14 -0
- package/editor/actions/concrete/WriteGridValueAction.d.ts.map +1 -0
- package/editor/camera/camera_framing.d.ts +33 -0
- package/editor/camera/camera_framing.d.ts.map +1 -0
- package/editor/clipboard.d.ts +19 -0
- package/editor/clipboard.d.ts.map +1 -0
- package/editor/ecs/EditorEntity.d.ts +16 -0
- package/editor/ecs/EditorEntity.d.ts.map +1 -0
- package/editor/ecs/EditorEntitySystem.d.ts +8 -0
- package/editor/ecs/EditorEntitySystem.d.ts.map +1 -0
- package/editor/ecs/component/TypeEditor.d.ts +7 -1
- package/editor/ecs/component/TypeEditor.d.ts.map +1 -1
- package/editor/ecs/component/TypeEditor.js +5 -0
- package/editor/ecs/component/editors/ColorEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ColorEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/HTMLElementEditor.d.ts +7 -0
- package/editor/ecs/component/editors/HTMLElementEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ImagePathEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ImagePathEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/LargeStringEditor.d.ts +16 -0
- package/editor/ecs/component/editors/LargeStringEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/NumericIntervalEditor.d.ts +7 -0
- package/editor/ecs/component/editors/NumericIntervalEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ObservedBooleanEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ObservedBooleanEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ObservedEnumEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ObservedEnumEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ObservedIntegerEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ObservedIntegerEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ObservedStringEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ObservedStringEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/Sampler2DEditor.d.ts +7 -0
- package/editor/ecs/component/editors/Sampler2DEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/collection/ListEditor.d.ts +8 -0
- package/editor/ecs/component/editors/collection/ListEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/common/BitFlagsEditor.d.ts +12 -0
- package/editor/ecs/component/editors/common/BitFlagsEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/common/EnumEditor.d.ts +8 -0
- package/editor/ecs/component/editors/common/EnumEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/common/makeV3_editor.d.ts +15 -0
- package/editor/ecs/component/editors/common/makeV3_editor.d.ts.map +1 -0
- package/editor/ecs/component/editors/common/noEditor.d.ts +3 -0
- package/editor/ecs/component/editors/common/noEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/common/two_way_sync.d.ts +22 -0
- package/editor/ecs/component/editors/common/two_way_sync.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/GridObstacleEditor.d.ts +7 -0
- package/editor/ecs/component/editors/ecs/GridObstacleEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/MinimapMarkerEditor.d.ts +14 -0
- package/editor/ecs/component/editors/ecs/MinimapMarkerEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.d.ts +20 -0
- package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/ParameterTrackEditor.d.ts +12 -0
- package/editor/ecs/component/editors/ecs/ParameterTrackEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/ParameterTrackSetEditor.d.ts +14 -0
- package/editor/ecs/component/editors/ecs/ParameterTrackSetEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/ParticleEmitterEditor.d.ts +52 -0
- package/editor/ecs/component/editors/ecs/ParticleEmitterEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/ParticleEmitterLayerEditor.d.ts +47 -0
- package/editor/ecs/component/editors/ecs/ParticleEmitterLayerEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/SGMeshEditor.d.ts +21 -0
- package/editor/ecs/component/editors/ecs/SGMeshEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/ShadedGeometryEditor.d.ts +26 -0
- package/editor/ecs/component/editors/ecs/ShadedGeometryEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/SimulationStepDefinitionEditor.d.ts +16 -0
- package/editor/ecs/component/editors/ecs/SimulationStepDefinitionEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/Trail2DEditor.d.ts +15 -0
- package/editor/ecs/component/editors/ecs/Trail2DEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts +42 -0
- package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/TransformEditor.d.ts +20 -0
- package/editor/ecs/component/editors/ecs/TransformEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/buildGridObstaclePreview.d.ts +8 -0
- package/editor/ecs/component/editors/ecs/buildGridObstaclePreview.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/terrain/SplatMappingEditor.d.ts +19 -0
- package/editor/ecs/component/editors/ecs/terrain/SplatMappingEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.d.ts +27 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainLayerEditor.d.ts +16 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainLayerEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainLayersEditor.d.ts +19 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainLayersEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainOverlayEditor.d.ts +18 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainOverlayEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/geom/QuaternionEditor.d.ts +6 -0
- package/editor/ecs/component/editors/geom/QuaternionEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/geom/Vector1Editor.d.ts +7 -0
- package/editor/ecs/component/editors/geom/Vector1Editor.d.ts.map +1 -0
- package/editor/ecs/component/editors/geom/Vector2Editor.d.ts +6 -0
- package/editor/ecs/component/editors/geom/Vector2Editor.d.ts.map +1 -0
- package/editor/ecs/component/editors/geom/Vector3Editor.d.ts +6 -0
- package/editor/ecs/component/editors/geom/Vector3Editor.d.ts.map +1 -0
- package/editor/ecs/component/editors/geom/Vector4Editor.d.ts +6 -0
- package/editor/ecs/component/editors/geom/Vector4Editor.d.ts.map +1 -0
- package/editor/ecs/component/editors/primitive/ArrayEditor.d.ts +8 -0
- package/editor/ecs/component/editors/primitive/ArrayEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/primitive/BooleanEditor.d.ts +7 -0
- package/editor/ecs/component/editors/primitive/BooleanEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/primitive/FunctionEditor.d.ts +7 -0
- package/editor/ecs/component/editors/primitive/FunctionEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/primitive/NumberEditor.d.ts +8 -0
- package/editor/ecs/component/editors/primitive/NumberEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/primitive/StringEditor.d.ts +7 -0
- package/editor/ecs/component/editors/primitive/StringEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/shade/MeshletGeometryEditor.d.ts +28 -0
- package/editor/ecs/component/editors/shade/MeshletGeometryEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/shade/ShadeImageEditor.d.ts +29 -0
- package/editor/ecs/component/editors/shade/ShadeImageEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/shade/ShadeMaterialEditor.d.ts +28 -0
- package/editor/ecs/component/editors/shade/ShadeMaterialEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/shade/ShadeTextureEditor.d.ts +41 -0
- package/editor/ecs/component/editors/shade/ShadeTextureEditor.d.ts.map +1 -0
- package/editor/ecs/component/editors/shade/StandardShadeMaterialEditor.d.ts +31 -0
- package/editor/ecs/component/editors/shade/StandardShadeMaterialEditor.d.ts.map +1 -0
- package/editor/ecs/component/prototypeObjectEditor.d.ts +2 -0
- package/editor/ecs/component/prototypeObjectEditor.d.ts.map +1 -0
- package/editor/ecs/component/registerBasicTypeEditors.d.ts +11 -0
- package/editor/ecs/component/registerBasicTypeEditors.d.ts.map +1 -0
- package/editor/ecs/component/registerEngineComponentEditors.d.ts +8 -0
- package/editor/ecs/component/registerEngineComponentEditors.d.ts.map +1 -0
- package/editor/enableEditor.d.ts +14 -0
- package/editor/enableEditor.d.ts.map +1 -0
- package/editor/entity_world_bounds.d.ts +17 -0
- package/editor/entity_world_bounds.d.ts.map +1 -0
- package/editor/library/MeshLibrary.d.ts +13 -0
- package/editor/library/MeshLibrary.d.ts.map +1 -0
- package/editor/particles/lut_ops.d.ts +34 -0
- package/editor/particles/lut_ops.d.ts.map +1 -0
- package/editor/particles/particleEditEvents.d.ts +11 -0
- package/editor/particles/particleEditEvents.d.ts.map +1 -0
- package/editor/particles/rebuildParticleEmitter.d.ts +11 -0
- package/editor/particles/rebuildParticleEmitter.d.ts.map +1 -0
- package/editor/persistence/EditorLayoutStore.d.ts +30 -0
- package/editor/persistence/EditorLayoutStore.d.ts.map +1 -0
- package/editor/persistence/SceneMetadata.d.ts +38 -0
- package/editor/persistence/SceneMetadata.d.ts.map +1 -0
- package/editor/persistence/SceneSlotManager.d.ts +40 -0
- package/editor/persistence/SceneSlotManager.d.ts.map +1 -0
- package/editor/persistence/buildNewSceneDataset.d.ts +10 -0
- package/editor/persistence/buildNewSceneDataset.d.ts.map +1 -0
- package/editor/persistence/files.d.ts +24 -0
- package/editor/persistence/files.d.ts.map +1 -0
- package/editor/persistence/scene_import.d.ts +45 -0
- package/editor/persistence/scene_import.d.ts.map +1 -0
- package/editor/persistence/scene_serialization.d.ts +36 -0
- package/editor/persistence/scene_serialization.d.ts.map +1 -0
- package/editor/persistence/string_buffer_codec.d.ts +20 -0
- package/editor/persistence/string_buffer_codec.d.ts.map +1 -0
- package/editor/process/DisableGameUIProcess.d.ts +8 -0
- package/editor/process/DisableGameUIProcess.d.ts.map +1 -0
- package/editor/process/EditorProcess.d.ts +19 -0
- package/editor/process/EditorProcess.d.ts.map +1 -0
- package/editor/process/GridDisplayProcess.d.ts +35 -0
- package/editor/process/GridDisplayProcess.d.ts.map +1 -0
- package/editor/process/ObstacleGridDisplayProcess.d.ts +13 -0
- package/editor/process/ObstacleGridDisplayProcess.d.ts.map +1 -0
- package/editor/process/ParticleEmitterRebuildProcess.d.ts +66 -0
- package/editor/process/ParticleEmitterRebuildProcess.d.ts.map +1 -0
- package/editor/process/ProcessEngine.d.ts +30 -0
- package/editor/process/ProcessEngine.d.ts.map +1 -0
- package/editor/process/SymbolicDisplayProcess.d.ts +23 -0
- package/editor/process/SymbolicDisplayProcess.d.ts.map +1 -0
- package/editor/process/symbolic/AudioEmitterSymbolicDisplay.d.ts +17 -0
- package/editor/process/symbolic/AudioEmitterSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/CameraSymbolicDisplay.d.ts +25 -0
- package/editor/process/symbolic/CameraSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/GridPositionSymbolicDisplay.d.ts +19 -0
- package/editor/process/symbolic/GridPositionSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/LightSymbolicDisplay.d.ts +19 -0
- package/editor/process/symbolic/LightSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/ParticleEmitterSymbolicDisplay.d.ts +18 -0
- package/editor/process/symbolic/ParticleEmitterSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/PathSymbolicDisplay.d.ts +20 -0
- package/editor/process/symbolic/PathSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/PositionedMarkerSymbolicDisplay.d.ts +25 -0
- package/editor/process/symbolic/PositionedMarkerSymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/SymbolicDisplay.d.ts +48 -0
- package/editor/process/symbolic/SymbolicDisplay.d.ts.map +1 -0
- package/editor/process/symbolic/gizmo_draw_wire_box_oriented.d.ts +13 -0
- package/editor/process/symbolic/gizmo_draw_wire_box_oriented.d.ts.map +1 -0
- package/editor/process/symbolic/gizmo_draw_wire_circle.d.ts +18 -0
- package/editor/process/symbolic/gizmo_draw_wire_circle.d.ts.map +1 -0
- package/editor/prototypeEditorShell.d.ts +13 -0
- package/editor/prototypeEditorShell.d.ts.map +1 -0
- package/editor/selection/editor_pick.d.ts +43 -0
- package/editor/selection/editor_pick.d.ts.map +1 -0
- package/editor/selection/screen_rect_frustum.d.ts +32 -0
- package/editor/selection/screen_rect_frustum.d.ts.map +1 -0
- package/editor/templates/entity_templates.d.ts +19 -0
- package/editor/templates/entity_templates.d.ts.map +1 -0
- package/editor/tools/GridPaintTool.d.ts +18 -0
- package/editor/tools/GridPaintTool.d.ts.map +1 -0
- package/editor/tools/SelectionTool.d.ts +38 -0
- package/editor/tools/SelectionTool.d.ts.map +1 -0
- package/editor/tools/SelectionTool.js +2 -2
- package/editor/tools/TransformToolV2.d.ts +70 -0
- package/editor/tools/TransformToolV2.d.ts.map +1 -0
- package/editor/tools/engine/Tool.d.ts +88 -0
- package/editor/tools/engine/Tool.d.ts.map +1 -0
- package/editor/tools/engine/ToolEngine.d.ts +22 -0
- package/editor/tools/engine/ToolEngine.d.ts.map +1 -0
- package/editor/tools/engine/ToolState.d.ts +7 -0
- package/editor/tools/engine/ToolState.d.ts.map +1 -0
- package/editor/tools/paint/TerrainHeightPaintTool.d.ts +18 -0
- package/editor/tools/paint/TerrainHeightPaintTool.d.ts.map +1 -0
- package/editor/tools/paint/TerrainPaintTool.d.ts +82 -0
- package/editor/tools/paint/TerrainPaintTool.d.ts.map +1 -0
- package/editor/tools/paint/TerrainTexturePaintTool.d.ts +19 -0
- package/editor/tools/paint/TerrainTexturePaintTool.d.ts.map +1 -0
- package/editor/tools/v2/BlenderCameraOrientationGizmo.d.ts +139 -0
- package/editor/tools/v2/BlenderCameraOrientationGizmo.d.ts.map +1 -0
- package/editor/tools/v2/GizmoNode.d.ts +21 -0
- package/editor/tools/v2/GizmoNode.d.ts.map +1 -0
- package/editor/tools/v2/TransformControls.d.ts +219 -0
- package/editor/tools/v2/TransformControls.d.ts.map +1 -0
- package/editor/tools/v2/TransformMode.d.ts +7 -0
- package/editor/tools/v2/TransformMode.d.ts.map +1 -0
- package/editor/tools/v2/handle/gizmo_drag_plane.d.ts +37 -0
- package/editor/tools/v2/handle/gizmo_drag_plane.d.ts.map +1 -0
- package/editor/tools/v2/handle/gizmo_draw.d.ts +14 -0
- package/editor/tools/v2/handle/gizmo_draw.d.ts.map +1 -0
- package/editor/tools/v2/handle/gizmo_handles.d.ts +160 -0
- package/editor/tools/v2/handle/gizmo_handles.d.ts.map +1 -0
- package/editor/tools/v2/handle/gizmo_ray_shapes.d.ts +103 -0
- package/editor/tools/v2/handle/gizmo_ray_shapes.d.ts.map +1 -0
- package/editor/view/GridPickCoordinateView.d.ts +22 -0
- package/editor/view/GridPickCoordinateView.d.ts.map +1 -0
- package/editor/view/ecs/ComponentControlView.d.ts +24 -0
- package/editor/view/ecs/ComponentControlView.d.ts.map +1 -0
- package/editor/view/ecs/EntityEditor.d.ts +25 -0
- package/editor/view/ecs/EntityEditor.d.ts.map +1 -0
- package/editor/view/ecs/EntityList.d.ts +22 -0
- package/editor/view/ecs/EntityList.d.ts.map +1 -0
- package/editor/view/ecs/HierarchicalEntityListView.d.ts +25 -0
- package/editor/view/ecs/HierarchicalEntityListView.d.ts.map +1 -0
- package/editor/view/ecs/components/DatGuiController.d.ts +2 -0
- package/editor/view/ecs/components/DatGuiController.d.ts.map +1 -0
- package/editor/view/ecs/components/color/GaugeView.d.ts +9 -5
- package/editor/view/ecs/components/color/GaugeView.d.ts.map +1 -1
- package/editor/view/ecs/components/color/GaugeView.js +4 -4
- package/editor/view/ecs/components/common/NumberController.d.ts +9 -5
- package/editor/view/ecs/components/common/NumberController.d.ts.map +1 -1
- package/editor/view/ecs/components/common/NumberController.js +4 -4
- package/editor/view/ecs/components/common/NumericIntervalController.d.ts +10 -0
- package/editor/view/ecs/components/common/NumericIntervalController.d.ts.map +1 -0
- package/editor/view/ecs/components/common/TextController.d.ts.map +1 -1
- package/editor/view/library/MeshLibraryView.d.ts +16 -0
- package/editor/view/library/MeshLibraryView.d.ts.map +1 -0
- package/editor/view/library/mesh_library_drag.d.ts +21 -0
- package/editor/view/library/mesh_library_drag.d.ts.map +1 -0
- package/editor/view/library/model_thumbnail_source.d.ts +12 -0
- package/editor/view/library/model_thumbnail_source.d.ts.map +1 -0
- package/editor/view/makeEntityDecorators.d.ts +6 -0
- package/editor/view/makeEntityDecorators.d.ts.map +1 -0
- package/editor/view/node-graph/NodeGraphCamera.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphSelection.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeView.d.ts.map +1 -1
- package/editor/view/node-graph/PortView.d.ts.map +1 -1
- package/editor/view/node-graph/actions/ConnectionCreateAction.d.ts.map +1 -1
- package/editor/view/node-graph/actions/ConnectionDeleteAction.d.ts.map +1 -1
- package/editor/view/node-graph/actions/NodeDeleteAction.d.ts.map +1 -1
- package/editor/view/node-graph/actions/NodeParameterSetAction.d.ts.map +1 -1
- package/editor/view/node-graph/actions/NodesMoveAction.d.ts.map +1 -1
- package/editor/view/node-graph/actions/SelectionSetAction.d.ts.map +1 -1
- package/editor/view/node-graph/connection_wire_geometry.d.ts.map +1 -1
- package/editor/view/particles/ColorLutGradientView.d.ts +19 -0
- package/editor/view/particles/ColorLutGradientView.d.ts.map +1 -0
- package/editor/view/particles/ScalarLutCurveView.d.ts +19 -0
- package/editor/view/particles/ScalarLutCurveView.d.ts.map +1 -0
- package/editor/view/prepareMeshLibrary.d.ts +7 -0
- package/editor/view/prepareMeshLibrary.d.ts.map +1 -0
- package/editor/view/process/ProcessView.d.ts +14 -0
- package/editor/view/process/ProcessView.d.ts.map +1 -0
- package/editor/view/shell/EditorShellView.d.ts +18 -0
- package/editor/view/shell/EditorShellView.d.ts.map +1 -0
- package/editor/view/shell/SceneTreePanelView.d.ts +17 -0
- package/editor/view/shell/SceneTreePanelView.d.ts.map +1 -0
- package/editor/view/shell/ViewportPanelView.d.ts +18 -0
- package/editor/view/shell/ViewportPanelView.d.ts.map +1 -0
- package/editor/view/tools/ToolSettingsView.d.ts +22 -0
- package/editor/view/tools/ToolSettingsView.d.ts.map +1 -0
- package/editor/view/tools/ToolView.d.ts +13 -0
- package/editor/view/tools/ToolView.d.ts.map +1 -0
- package/editor/view/v2/SplitView.d.ts +2 -0
- package/editor/view/v2/SplitView.d.ts.map +1 -0
- package/package.json +9 -11
- package/samples/engine/README.md +113 -0
- package/samples/engine/first-scene/index.html +32 -0
- package/samples/engine/first-scene/main.js +152 -0
- package/src/core/assert.d.ts +2 -2
- package/src/core/binary/BitSet.d.ts +2 -2
- package/src/core/binary/BitSet.d.ts.map +1 -1
- package/src/core/binary/BitSet.js +1 -1
- package/src/core/bvh2/bvh3/BVH.d.ts +4 -0
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +4 -0
- package/src/core/bvh2/bvh3/BvhClient.d.ts +4 -0
- package/src/core/bvh2/bvh3/BvhClient.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BvhClient.js +4 -0
- package/src/core/collection/array/array_sort_quick.d.ts +1 -1
- package/src/core/collection/list/List.d.ts +7 -3
- package/src/core/collection/list/List.d.ts.map +1 -1
- package/src/core/collection/list/List.js +6 -2
- package/src/core/collection/table/RowFirstTableSpec.d.ts.map +1 -1
- package/src/core/collection/table/RowFirstTableSpec.js +0 -4
- package/src/core/color/Color.d.ts +1 -0
- package/src/core/color/Color.d.ts.map +1 -1
- package/src/core/color/Color.js +4 -0
- package/src/core/events/signal/SignalBinding.d.ts +4 -0
- package/src/core/events/signal/SignalBinding.d.ts.map +1 -1
- package/src/core/events/signal/SignalBinding.js +4 -0
- package/src/core/geom/2d/quad-tree/QuadTreeDatum.d.ts +5 -1
- package/src/core/geom/2d/quad-tree/QuadTreeDatum.d.ts.map +1 -1
- package/src/core/geom/2d/quad-tree/QuadTreeDatum.js +4 -0
- package/src/core/geom/3d/SurfacePoint3.d.ts +2 -2
- package/src/core/geom/3d/SurfacePoint3.d.ts.map +1 -1
- package/src/core/geom/3d/SurfacePoint3.js +1 -1
- package/src/core/geom/3d/aabb/AABB3.d.ts +63 -7
- package/src/core/geom/3d/aabb/AABB3.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/AABB3.js +17 -3
- package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts +30 -0
- package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_rigidity_defect.js +71 -0
- package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +2 -2
- package/src/core/geom/3d/ray/Ray3.d.ts +4 -4
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts +10 -3
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/AbstractShape3D.js +9 -2
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts +2 -2
- package/src/core/geom/3d/sphere/harmonics/sh3_rotate.d.ts +1 -1
- package/src/core/geom/Vector1.d.ts +4 -0
- package/src/core/geom/Vector1.d.ts.map +1 -1
- package/src/core/geom/Vector1.js +4 -0
- package/src/core/geom/Vector2.d.ts +4 -0
- package/src/core/geom/Vector2.d.ts.map +1 -1
- package/src/core/geom/Vector2.js +4 -0
- package/src/core/geom/Vector3.d.ts +4 -0
- package/src/core/geom/Vector3.d.ts.map +1 -1
- package/src/core/geom/Vector3.js +4 -0
- package/src/core/geom/Vector4.d.ts +4 -0
- package/src/core/geom/Vector4.d.ts.map +1 -1
- package/src/core/geom/Vector4.js +4 -0
- package/src/core/geom/packing/max-rect/MaxRectanglesPacker.d.ts +6 -2
- package/src/core/geom/packing/max-rect/MaxRectanglesPacker.d.ts.map +1 -1
- package/src/core/geom/packing/max-rect/MaxRectanglesPacker.js +4 -0
- package/src/core/geom/packing/miniball/Subspan.d.ts +4 -4
- package/src/core/geom/packing/miniball/Subspan.d.ts.map +1 -1
- package/src/core/geom/packing/miniball/Subspan.js +2 -2
- package/src/core/math/interval/NumericInterval.d.ts +4 -0
- package/src/core/math/interval/NumericInterval.d.ts.map +1 -1
- package/src/core/math/interval/NumericInterval.js +4 -0
- package/src/core/math/random/roundFair.d.ts +2 -2
- package/src/core/math/random/roundFair.d.ts.map +1 -1
- package/src/core/math/random/roundFair.js +1 -1
- package/src/core/model/BoundedValue.d.ts +4 -0
- package/src/core/model/BoundedValue.d.ts.map +1 -1
- package/src/core/model/BoundedValue.js +4 -0
- package/src/core/model/ObservedBoolean.d.ts +4 -0
- package/src/core/model/ObservedBoolean.d.ts.map +1 -1
- package/src/core/model/ObservedBoolean.js +4 -0
- package/src/core/model/ObservedInteger.d.ts +4 -0
- package/src/core/model/ObservedInteger.d.ts.map +1 -1
- package/src/core/model/ObservedInteger.js +4 -0
- package/src/core/model/ObservedString.d.ts +4 -0
- package/src/core/model/ObservedString.d.ts.map +1 -1
- package/src/core/model/ObservedString.js +4 -0
- package/src/core/model/stat/Stat.d.ts +7 -3
- package/src/core/model/stat/Stat.d.ts.map +1 -1
- package/src/core/model/stat/Stat.js +4 -0
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +65 -0
- package/src/engine/EngineHarness.d.ts +8 -1
- package/src/engine/EngineHarness.d.ts.map +1 -1
- package/src/engine/EngineHarness.js +10 -14
- package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts +2 -2
- package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts.map +1 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.js +4 -4
- package/src/engine/asset/loaders/async_traverse_three_object.d.ts +2 -2
- package/src/engine/asset/loaders/async_traverse_three_object.d.ts.map +1 -1
- package/src/engine/asset/loaders/async_traverse_three_object.js +1 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts +7 -3
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +33 -3
- package/src/engine/control/first-person/DESIGN.md +20 -2
- package/src/engine/control/first-person/DESIGN_COLLISION.md +17 -0
- package/src/engine/control/first-person/collision/KinematicMover.d.ts +58 -11
- package/src/engine/control/first-person/collision/KinematicMover.d.ts.map +1 -1
- package/src/engine/control/first-person/collision/KinematicMover.js +97 -20
- package/src/engine/ecs/Entity.js +1 -1
- package/src/engine/ecs/EntityComponentDataset.d.ts +2 -2
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +1 -1
- package/src/engine/ecs/EntityManager.d.ts.map +1 -1
- package/src/engine/ecs/EntityManager.js +27 -3
- package/src/engine/ecs/animation/Animation.d.ts +17 -3
- package/src/engine/ecs/animation/Animation.d.ts.map +1 -1
- package/src/engine/ecs/animation/Animation.js +26 -6
- package/src/engine/ecs/terrain/TerrainPreview.d.ts +4 -0
- package/src/engine/ecs/terrain/TerrainPreview.d.ts.map +1 -1
- package/src/engine/ecs/terrain/TerrainPreview.js +4 -0
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts +4 -4
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +2 -2
- package/src/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.d.ts +3 -2
- package/src/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.js +25 -2
- package/src/engine/ecs/transform/Transform64.d.ts +4 -4
- package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
- package/src/engine/ecs/transform/Transform64.js +2 -2
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts +26 -0
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.js +26 -0
- package/src/engine/graphics/ecs/light/Light.d.ts +38 -1
- package/src/engine/graphics/ecs/light/Light.d.ts.map +1 -1
- package/src/engine/graphics/ecs/light/Light.js +51 -1
- package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts +3 -3
- package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh/copyToVector3.js +2 -2
- package/src/engine/graphics/ecs/mesh/setMesh.d.ts +2 -2
- package/src/engine/graphics/ecs/mesh/setMesh.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh/setMesh.js +1 -1
- package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.d.ts +2 -2
- package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.js +1 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.d.ts +3 -3
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.js +2 -2
- package/src/engine/graphics/geometry/buffered/computeGeometryHash.d.ts +2 -2
- package/src/engine/graphics/geometry/buffered/computeGeometryHash.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryHash.js +1 -1
- package/src/engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.d.ts +2 -2
- package/src/engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.js +1 -1
- package/src/engine/graphics/geometry/compute_geometry_polycount.d.ts +2 -2
- package/src/engine/graphics/geometry/compute_geometry_polycount.d.ts.map +1 -1
- package/src/engine/graphics/geometry/compute_geometry_polycount.js +1 -1
- package/src/engine/graphics/geometry/ribbon/copyAttributeV3.d.ts +3 -3
- package/src/engine/graphics/geometry/ribbon/copyAttributeV3.d.ts.map +1 -1
- package/src/engine/graphics/geometry/ribbon/copyAttributeV3.js +2 -2
- package/src/engine/graphics/geometry/ribbon/copyAttributeValue.d.ts +4 -4
- package/src/engine/graphics/geometry/ribbon/copyAttributeValue.d.ts.map +1 -1
- package/src/engine/graphics/geometry/ribbon/copyAttributeValue.js +3 -3
- package/src/engine/graphics/geometry/ribbon/equalAttributeV3.d.ts +3 -3
- package/src/engine/graphics/geometry/ribbon/equalAttributeV3.d.ts.map +1 -1
- package/src/engine/graphics/geometry/ribbon/equalAttributeV3.js +2 -2
- package/src/engine/graphics/geometry/ribbon/equalAttributeValue.d.ts +4 -4
- package/src/engine/graphics/geometry/ribbon/equalAttributeValue.d.ts.map +1 -1
- package/src/engine/graphics/geometry/ribbon/equalAttributeValue.js +3 -3
- package/src/engine/graphics/geometry/scaleGeometryToBox.d.ts +2 -2
- package/src/engine/graphics/geometry/scaleGeometryToBox.d.ts.map +1 -1
- package/src/engine/graphics/geometry/scaleGeometryToBox.js +1 -1
- package/src/engine/graphics/impostors/card_cluster/FacePlaneAssignment.d.ts +2 -2
- package/src/engine/graphics/impostors/card_cluster/FacePlaneAssignment.d.ts.map +1 -1
- package/src/engine/graphics/impostors/card_cluster/FacePlaneAssignment.js +1 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorDescription.d.ts +2 -2
- package/src/engine/graphics/impostors/octahedral/ImpostorDescription.d.ts.map +1 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorDescription.js +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +4 -12
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +2 -2
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleLayer.d.ts +5 -20
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleLayer.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts +24 -24
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +16 -16
- package/src/engine/graphics/render/layers/RenderLayer.d.ts +4 -4
- package/src/engine/graphics/render/layers/RenderLayer.d.ts.map +1 -1
- package/src/engine/graphics/render/layers/RenderLayer.js +2 -2
- package/src/engine/graphics/render/make_bvh_visibility_builder.js +1 -1
- package/src/engine/graphics/render/visibility/VisibilityComputer.d.ts +1 -1
- package/src/engine/graphics/render/visibility/VisibilityComputer.js +1 -1
- package/src/engine/graphics/texture/computeThreeTextureInternalFormatFromDataType.d.ts +2 -2
- package/src/engine/graphics/texture/computeThreeTextureInternalFormatFromDataType.d.ts.map +1 -1
- package/src/engine/graphics/texture/computeThreeTextureInternalFormatFromDataType.js +1 -1
- package/src/engine/graphics3/DecalSystem.d.ts +8 -0
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +8 -0
- package/src/engine/graphics3/GraphicsEngine.d.ts +19 -8
- package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine.js +22 -11
- package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
- package/src/engine/graphics3/LightSystem.js +11 -1
- package/src/engine/input/devices/gamepad/GamepadStickCalibration.d.ts +4 -0
- package/src/engine/input/devices/gamepad/GamepadStickCalibration.d.ts.map +1 -1
- package/src/engine/input/devices/gamepad/GamepadStickCalibration.js +4 -0
- package/src/engine/navigation/mesh/NavigationMesh.d.ts +90 -9
- package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
- package/src/engine/navigation/mesh/NavigationMesh.js +80 -8
- package/src/engine/network/NetworkSession.d.ts +60 -0
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +141 -1
- package/src/engine/network/orchestrator/NetworkPeer.d.ts +56 -8
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +263 -67
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +6 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +6 -0
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +13 -7
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +103 -138
- package/src/engine/network/replication/Replicator.d.ts +47 -6
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +362 -107
- package/src/engine/network/sim/ActionLog.d.ts +2 -0
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +2 -0
- package/src/engine/network/sim/ActionRecordCursor.d.ts +82 -0
- package/src/engine/network/sim/ActionRecordCursor.d.ts.map +1 -0
- package/src/engine/network/sim/ActionRecordCursor.js +120 -0
- package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
- package/src/engine/network/sim/RewindEngine.js +13 -29
- package/src/engine/network/sim/SimActionExecutor.d.ts +2 -3
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +10 -11
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +27 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +27 -0
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/sound/SoundEngine.d.ts +24 -0
- package/src/engine/sound/SoundEngine.d.ts.map +1 -1
- package/src/engine/sound/SoundEngine.js +29 -11
- package/src/engine/sound/simulation/configureAcousticSimulation.d.ts +12 -4
- package/src/engine/sound/simulation/configureAcousticSimulation.d.ts.map +1 -1
- package/src/engine/sound/simulation/configureAcousticSimulation.js +10 -4
- package/src/engine/sound/simulation/ecs/AcousticProbeFieldSystem.d.ts +3 -1
- package/src/engine/sound/simulation/ecs/AcousticProbeFieldSystem.d.ts.map +1 -1
- package/src/engine/sound/simulation/ecs/AcousticProbeFieldSystem.js +27 -1
- package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts +34 -0
- package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts.map +1 -1
- package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +61 -2
- package/src/engine/sound/simulation/render/reverbImpulseResponse.d.ts.map +1 -1
- package/src/engine/sound/simulation/render/reverbImpulseResponse.js +9 -0
- package/src/shade/playground/particle_system/README.md +14 -3
- package/src/shade/playground/particle_system/index.html +1 -0
- package/src/shade/playground/particle_system/main.js +15 -2
- package/src/shade/playground/particle_system/particle_scene.d.ts +11 -2
- package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_scene.js +164 -46
- package/src/shade/playground/skinned_mesh_soup/README.md +39 -18
- package/src/shade/playground/skinned_mesh_soup/index.html +9 -6
- package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
- package/src/shade/playground/skinned_mesh_soup/main.js +16 -13
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +8 -2
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +23 -4
- package/src/shade/renderer/GraphicsContext.d.ts +1 -0
- package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
- package/src/shade/renderer/GraphicsContext.js +4 -0
- package/src/shade/renderer/Renderer.d.ts +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +1958 -1796
- package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +357 -0
- package/src/shade/renderer/animation/skin_bind_transform.d.ts +25 -0
- package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_bind_transform.js +33 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts +67 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.js +199 -0
- package/src/shade/renderer/animation/skin_frame_defect.d.ts +34 -0
- package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_frame_defect.js +132 -0
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts +24 -0
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_joint_matrix.js +46 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +70 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.js +216 -0
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts +86 -0
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_test_fixtures.js +250 -0
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts +18 -4
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +18 -4
- package/src/shade/renderer/geometry/MeshletGeometrySerializationAdapter.d.ts +13 -0
- package/src/shade/renderer/geometry/MeshletGeometrySerializationAdapter.d.ts.map +1 -1
- package/src/shade/renderer/geometry/MeshletGeometrySerializationAdapter.js +13 -0
- package/src/shade/renderer/geometry/meshlet_geometry_build_from_geometry.d.ts +18 -0
- package/src/shade/renderer/geometry/meshlet_geometry_build_from_geometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet_geometry_build_from_geometry.js +18 -0
- package/src/shade/renderer/global_illumination/lpv/LightProbeVolume.d.ts +4 -0
- package/src/shade/renderer/global_illumination/lpv/LightProbeVolume.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/LightProbeVolume.js +4 -0
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +12 -0
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +13 -0
- package/src/shade/renderer/light/environment/rgbe/parse_rgbe.d.ts +1 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/DESIGN.md +71 -20
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +29 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +61 -6
- package/src/shade/renderer/particles/ParticleConstants.d.ts +31 -0
- package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
- package/src/shade/renderer/particles/ParticleConstants.js +33 -0
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +61 -0
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -0
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +179 -0
- package/src/shade/renderer/particles/coherence/particle_program_buckets.d.ts +63 -0
- package/src/shade/renderer/particles/coherence/particle_program_buckets.d.ts.map +1 -0
- package/src/shade/renderer/particles/coherence/particle_program_buckets.js +116 -0
- package/src/shade/renderer/particles/coherence/shader_particle_bucket.d.ts +59 -0
- package/src/shade/renderer/particles/coherence/shader_particle_bucket.d.ts.map +1 -0
- package/src/shade/renderer/particles/coherence/shader_particle_bucket.js +344 -0
- package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts +27 -5
- package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.js +27 -5
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +13 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.js +15 -1
- package/src/shade/renderer/particles/data/chunk_particle_emitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/chunk_particle_emitter.js +3 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +43 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +44 -0
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +33 -59
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +185 -118
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +15 -10
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/compile_particle_graph.js +205 -170
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +44 -0
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_graph_authoring.js +108 -0
- package/src/shade/renderer/particles/graph_particles.d.ts +39 -11
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +60 -20
- package/src/shade/renderer/particles/particle_prototype.d.ts.map +1 -1
- package/src/shade/renderer/particles/particle_prototype.js +181 -180
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +8 -1
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/EmitterRegistry.js +8 -1
- package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +22 -2
- package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ProgramArena.js +54 -3
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +4 -4
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/create_particle_effect.js +19 -19
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +32 -14
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +2 -23
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +40 -11
- package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts +6 -17
- package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts.map +1 -1
- package/src/shade/renderer/particles/sort/shader_particle_sort.js +60 -9
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +1 -1
- package/src/shade/renderer/scene/SkinnedMesh.d.ts +11 -0
- package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
- package/src/shade/renderer/scene/SkinnedMesh.js +11 -0
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts +33 -3
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js +58 -37
- package/src/shade/wgsl/emulator/CPUBitmapData.d.ts +1 -1
- package/src/view/DOM.d.ts +69 -0
- package/src/view/DOM.d.ts.map +1 -0
- package/src/view/DOM.js +2 -1
- package/src/view/common/LocalizedLabelView.d.ts +50 -0
- package/src/view/common/LocalizedLabelView.d.ts.map +1 -0
- package/src/view/controller/controls/GuiControl.d.ts +19 -0
- package/src/view/controller/controls/GuiControl.d.ts.map +1 -0
- package/src/view/elements/FrameRateView.d.ts +45 -0
- package/src/view/elements/FrameRateView.d.ts.map +1 -0
- package/src/view/elements/FrameRateView.js +131 -0
- package/src/view/elements/SliderView.d.ts +37 -0
- package/src/view/elements/SliderView.d.ts.map +1 -0
- package/src/view/elements/SliderView.js +71 -0
- package/src/view/elements/navigation/ViewStack.d.ts +1 -1
- package/src/view/elements/navigation/ViewStack.js +1 -1
- package/src/view/elements/notify/NotificationView.d.ts +22 -0
- package/src/view/elements/notify/NotificationView.d.ts.map +1 -0
- package/src/view/tooltip/TooltipView.d.ts +5 -1
- package/src/view/tooltip/TooltipView.d.ts.map +1 -1
- package/src/view/tooltip/TooltipView.js +4 -0
- package/src/shade/renderer/particles/graph/ParticleGraph.d.ts +0 -54
- package/src/shade/renderer/particles/graph/ParticleGraph.d.ts.map +0 -1
- package/src/shade/renderer/particles/graph/ParticleGraph.js +0 -99
|
@@ -1,1796 +1,1958 @@
|
|
|
1
|
-
import { assert } from "../../../core/assert.js";
|
|
2
|
-
import { FrameGraph } from "../../../engine/graphics/render/frame_graph/FrameGraph.js";
|
|
3
|
-
import { GPUDatabase } from "../buffer/table/GPUDatabase.js";
|
|
4
|
-
import {
|
|
5
|
-
graph_scene_update_transform_hierarchy
|
|
6
|
-
} from "../scene/hierarchy/graph_scene_update_transform_hierarchy.js";
|
|
7
|
-
import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
|
|
8
|
-
import {
|
|
9
|
-
ANIMATION_BOUND_TRACK_GROUP_NULL,
|
|
10
|
-
TRACKS_PER_GROUP_NODE,
|
|
11
|
-
} from "./ANIMATION_BOUND_TRACK_GROUP_STRUCT.js";
|
|
12
|
-
import { ANIMATION_DATABASE_SPEC } from "./ANIMATION_DATABASE_SPEC.js";
|
|
13
|
-
import { AnimationClipFlags } from "./AnimationClipFlags.js";
|
|
14
|
-
import { KEYFRAMES_PER_BLOCK } from "./ANIMATION_KEYFRAME_BLOCK_STRUCT.js";
|
|
15
|
-
import {
|
|
16
|
-
ANIMATION_SKIN_JOINT_BLOCK_NULL,
|
|
17
|
-
JOINTS_PER_SKIN_BLOCK,
|
|
18
|
-
} from "./ANIMATION_SKIN_JOINT_BLOCK_STRUCT.js";
|
|
19
|
-
import { POSE_ACCUMULATOR_SLOT_BYTES } from "./POSE_ACCUMULATOR_LAYOUT.js";
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from "./
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
*
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
* cap
|
|
85
|
-
* for a
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* `items
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* @
|
|
110
|
-
* @
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* {@link
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* @
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
*
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
*
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
*
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
*
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
*
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
*
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
*
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
* {@link
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
*
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
* unregister already work
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
*
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
*
|
|
468
|
-
* @
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
*
|
|
762
|
-
* {@link
|
|
763
|
-
*
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
*
|
|
785
|
-
*
|
|
786
|
-
* @
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
* the
|
|
802
|
-
*
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
*
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
* @
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
this.#
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
*
|
|
862
|
-
*
|
|
863
|
-
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
const
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
*
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
//
|
|
1033
|
-
//
|
|
1034
|
-
//
|
|
1035
|
-
//
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
//
|
|
1041
|
-
//
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
//
|
|
1060
|
-
//
|
|
1061
|
-
//
|
|
1062
|
-
//
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
//
|
|
1100
|
-
//
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
*
|
|
1299
|
-
*
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
const
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
*
|
|
1448
|
-
*
|
|
1449
|
-
*
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
this.#
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
//
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
*
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1564
|
-
*
|
|
1565
|
-
*
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
1568
|
-
*
|
|
1569
|
-
*
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
.
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
//
|
|
1618
|
-
//
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
*
|
|
1639
|
-
*
|
|
1640
|
-
*
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1643
|
-
*
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1
|
+
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import { FrameGraph } from "../../../engine/graphics/render/frame_graph/FrameGraph.js";
|
|
3
|
+
import { GPUDatabase } from "../buffer/table/GPUDatabase.js";
|
|
4
|
+
import {
|
|
5
|
+
graph_scene_update_transform_hierarchy
|
|
6
|
+
} from "../scene/hierarchy/graph_scene_update_transform_hierarchy.js";
|
|
7
|
+
import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
|
|
8
|
+
import {
|
|
9
|
+
ANIMATION_BOUND_TRACK_GROUP_NULL,
|
|
10
|
+
TRACKS_PER_GROUP_NODE,
|
|
11
|
+
} from "./ANIMATION_BOUND_TRACK_GROUP_STRUCT.js";
|
|
12
|
+
import { ANIMATION_DATABASE_SPEC } from "./ANIMATION_DATABASE_SPEC.js";
|
|
13
|
+
import { AnimationClipFlags } from "./AnimationClipFlags.js";
|
|
14
|
+
import { KEYFRAMES_PER_BLOCK } from "./ANIMATION_KEYFRAME_BLOCK_STRUCT.js";
|
|
15
|
+
import {
|
|
16
|
+
ANIMATION_SKIN_JOINT_BLOCK_NULL,
|
|
17
|
+
JOINTS_PER_SKIN_BLOCK,
|
|
18
|
+
} from "./ANIMATION_SKIN_JOINT_BLOCK_STRUCT.js";
|
|
19
|
+
import { POSE_ACCUMULATOR_SLOT_BYTES } from "./POSE_ACCUMULATOR_LAYOUT.js";
|
|
20
|
+
import {
|
|
21
|
+
clip_scale_channels,
|
|
22
|
+
skin_clip_scale_conflicts
|
|
23
|
+
} from "./skin_clip_scale_conflicts.js";
|
|
24
|
+
import { skin_normalize_mesh_frame } from "./skin_normalize_mesh_frame.js";
|
|
25
|
+
import {
|
|
26
|
+
shader_animation_apply,
|
|
27
|
+
WORKGROUP_SIZE as ANIMATION_APPLY_WORKGROUP_SIZE,
|
|
28
|
+
} from "./shader_animation_apply.js";
|
|
29
|
+
import {
|
|
30
|
+
shader_animation_pose_resolve,
|
|
31
|
+
WORKGROUP_SIZE as ANIMATION_POSE_RESOLVE_WORKGROUP_SIZE,
|
|
32
|
+
} from "./shader_animation_pose_resolve.js";
|
|
33
|
+
import {
|
|
34
|
+
shader_animation_tick,
|
|
35
|
+
WORKGROUP_SIZE as ANIMATION_TICK_WORKGROUP_SIZE,
|
|
36
|
+
} from "./shader_animation_tick.js";
|
|
37
|
+
import {
|
|
38
|
+
shader_skin_matrix_prep,
|
|
39
|
+
WORKGROUP_SIZE as SKIN_MATRIX_PREP_WORKGROUP_SIZE,
|
|
40
|
+
} from "./skinning/shader_skin_matrix_prep.js";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Tail-slot placeholders for the fixed-size inline arrays in chain
|
|
44
|
+
* nodes. The shader's `count` guard means these bytes are never read,
|
|
45
|
+
* but the upload buffer doesn't zero unwritten ranges and
|
|
46
|
+
* `write_struct_value` skips undefined fields — so explicit zeros are
|
|
47
|
+
* the only way to keep tail bytes deterministic. Frozen so a stray
|
|
48
|
+
* mutation can't bleed into multiple slots that share the reference.
|
|
49
|
+
*/
|
|
50
|
+
const ZERO_KEYFRAME = Object.freeze({ time: 0, value: 0, inTangent: 0, outTangent: 0 });
|
|
51
|
+
const ZERO_BINDING = Object.freeze({ track: 0, instance: 0, property: 0 });
|
|
52
|
+
// Object.freeze on a typed array with elements throws under V8
|
|
53
|
+
// ("Cannot freeze array buffer views with elements"), so we leave the
|
|
54
|
+
// Float32Array unfrozen — the surrounding placeholder object is still
|
|
55
|
+
// frozen to keep accidental field-level mutation out of bounds.
|
|
56
|
+
const ZERO_INVERSE_BIND = new Float32Array(16);
|
|
57
|
+
const ZERO_SKIN_JOINT = Object.freeze({ node: 0, inverse_bind: ZERO_INVERSE_BIND });
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* One skinning matrix is a `mat4x4f` — 16 f32s, 64 bytes. The
|
|
61
|
+
* `skin_matrices` scratch buffer holds one entry per (skin, joint) pair
|
|
62
|
+
* across every registered skin.
|
|
63
|
+
*/
|
|
64
|
+
const SKIN_MATRIX_BYTES = 64;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Initial capacity of the `skin_matrices` scratch buffer, in matrices.
|
|
68
|
+
* 256 × 64 = 16 KB — fits a handful of small skeletons before the first
|
|
69
|
+
* grow. Picked to be wasteful neither at "no skins" nor "one character"
|
|
70
|
+
* scale; growth doubles, so a few realloc cycles cover anything larger.
|
|
71
|
+
*/
|
|
72
|
+
const SKIN_MATRICES_INITIAL_CAPACITY = 256;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Initial capacity of the {@link #pose_accumulator_buffer} in rows
|
|
76
|
+
* (= transforms-table slots). 256 × 64 = 16 KB; growth doubles to
|
|
77
|
+
* fit larger scenes. Resolve always zeroes the slot after draining,
|
|
78
|
+
* so a fresh buffer (createBuffer is zero-initialised) and a "no
|
|
79
|
+
* contribution this frame" state are observationally identical.
|
|
80
|
+
*/
|
|
81
|
+
const POSE_ACCUMULATOR_INITIAL_CAPACITY = 256;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Per-frame `dt` cap pushed into the tick shader. Without it, a tab
|
|
85
|
+
* backgrounded for several seconds (or a paused debugger) would
|
|
86
|
+
* leak that whole interval into the next tick — either rocketing a
|
|
87
|
+
* looping clip through dozens of cycles in one step or, for
|
|
88
|
+
* non-looping clips, clamping them past the meaningful range. The
|
|
89
|
+
* cap trades a few frames of CSS-smooth animation after a stall
|
|
90
|
+
* for a deterministic clip state.
|
|
91
|
+
*/
|
|
92
|
+
const MAX_DT_SECONDS = 1 / 15;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Allocate a singly-linked chain of fixed-capacity nodes into `table`,
|
|
96
|
+
* one node per `items_per_chunk`-sized window of `items`. Builds
|
|
97
|
+
* tail-first so each node's successor id is known at `add()` time —
|
|
98
|
+
* the alternative (forward + back-patch) would mean a second `set()`
|
|
99
|
+
* per node.
|
|
100
|
+
*
|
|
101
|
+
* `build_node(start, count, next_id)` constructs the record to add: it
|
|
102
|
+
* populates the inline array from `items[start..start+count]`, pads
|
|
103
|
+
* tail slots, and assembles any extra payload the table expects
|
|
104
|
+
* (including embedding `next_id` as the node's `next` field).
|
|
105
|
+
*
|
|
106
|
+
* Returns the head id (the last `add()`'s slot id), or `0xFFFFFFFF` if
|
|
107
|
+
* `items` is empty.
|
|
108
|
+
*
|
|
109
|
+
* @template T
|
|
110
|
+
* @template R
|
|
111
|
+
* @param {{ add: (record: R) => number }} table
|
|
112
|
+
* @param {T[]} items
|
|
113
|
+
* @param {number} items_per_chunk
|
|
114
|
+
* @param {(start: number, count: number, next_id: number) => R} build_node
|
|
115
|
+
* @returns {number}
|
|
116
|
+
*/
|
|
117
|
+
function add_linked_chain(table, items, items_per_chunk, build_node) {
|
|
118
|
+
const node_count = Math.ceil(items.length / items_per_chunk);
|
|
119
|
+
let next_id = 0xFFFFFFFF;
|
|
120
|
+
|
|
121
|
+
for (let n = node_count - 1; n >= 0; n--) {
|
|
122
|
+
const start = n * items_per_chunk;
|
|
123
|
+
const this_count = Math.min(items_per_chunk, items.length - start);
|
|
124
|
+
next_id = table.add(build_node(start, this_count, next_id));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return next_id;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Top-level coordinator for GPU-resident animation.
|
|
132
|
+
*
|
|
133
|
+
* Owns a single {@link GPUDatabase} keyed by {@link ANIMATION_DATABASE_SPEC}
|
|
134
|
+
* with five tables: `animation_curves`, `animation_keyframe_blocks`,
|
|
135
|
+
* `animation_tracks`, `animation_clips`, `animation_bound_track_groups`.
|
|
136
|
+
* Every record — including individual keyframes (inlined inside block
|
|
137
|
+
* nodes) and individual bindings (inlined inside group nodes) — lives in
|
|
138
|
+
* the database, so the dispatch shader needs only one storage binding.
|
|
139
|
+
*
|
|
140
|
+
* Animation *data* (curves, keyframes, tracks) is independent from
|
|
141
|
+
* *bound clips* (each carrying a `time` and a head pointer to its
|
|
142
|
+
* bound-track group chain). Bindings are no longer their own table:
|
|
143
|
+
* each chain node inlines up to {@link TRACKS_PER_GROUP_NODE} bindings
|
|
144
|
+
* and back-references its owning clip.
|
|
145
|
+
*
|
|
146
|
+
* Usage:
|
|
147
|
+
* 1. (Once at setup) Either low-level (`add_curve`, `add_track`,
|
|
148
|
+
* `add_skin`, `add_clip`) or high-level (`register_skin`,
|
|
149
|
+
* `register_clip` against the CPU data classes {@link Skin} /
|
|
150
|
+
* {@link ShadeAnimationClip}).
|
|
151
|
+
* 2. (Once) {@link start} per clip to begin GPU-driven playback —
|
|
152
|
+
* the {@link shader_animation_tick} pass advances `time` each
|
|
153
|
+
* frame thereafter. CPU-driven prototypes can instead call
|
|
154
|
+
* {@link set_time} per frame and skip the Playing flag.
|
|
155
|
+
* 3. (Per frame) {@link update} flushes pending writes for the
|
|
156
|
+
* database. The scene context already does this on its own
|
|
157
|
+
* update path.
|
|
158
|
+
*/
|
|
159
|
+
export class GPUAnimationManager {
|
|
160
|
+
|
|
161
|
+
/** @type {GPUDevice} */
|
|
162
|
+
#device;
|
|
163
|
+
|
|
164
|
+
/** @type {string} */
|
|
165
|
+
#label;
|
|
166
|
+
|
|
167
|
+
/** @type {GPUDatabase} */
|
|
168
|
+
#database;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Ping-pong pair of per-frame skinning-matrix buffers — one holds
|
|
172
|
+
* this frame's matrices (target of the prep dispatch, source for
|
|
173
|
+
* skinning's current-position write), the other last frame's
|
|
174
|
+
* (source for skinning's `position_prev` write that feeds the
|
|
175
|
+
* velocity post-pass).
|
|
176
|
+
*
|
|
177
|
+
* Ping-pong rather than a single buffer because the prev-frame
|
|
178
|
+
* matrices need to survive next frame's prep dispatch — and the
|
|
179
|
+
* cheapest way to preserve them is to write the new matrices into
|
|
180
|
+
* the OTHER buffer instead of overwriting the only one we have.
|
|
181
|
+
*
|
|
182
|
+
* {@link #skin_matrices_current_index} selects which entry of this
|
|
183
|
+
* array is "current" for the frame about to be dispatched;
|
|
184
|
+
* {@link dispatch_skin_matrix_prep} flips it before each frame's
|
|
185
|
+
* prep so the now-stale slot gets recycled.
|
|
186
|
+
*
|
|
187
|
+
* Lazily allocated on first {@link add_skin}; both grow together
|
|
188
|
+
* by doubling. After a grow both buffers are zero-initialised and
|
|
189
|
+
* {@link #first_frame_skin_matrices} is set so the next prep
|
|
190
|
+
* dispatch seeds the "previous" buffer with a copy of the freshly
|
|
191
|
+
* written "current" — without this, the first velocity readback
|
|
192
|
+
* after a grow would interpolate against zero matrices.
|
|
193
|
+
*
|
|
194
|
+
* @type {Array<GPUBuffer|null>}
|
|
195
|
+
*/
|
|
196
|
+
#skin_matrices_buffers = [null, null];
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Which entry of {@link #skin_matrices_buffers} is "current" for
|
|
200
|
+
* the next prep dispatch. Flipped at the start of every prep call.
|
|
201
|
+
* @type {number}
|
|
202
|
+
*/
|
|
203
|
+
#skin_matrices_current_index = 0;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* When true, the next prep dispatch will copy the freshly-written
|
|
207
|
+
* "current" buffer into the "previous" buffer at the end of the
|
|
208
|
+
* pass — used on first allocation and after every grow so the
|
|
209
|
+
* very first velocity computation has matching prev/current
|
|
210
|
+
* matrices (zero velocity).
|
|
211
|
+
* @type {boolean}
|
|
212
|
+
*/
|
|
213
|
+
#first_frame_skin_matrices = true;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Capacity of each of {@link #skin_matrices_buffers} in matrices
|
|
217
|
+
* (not bytes). Both buffers always have the same capacity.
|
|
218
|
+
* @type {number}
|
|
219
|
+
*/
|
|
220
|
+
#skin_matrices_capacity = 0;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Next free matrix index. Each {@link add_skin} reserves
|
|
224
|
+
* `joint_count` consecutive entries starting here, then advances.
|
|
225
|
+
* Monotonic — no freeing in the MVP.
|
|
226
|
+
* @type {number}
|
|
227
|
+
*/
|
|
228
|
+
#next_skin_matrix_offset = 0;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* CPU-side `skin_id → skin_matrix_offset` map. Each registered
|
|
232
|
+
* skin's base address in the shared `skin_matrices` scratch
|
|
233
|
+
* buffer; the per-block absolute offset (the prep shader's hot
|
|
234
|
+
* path) is derived as `base + chain_position *
|
|
235
|
+
* JOINTS_PER_SKIN_BLOCK` at registration. Storing the base on
|
|
236
|
+
* GPU would duplicate it — the block records already carry the
|
|
237
|
+
* per-block absolute address, and only the CPU (the skinning-
|
|
238
|
+
* binding upload path) needs the skin's base value.
|
|
239
|
+
*
|
|
240
|
+
* @type {Map<number, number>}
|
|
241
|
+
*/
|
|
242
|
+
#skin_matrix_offsets = new Map();
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Registered skins by id, kept for one reason: a clip registered *after* a skin has to be held
|
|
246
|
+
* against it, and a clip registered before one has to be held against the skin when it arrives.
|
|
247
|
+
* The frame a skinned mesh is deformed in is fixed once, at registration, and a clip that scales
|
|
248
|
+
* a joint is the one thing that can undo it afterwards — see {@link skin_clip_scale_conflicts}
|
|
249
|
+
* and `SKINNING_FRAME_PLAN.md` §4.
|
|
250
|
+
*
|
|
251
|
+
* @type {Map<number, Skin>}
|
|
252
|
+
*/
|
|
253
|
+
#skins_by_id = new Map();
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Registered clips that scale *something*, by id. Almost always empty — a character's clips
|
|
257
|
+
* rotate and translate — which is what keeps the pairwise check free in the ordinary case.
|
|
258
|
+
*
|
|
259
|
+
* @type {Map<number, ShadeAnimationClip>}
|
|
260
|
+
*/
|
|
261
|
+
#scaling_clips = new Map();
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Per-frame pose-accumulator scratch buffer. One slot per
|
|
265
|
+
* `transforms_table` row (slot size = `POSE_ACCUMULATOR_SLOT_BYTES`).
|
|
266
|
+
* The apply pass atomic-adds weighted TRS contributions into each
|
|
267
|
+
* dirty row; the resolve pass drains it into `transforms_table.local_*`
|
|
268
|
+
* and zeros the slot for next frame.
|
|
269
|
+
*
|
|
270
|
+
* Lazily allocated on first {@link ensure_pose_accumulator_capacity};
|
|
271
|
+
* grows by doubling. Grow destroys the old buffer — since resolve
|
|
272
|
+
* always leaves it zero, no copy is needed on grow.
|
|
273
|
+
*
|
|
274
|
+
* @type {GPUBuffer|null}
|
|
275
|
+
*/
|
|
276
|
+
#pose_accumulator_buffer = null;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Capacity of {@link #pose_accumulator_buffer} in rows (slot
|
|
280
|
+
* indices), not bytes.
|
|
281
|
+
* @type {number}
|
|
282
|
+
*/
|
|
283
|
+
#pose_accumulator_capacity = 0;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Back-reference to the owning scene context. Lets the high-level
|
|
287
|
+
* `register_*` methods resolve `Node3D.id` → transforms-table row
|
|
288
|
+
* via {@link GPUSceneContext#id_mapping} and bind skinning meshes
|
|
289
|
+
* via {@link GPUSceneContext#skinning}, without callers having to
|
|
290
|
+
* thread the context through every call.
|
|
291
|
+
*
|
|
292
|
+
* The manager doesn't touch this at construction (the scene
|
|
293
|
+
* context is itself only partially constructed when it builds the
|
|
294
|
+
* manager) — only inside `register_*` calls, which happen after
|
|
295
|
+
* scene.build has populated `id_mapping`.
|
|
296
|
+
*
|
|
297
|
+
* @type {GPUSceneContext}
|
|
298
|
+
*/
|
|
299
|
+
#scene_context;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Identity-keyed cache of curve-id-on-GPU for every
|
|
303
|
+
* {@link AnimationCurve} that has been registered via
|
|
304
|
+
* {@link register_clip}. Lets multiple clips whose channels share
|
|
305
|
+
* the same curve instance (e.g. one base clip retargeted across
|
|
306
|
+
* many character instances) reuse the same GPU rows for the
|
|
307
|
+
* curve header + keyframe blocks rather than uploading
|
|
308
|
+
* duplicates. At grid-of-dancers scale duplication would balloon
|
|
309
|
+
* the keyframe-blocks table past its page-table limits.
|
|
310
|
+
*
|
|
311
|
+
* Low-level `add_curve` deliberately stays uncached — every call
|
|
312
|
+
* uploads — so existing callers that pre-build curves with
|
|
313
|
+
* distinct IDs (e.g. a pre-built track pool)
|
|
314
|
+
* keep their behavior.
|
|
315
|
+
*
|
|
316
|
+
* @type {WeakMap<AnimationCurve, number>}
|
|
317
|
+
*/
|
|
318
|
+
#curve_id_cache = new WeakMap();
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* The curves uploaded so far, by what they are rather than which instance they were: the
|
|
322
|
+
* `hash()` of a curve's keys, to every uploaded curve with that hash and its GPU id.
|
|
323
|
+
*
|
|
324
|
+
* An instance cache alone shares nothing between two parses of one file, and a character
|
|
325
|
+
* instanced a few hundred times is a few hundred parses — each with its own instances of the
|
|
326
|
+
* same keys, filling the keyframe-block table with copies of one dance until its page limit
|
|
327
|
+
* refuses the next dancer. Curves are read-only once uploaded and nothing here releases them,
|
|
328
|
+
* so equal content can safely mean one upload.
|
|
329
|
+
*
|
|
330
|
+
* A hash bucket is a list because a hash is not an identity: a curve is only shared with one
|
|
331
|
+
* whose every key `equals` its own, tangents included.
|
|
332
|
+
*
|
|
333
|
+
* @type {Map<number, {curve: AnimationCurve, id: number}[]>}
|
|
334
|
+
*/
|
|
335
|
+
#curve_id_by_content = new Map();
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Cache of track-id-on-GPU keyed by `(curve_id_x, curve_id_y,
|
|
339
|
+
* curve_id_z, curve_id_w, mask)`. With curve dedup already
|
|
340
|
+
* sharing curve IDs across clips, two channels in different
|
|
341
|
+
* clips that bind to the same (target_property, curves) end up
|
|
342
|
+
* with identical track keys — and we can share the track row
|
|
343
|
+
* too. Each curve_id slot is `-1` when the corresponding channel
|
|
344
|
+
* is absent.
|
|
345
|
+
*
|
|
346
|
+
* Keys are joined into a string for Map lookup; the join cost is
|
|
347
|
+
* negligible compared to the GPU upload it avoids.
|
|
348
|
+
*
|
|
349
|
+
* @type {Map<string, number>}
|
|
350
|
+
*/
|
|
351
|
+
#track_id_cache = new Map();
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Skins registered via {@link register_skin} whose joint-block
|
|
355
|
+
* chain hasn't been built yet because one or more joint Node3Ds
|
|
356
|
+
* lacks an `id_mapping` row. The skin's GPU table row exists
|
|
357
|
+
* (placeholder `joint_block_head = NULL`, no joints driving the
|
|
358
|
+
* prep pass yet), and state mutators / unregister already work
|
|
359
|
+
* — but the deformation only kicks in once {@link update}
|
|
360
|
+
* successfully drains the entry.
|
|
361
|
+
*
|
|
362
|
+
* Each entry: `skin_id`, the CPU {@link Skin} (whose `joints`
|
|
363
|
+
* array drives the chain build), the `skin_matrix_offset`
|
|
364
|
+
* reserved at register time, and the `inverse_bind_matrices`
|
|
365
|
+
* typed array.
|
|
366
|
+
*
|
|
367
|
+
* @type {Array<{
|
|
368
|
+
* skin_id: number,
|
|
369
|
+
* skin: Skin,
|
|
370
|
+
* skin_matrix_offset: number,
|
|
371
|
+
* inverse_bind_matrices: Float32Array,
|
|
372
|
+
* }>}
|
|
373
|
+
*/
|
|
374
|
+
#pending_skins = [];
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Clips registered via {@link register_clip} whose bindings
|
|
378
|
+
* chain hasn't been built yet because one or more channel
|
|
379
|
+
* targets lacks an `id_mapping` row. The clip's GPU table row
|
|
380
|
+
* exists (placeholder `bound_track_group_head = NULL`, no
|
|
381
|
+
* tracks driving the apply pass yet); time/state mutators and
|
|
382
|
+
* unregister already work.
|
|
383
|
+
*
|
|
384
|
+
* Each entry: `clip_id` plus the per-channel `(track_id,
|
|
385
|
+
* target, property)` triples — the curves and tracks were
|
|
386
|
+
* interned at register time so only the (target → instance row)
|
|
387
|
+
* resolution is deferred.
|
|
388
|
+
*
|
|
389
|
+
* @type {Array<{
|
|
390
|
+
* clip_id: number,
|
|
391
|
+
* channels: Array<{ track: number, target: Node3D, property: number }>,
|
|
392
|
+
* }>}
|
|
393
|
+
*/
|
|
394
|
+
#pending_clips = [];
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* @param {GPUDevice} device
|
|
398
|
+
* @param {string} label
|
|
399
|
+
* @param {GPUSceneContext} scene_context
|
|
400
|
+
*/
|
|
401
|
+
constructor(device, label, scene_context) {
|
|
402
|
+
assert.defined(device, 'device');
|
|
403
|
+
assert.defined(scene_context, 'scene_context');
|
|
404
|
+
|
|
405
|
+
this.#device = device;
|
|
406
|
+
this.#label = label;
|
|
407
|
+
this.#scene_context = scene_context;
|
|
408
|
+
|
|
409
|
+
this.#database = new GPUDatabase({
|
|
410
|
+
device,
|
|
411
|
+
definition: ANIMATION_DATABASE_SPEC,
|
|
412
|
+
label: `${label}/Database`,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* @returns {GPUDatabase}
|
|
418
|
+
*/
|
|
419
|
+
get database() {
|
|
420
|
+
return this.#database;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Per-frame skinning-matrix scratch buffer for the *current*
|
|
425
|
+
* frame. `null` until the first skin is registered. The
|
|
426
|
+
* skin-matrix-prep pass writes to it; the skinning compute pass
|
|
427
|
+
* reads from it to deform current-frame positions. Address `j`
|
|
428
|
+
* of skin `s` is at matrix index `s.skin_matrix_offset + j`.
|
|
429
|
+
*
|
|
430
|
+
* The buffer reference is invalidated on grow AND flips role
|
|
431
|
+
* every frame as part of the ping-pong with
|
|
432
|
+
* {@link prev_skin_matrices_buffer} — re-fetch each frame.
|
|
433
|
+
*
|
|
434
|
+
* @returns {GPUBuffer|null}
|
|
435
|
+
*/
|
|
436
|
+
get skin_matrices_buffer() {
|
|
437
|
+
return this.#skin_matrices_buffers[this.#skin_matrices_current_index];
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Previous-frame counterpart of {@link skin_matrices_buffer} —
|
|
442
|
+
* holds the matrices the previous frame's prep dispatch wrote.
|
|
443
|
+
* Read by the skinning compute pass to produce per-vertex
|
|
444
|
+
* `position_prev` data for the velocity post-pass.
|
|
445
|
+
*
|
|
446
|
+
* `null` until the first skin is registered. Flips role with
|
|
447
|
+
* {@link skin_matrices_buffer} every frame.
|
|
448
|
+
*
|
|
449
|
+
* @returns {GPUBuffer|null}
|
|
450
|
+
*/
|
|
451
|
+
get prev_skin_matrices_buffer() {
|
|
452
|
+
return this.#skin_matrices_buffers[1 - this.#skin_matrices_current_index];
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Number of matrices currently in use (= sum of `joint_count` over
|
|
457
|
+
* registered skins). Independent of buffer capacity, which is at
|
|
458
|
+
* least this big.
|
|
459
|
+
*
|
|
460
|
+
* @returns {number}
|
|
461
|
+
*/
|
|
462
|
+
get skin_matrix_count() {
|
|
463
|
+
return this.#next_skin_matrix_offset;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Pose-accumulator scratch buffer (per-Node3D-row weighted
|
|
468
|
+
* contribution slots). `null` until {@link ensure_pose_accumulator_capacity}
|
|
469
|
+
* is called for the first time.
|
|
470
|
+
*
|
|
471
|
+
* The buffer reference is invalidated on grow — re-fetch each
|
|
472
|
+
* frame after {@link ensure_pose_accumulator_capacity} rather
|
|
473
|
+
* than caching across frames.
|
|
474
|
+
*
|
|
475
|
+
* @returns {GPUBuffer|null}
|
|
476
|
+
*/
|
|
477
|
+
get pose_accumulator_buffer() {
|
|
478
|
+
return this.#pose_accumulator_buffer;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Ensure the pose-accumulator scratch buffer can address at least
|
|
483
|
+
* `row_count` `transforms_table` rows. Grows by doubling from the
|
|
484
|
+
* initial capacity; idempotent when already big enough. Called
|
|
485
|
+
* by the per-frame dispatch driver after `scene.build` has
|
|
486
|
+
* stabilised the transforms-table size for the frame.
|
|
487
|
+
*
|
|
488
|
+
* Grow destroys the previous GPU buffer; resolve always leaves the
|
|
489
|
+
* accumulator zeroed at the end of each frame, so there's nothing
|
|
490
|
+
* to copy across the realloc.
|
|
491
|
+
*
|
|
492
|
+
* @param {number} row_count
|
|
493
|
+
*/
|
|
494
|
+
ensure_pose_accumulator_capacity(row_count) {
|
|
495
|
+
assert.isNonNegativeInteger(row_count, 'row_count');
|
|
496
|
+
|
|
497
|
+
// Existing buffer fits the request → nothing to do. The null
|
|
498
|
+
// check guarantees the very first call always allocates,
|
|
499
|
+
// even when `row_count == 0` (e.g. before any scene content
|
|
500
|
+
// has been built): downstream binding paths assume the
|
|
501
|
+
// buffer reference is non-null whenever the apply pass runs.
|
|
502
|
+
if (this.#pose_accumulator_buffer !== null && row_count <= this.#pose_accumulator_capacity) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
let new_capacity = Math.max(this.#pose_accumulator_capacity, POSE_ACCUMULATOR_INITIAL_CAPACITY);
|
|
507
|
+
while (new_capacity < row_count) {
|
|
508
|
+
new_capacity *= 2;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (this.#pose_accumulator_buffer !== null) {
|
|
512
|
+
this.#pose_accumulator_buffer.destroy();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
this.#pose_accumulator_buffer = this.#device.createBuffer({
|
|
516
|
+
label: `${this.#label}/PoseAccumulator`,
|
|
517
|
+
size: new_capacity * POSE_ACCUMULATOR_SLOT_BYTES,
|
|
518
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
|
|
519
|
+
});
|
|
520
|
+
this.#pose_accumulator_capacity = new_capacity;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Read back a skin's record from the database's CPU shadow.
|
|
525
|
+
*
|
|
526
|
+
* @param {number} skin_id
|
|
527
|
+
* @returns {{joint_block_head: number, joint_count: number}}
|
|
528
|
+
*/
|
|
529
|
+
get_skin(skin_id) {
|
|
530
|
+
assert.isNonNegativeInteger(skin_id, 'skin_id');
|
|
531
|
+
return this.#database.get('animation_skins').get(skin_id);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Base address of the skin's matrix range in the shared
|
|
536
|
+
* `skin_matrices` scratch buffer — matrix `j` of the skin lives
|
|
537
|
+
* at `skin_matrices[get_skin_matrix_offset(skin_id) + j]`.
|
|
538
|
+
*
|
|
539
|
+
* Tracked CPU-side rather than on the skin record because the
|
|
540
|
+
* value is only ever consumed by the skinning-binding upload
|
|
541
|
+
* path; the prep shader uses the per-block absolute offset
|
|
542
|
+
* (cheaper than a per-thread skin lookup for that hot path).
|
|
543
|
+
*
|
|
544
|
+
* @param {number} skin_id
|
|
545
|
+
* @returns {number}
|
|
546
|
+
*/
|
|
547
|
+
get_skin_matrix_offset(skin_id) {
|
|
548
|
+
assert.isNonNegativeInteger(skin_id, 'skin_id');
|
|
549
|
+
const offset = this.#skin_matrix_offsets.get(skin_id);
|
|
550
|
+
assert.defined(offset, `unknown skin_id ${skin_id}`);
|
|
551
|
+
return offset;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Add an animation curve. Keyframes are split into linked-list blocks
|
|
556
|
+
* of up to {@link KEYFRAMES_PER_BLOCK} entries each; the curve header
|
|
557
|
+
* points at the head block, and each block's `next` field chains
|
|
558
|
+
* forward.
|
|
559
|
+
*
|
|
560
|
+
* The curve is a cubic Hermite spline — step, linear, and arbitrary
|
|
561
|
+
* cubic shapes are all expressible by choosing tangents on each keyframe.
|
|
562
|
+
*
|
|
563
|
+
* @param {AnimationCurve} curve
|
|
564
|
+
* @returns {number} curve id (index into the `animation_curves` table)
|
|
565
|
+
*/
|
|
566
|
+
add_curve(curve) {
|
|
567
|
+
assert.defined(curve, 'curve');
|
|
568
|
+
assert.equal(curve.isAnimationCurve, true, 'curve.isAnimationCurve !== true');
|
|
569
|
+
assert.greaterThanOrEqual(curve.length, 1, 'curve must have at least one keyframe');
|
|
570
|
+
|
|
571
|
+
const keys = curve.keys;
|
|
572
|
+
const blocks_table = this.#database.get('animation_keyframe_blocks');
|
|
573
|
+
|
|
574
|
+
const head_block_id = add_linked_chain(
|
|
575
|
+
blocks_table,
|
|
576
|
+
keys,
|
|
577
|
+
KEYFRAMES_PER_BLOCK,
|
|
578
|
+
(start, count, next) => {
|
|
579
|
+
const keyframes = new Array(KEYFRAMES_PER_BLOCK);
|
|
580
|
+
for (let j = 0; j < KEYFRAMES_PER_BLOCK; j++) {
|
|
581
|
+
keyframes[j] = j < count ? keys[start + j] : ZERO_KEYFRAME;
|
|
582
|
+
}
|
|
583
|
+
return { keyframes, count, next };
|
|
584
|
+
}
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
const curves_table = this.#database.get('animation_curves');
|
|
588
|
+
return curves_table.add({
|
|
589
|
+
kind: 0,
|
|
590
|
+
keyframe_block_head: head_block_id,
|
|
591
|
+
keyframe_count: keys.length,
|
|
592
|
+
time_min: curve.start_time,
|
|
593
|
+
time_max: curve.end_time,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Add a track. Channels are addressed by name (`x`, `y`, `z`, `w`) — the
|
|
599
|
+
* provided curves go into the matching slots of the track's `vec4f`
|
|
600
|
+
* output. Omitted channels are masked off and read as 0.
|
|
601
|
+
*
|
|
602
|
+
* The slot meaning is property-specific: for `MeshTranslation`, x/y/z
|
|
603
|
+
* are the translation components; for `MeshRotation` they're the
|
|
604
|
+
* quaternion's x/y/z/w. The track's mask travels with the evaluated
|
|
605
|
+
* value to the apply step, which uses it to decide which destinations
|
|
606
|
+
* to overwrite.
|
|
607
|
+
*
|
|
608
|
+
* @param {{ x?: number, y?: number, z?: number, w?: number }} channels
|
|
609
|
+
* curve ids per channel; pass at least one
|
|
610
|
+
* @returns {number} track id (index into the `animation_tracks` table)
|
|
611
|
+
*/
|
|
612
|
+
add_track(channels) {
|
|
613
|
+
assert.defined(channels, 'channels');
|
|
614
|
+
|
|
615
|
+
const cx = channels.x;
|
|
616
|
+
const cy = channels.y;
|
|
617
|
+
const cz = channels.z;
|
|
618
|
+
const cw = channels.w;
|
|
619
|
+
|
|
620
|
+
let mask = 0;
|
|
621
|
+
if (cx !== undefined) mask |= 0x1;
|
|
622
|
+
if (cy !== undefined) mask |= 0x2;
|
|
623
|
+
if (cz !== undefined) mask |= 0x4;
|
|
624
|
+
if (cw !== undefined) mask |= 0x8;
|
|
625
|
+
|
|
626
|
+
assert.notEqual(mask, 0, 'track must have at least one channel');
|
|
627
|
+
|
|
628
|
+
const curves = [
|
|
629
|
+
cx ?? 0,
|
|
630
|
+
cy ?? 0,
|
|
631
|
+
cz ?? 0,
|
|
632
|
+
cw ?? 0,
|
|
633
|
+
];
|
|
634
|
+
|
|
635
|
+
const table = this.#database.get('animation_tracks');
|
|
636
|
+
return table.add({ mask, curves });
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Create a bound clip — a group of bound tracks that share a single
|
|
641
|
+
* `time`. Bindings are split into linked-list group nodes of up to
|
|
642
|
+
* {@link TRACKS_PER_GROUP_NODE} each; the clip points at the head
|
|
643
|
+
* node and each node back-references the clip so the apply shader
|
|
644
|
+
* (one thread per group node) can fetch the clip without walking the
|
|
645
|
+
* chain from the clip end.
|
|
646
|
+
*
|
|
647
|
+
* Tracks may be authored on a clock that doesn't align with
|
|
648
|
+
* `[time_start, time_end]` — their curves are clamped to their own
|
|
649
|
+
* `[time_min, time_max]` during evaluation.
|
|
650
|
+
*
|
|
651
|
+
* Defaults: `time = 0`, `time_start = 0`, `time_end = 0`,
|
|
652
|
+
* `playback_rate = 1`, `playback_weight = 1`, `flags = 0` (not
|
|
653
|
+
* playing, not looping). The clip is inert at creation — call
|
|
654
|
+
* {@link start} to begin GPU-side time advancement.
|
|
655
|
+
*
|
|
656
|
+
* @param {{
|
|
657
|
+
* time?: number,
|
|
658
|
+
* time_start?: number,
|
|
659
|
+
* time_end?: number,
|
|
660
|
+
* bindings: Array<{ track: number, instance: number, property: number }>,
|
|
661
|
+
* }} clip
|
|
662
|
+
* @returns {number} clip id (index into the `animation_clips` table)
|
|
663
|
+
*/
|
|
664
|
+
add_clip(clip) {
|
|
665
|
+
assert.defined(clip, 'clip');
|
|
666
|
+
assert.isArray(clip.bindings, 'clip.bindings');
|
|
667
|
+
assert.greaterThanOrEqual(clip.bindings.length, 1, 'clip must have at least one binding');
|
|
668
|
+
|
|
669
|
+
const time = clip.time ?? 0;
|
|
670
|
+
const time_start = clip.time_start ?? 0;
|
|
671
|
+
const time_end = clip.time_end ?? 0;
|
|
672
|
+
const bindings = clip.bindings;
|
|
673
|
+
|
|
674
|
+
const clips_table = this.#database.get('animation_clips');
|
|
675
|
+
const groups_table = this.#database.get('animation_bound_track_groups');
|
|
676
|
+
|
|
677
|
+
// Reserve the clip slot up front so group nodes can back-reference
|
|
678
|
+
// it via `clip`. The head pointer is patched in once the chain is
|
|
679
|
+
// built (we don't know its first id until we've allocated every
|
|
680
|
+
// group node).
|
|
681
|
+
const clip_id = clips_table.add({
|
|
682
|
+
time,
|
|
683
|
+
time_start,
|
|
684
|
+
time_end,
|
|
685
|
+
bound_track_group_head: ANIMATION_BOUND_TRACK_GROUP_NULL,
|
|
686
|
+
playback_rate: 1,
|
|
687
|
+
flags: 0,
|
|
688
|
+
playback_weight: 1,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
const head_group_id = add_linked_chain(
|
|
692
|
+
groups_table,
|
|
693
|
+
bindings,
|
|
694
|
+
TRACKS_PER_GROUP_NODE,
|
|
695
|
+
(start, count, next) => {
|
|
696
|
+
const inline_bindings = new Array(TRACKS_PER_GROUP_NODE);
|
|
697
|
+
for (let j = 0; j < TRACKS_PER_GROUP_NODE; j++) {
|
|
698
|
+
if (j < count) {
|
|
699
|
+
const b = bindings[start + j];
|
|
700
|
+
|
|
701
|
+
assert.isNonNegativeInteger(b.track, `clip.bindings[${start + j}].track`);
|
|
702
|
+
assert.isNonNegativeInteger(b.instance, `clip.bindings[${start + j}].instance`);
|
|
703
|
+
assert.isNonNegativeInteger(b.property, `clip.bindings[${start + j}].property`);
|
|
704
|
+
|
|
705
|
+
inline_bindings[j] = b;
|
|
706
|
+
} else {
|
|
707
|
+
inline_bindings[j] = ZERO_BINDING;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return { bindings: inline_bindings, count, next, clip: clip_id };
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
// Patch the head pointer now that the chain exists. Re-`set` the
|
|
715
|
+
// whole record because the table API doesn't expose per-field
|
|
716
|
+
// updates.
|
|
717
|
+
clips_table.set(clip_id, {
|
|
718
|
+
time,
|
|
719
|
+
time_start,
|
|
720
|
+
time_end,
|
|
721
|
+
bound_track_group_head: head_group_id,
|
|
722
|
+
playback_rate: 1,
|
|
723
|
+
flags: 0,
|
|
724
|
+
playback_weight: 1,
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
return clip_id;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Overwrite a single field of a clip's record by reading the current
|
|
732
|
+
* record back from the CPU shadow and re-`set`ting with one field
|
|
733
|
+
* changed. The table API doesn't expose per-field updates, so we
|
|
734
|
+
* round-trip through a full record; the upload-buffer dedupe
|
|
735
|
+
* collapses the resulting per-frame write into a single GPU touch
|
|
736
|
+
* when nothing else changed.
|
|
737
|
+
*
|
|
738
|
+
* @param {number} clip_id
|
|
739
|
+
* @param {string} field
|
|
740
|
+
* @param {number} value
|
|
741
|
+
*/
|
|
742
|
+
#patch_clip_field(clip_id, field, value) {
|
|
743
|
+
assert.isNonNegativeInteger(clip_id, 'clip_id');
|
|
744
|
+
|
|
745
|
+
const clips_table = this.#database.get('animation_clips');
|
|
746
|
+
const current = clips_table.get(clip_id);
|
|
747
|
+
|
|
748
|
+
clips_table.set(clip_id, {
|
|
749
|
+
time: current.time,
|
|
750
|
+
time_start: current.time_start,
|
|
751
|
+
time_end: current.time_end,
|
|
752
|
+
bound_track_group_head: current.bound_track_group_head,
|
|
753
|
+
playback_rate: current.playback_rate,
|
|
754
|
+
flags: current.flags,
|
|
755
|
+
playback_weight: current.playback_weight,
|
|
756
|
+
[field]: value,
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Direct override of a clip's `time`. Bypasses {@link start} /
|
|
762
|
+
* {@link stop} — `time` is written even if the clip is paused, and
|
|
763
|
+
* the {@link AnimationClipFlags.Playing} bit is left untouched.
|
|
764
|
+
* The host typically uses this to scrub or rewind; GPU-driven
|
|
765
|
+
* playback advances time on its own via the tick shader.
|
|
766
|
+
*
|
|
767
|
+
* TODO: race between `start()` and `set_time()` is non-atomic — if
|
|
768
|
+
* a caller does `start(id); set_time(id, phase)` and the next GPU
|
|
769
|
+
* tick fires before the page upload from `set_time` lands, the
|
|
770
|
+
* tick advances from the old `time` for one frame. RIS would be
|
|
771
|
+
* an atomic `start_at(id, time, ...)` that fuses both field
|
|
772
|
+
* writes into one record set. For phase offsets the one-frame
|
|
773
|
+
* skew is invisible; for scrub-and-resume UIs it can show.
|
|
774
|
+
*
|
|
775
|
+
* @param {number} clip_id
|
|
776
|
+
* @param {number} time
|
|
777
|
+
*/
|
|
778
|
+
set_time(clip_id, time) {
|
|
779
|
+
assert.isNumber(time, 'time');
|
|
780
|
+
this.#patch_clip_field(clip_id, 'time', time);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Direct override of a clip's per-frame advance scalar. `1.0` =
|
|
785
|
+
* realtime; `0.0` effectively pauses (independent of the
|
|
786
|
+
* {@link AnimationClipFlags.Playing} bit); negative values play
|
|
787
|
+
* in reverse.
|
|
788
|
+
*
|
|
789
|
+
* @param {number} clip_id
|
|
790
|
+
* @param {number} rate
|
|
791
|
+
*/
|
|
792
|
+
set_playback_rate(clip_id, rate) {
|
|
793
|
+
assert.isNumber(rate, 'rate');
|
|
794
|
+
this.#patch_clip_field(clip_id, 'playback_rate', rate);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Override a clip's contribution weight into the pose accumulator.
|
|
799
|
+
* `1.0` is full strength; `0.0` silences the clip without removing
|
|
800
|
+
* its bindings; values in between blend it against other clips
|
|
801
|
+
* targeting the same nodes. The apply shader pre-multiplies every
|
|
802
|
+
* curve-evaluated value by this scalar before atomic-adding into
|
|
803
|
+
* the accumulator.
|
|
804
|
+
*
|
|
805
|
+
* Normalized blends expect weights across all clips driving a
|
|
806
|
+
* node to sum to `1`; additive layers use weights that don't sum
|
|
807
|
+
* to `1`. The system doesn't enforce either — host's call.
|
|
808
|
+
*
|
|
809
|
+
* @param {number} clip_id
|
|
810
|
+
* @param {number} weight
|
|
811
|
+
*/
|
|
812
|
+
set_playback_weight(clip_id, weight) {
|
|
813
|
+
assert.isNumber(weight, 'weight');
|
|
814
|
+
this.#patch_clip_field(clip_id, 'playback_weight', weight);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Add (OR) one or more flag bits onto a clip's bitfield. Bits
|
|
819
|
+
* already set stay set; other bits are untouched. Values come
|
|
820
|
+
* from {@link AnimationClipFlags} and can be combined with `|`:
|
|
821
|
+
* `set_flags(id, AnimationClipFlags.Loop | AnimationClipFlags.Playing)`.
|
|
822
|
+
*
|
|
823
|
+
* Counterpart {@link clear_flags} ANDs the bits out. Together
|
|
824
|
+
* they cover the common cases without the overwrite footgun
|
|
825
|
+
* the original version had (where setting Loop would silently
|
|
826
|
+
* clear Playing).
|
|
827
|
+
*
|
|
828
|
+
* For toggling just the playing bit, {@link start} / {@link stop}
|
|
829
|
+
* are equivalent shortcuts.
|
|
830
|
+
*
|
|
831
|
+
* @param {number} clip_id
|
|
832
|
+
* @param {number} flags bits to set
|
|
833
|
+
*/
|
|
834
|
+
set_flags(clip_id, flags) {
|
|
835
|
+
assert.isNonNegativeInteger(flags, 'flags');
|
|
836
|
+
|
|
837
|
+
const clips_table = this.#database.get('animation_clips');
|
|
838
|
+
const current = clips_table.get(clip_id);
|
|
839
|
+
|
|
840
|
+
this.#patch_clip_field(clip_id, 'flags', current.flags | flags);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Clear (AND-NOT) one or more flag bits from a clip's bitfield.
|
|
845
|
+
* Bits not present in `flags` are left untouched. Symmetric
|
|
846
|
+
* with {@link set_flags}.
|
|
847
|
+
*
|
|
848
|
+
* @param {number} clip_id
|
|
849
|
+
* @param {number} flags bits to clear
|
|
850
|
+
*/
|
|
851
|
+
clear_flags(clip_id, flags) {
|
|
852
|
+
assert.isNonNegativeInteger(flags, 'flags');
|
|
853
|
+
|
|
854
|
+
const clips_table = this.#database.get('animation_clips');
|
|
855
|
+
const current = clips_table.get(clip_id);
|
|
856
|
+
|
|
857
|
+
this.#patch_clip_field(clip_id, 'flags', current.flags & ~flags);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Begin GPU-side playback. Sets the {@link AnimationClipFlags.Playing}
|
|
862
|
+
* bit; preserves every other flag bit, the current `time`, the
|
|
863
|
+
* `playback_rate`, and so on. Calling {@link stop} and then `start`
|
|
864
|
+
* back-to-back should feel like a no-op modulo at most one tick's
|
|
865
|
+
* worth of advance.
|
|
866
|
+
*
|
|
867
|
+
* Idempotent: starting an already-playing clip is a no-op (the
|
|
868
|
+
* upload-buffer dedupe collapses the write).
|
|
869
|
+
*
|
|
870
|
+
* @param {number} clip_id
|
|
871
|
+
*/
|
|
872
|
+
start(clip_id) {
|
|
873
|
+
assert.isNonNegativeInteger(clip_id, 'clip_id');
|
|
874
|
+
|
|
875
|
+
const clips_table = this.#database.get('animation_clips');
|
|
876
|
+
const current = clips_table.get(clip_id);
|
|
877
|
+
|
|
878
|
+
this.#patch_clip_field(clip_id, 'flags', current.flags | AnimationClipFlags.Playing);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Pause GPU-side playback. Clears the {@link AnimationClipFlags.Playing}
|
|
883
|
+
* bit; preserves every other flag bit and the current `time`.
|
|
884
|
+
* Symmetric with {@link start} — a stop/start pair leaves the clip
|
|
885
|
+
* where it was (give or take one tick of GPU time loss).
|
|
886
|
+
*
|
|
887
|
+
* Idempotent: stopping an already-stopped clip is a no-op.
|
|
888
|
+
*
|
|
889
|
+
* @param {number} clip_id
|
|
890
|
+
*/
|
|
891
|
+
stop(clip_id) {
|
|
892
|
+
assert.isNonNegativeInteger(clip_id, 'clip_id');
|
|
893
|
+
|
|
894
|
+
const clips_table = this.#database.get('animation_clips');
|
|
895
|
+
const current = clips_table.get(clip_id);
|
|
896
|
+
|
|
897
|
+
this.#patch_clip_field(clip_id, 'flags', current.flags & ~AnimationClipFlags.Playing);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Register a skin: an ordered list of joints, each pinning a
|
|
902
|
+
* Node3D row that drives the joint plus the inverse-bind matrix
|
|
903
|
+
* that takes vertex positions from mesh space into the joint's
|
|
904
|
+
* bind-pose local space. The skin reserves a contiguous range of
|
|
905
|
+
* `joints.length` matrices in the {@link #skin_matrices_buffer}
|
|
906
|
+
* scratch buffer; the prep pass populates that range each frame
|
|
907
|
+
* with `node.global × inverse_bind` for every joint.
|
|
908
|
+
*
|
|
909
|
+
* The skin record carries no mesh-world factor. The rasterizer
|
|
910
|
+
* applies `mesh.transform_global` to the skinned clone vertex
|
|
911
|
+
* via the standard mesh transform path
|
|
912
|
+
* ({@link chunk_mesh_resolve_vertex_position_world}), so adding
|
|
913
|
+
* an `inverse(mesh.global)` factor in the skin matrix would
|
|
914
|
+
* double-cancel against that re-application and shrink the rig
|
|
915
|
+
* back to mesh-local coordinates rendered as world.
|
|
916
|
+
*
|
|
917
|
+
* Joints are split into linked-list blocks of up to
|
|
918
|
+
* {@link JOINTS_PER_SKIN_BLOCK} each — same chain pattern used for
|
|
919
|
+
* bound-track groups and keyframe blocks. Each block records the
|
|
920
|
+
* absolute write offset for its slots, so the prep shader's
|
|
921
|
+
* per-thread work is one block load + a bounded inner loop with no
|
|
922
|
+
* indirection back through the skin record.
|
|
923
|
+
*
|
|
924
|
+
* @param {{
|
|
925
|
+
* joints: Array<{ node: number, inverse_bind: Float32Array | number[] }>,
|
|
926
|
+
* }} skin
|
|
927
|
+
* @returns {number} skin id (index into the `animation_skins` table)
|
|
928
|
+
*/
|
|
929
|
+
add_skin(skin) {
|
|
930
|
+
assert.defined(skin, 'skin');
|
|
931
|
+
assert.isArray(skin.joints, 'skin.joints');
|
|
932
|
+
assert.greaterThanOrEqual(skin.joints.length, 1, 'skin must have at least one joint');
|
|
933
|
+
|
|
934
|
+
const joints = skin.joints;
|
|
935
|
+
const joint_count = joints.length;
|
|
936
|
+
|
|
937
|
+
// Reserve the matrix range. Each block bakes in its absolute
|
|
938
|
+
// slot offset (skin_base + chain_position * JOINTS_PER_SKIN_BLOCK)
|
|
939
|
+
// so the prep shader writes directly without dereferencing
|
|
940
|
+
// the skin row for the offset; the base is also stashed on
|
|
941
|
+
// the CPU map so the skinning-binding upload can look it up
|
|
942
|
+
// without reading the GPU back.
|
|
943
|
+
const skin_matrix_offset = this.#next_skin_matrix_offset;
|
|
944
|
+
this.#next_skin_matrix_offset += joint_count;
|
|
945
|
+
this.#ensure_skin_matrices_capacity(this.#next_skin_matrix_offset);
|
|
946
|
+
|
|
947
|
+
const skins_table = this.#database.get('animation_skins');
|
|
948
|
+
const blocks_table = this.#database.get('animation_skin_joint_blocks');
|
|
949
|
+
|
|
950
|
+
// Reserve the skin row up front. The head pointer is patched
|
|
951
|
+
// in once the chain exists. NULL placeholder — 0 is a valid
|
|
952
|
+
// block row id (the first allocation in an empty table).
|
|
953
|
+
const skin_id = skins_table.add({
|
|
954
|
+
joint_block_head: ANIMATION_SKIN_JOINT_BLOCK_NULL,
|
|
955
|
+
joint_count,
|
|
956
|
+
});
|
|
957
|
+
this.#skin_matrix_offsets.set(skin_id, skin_matrix_offset);
|
|
958
|
+
|
|
959
|
+
const head_block_id = add_linked_chain(
|
|
960
|
+
blocks_table,
|
|
961
|
+
joints,
|
|
962
|
+
JOINTS_PER_SKIN_BLOCK,
|
|
963
|
+
(start, count, next) => {
|
|
964
|
+
const inline_joints = new Array(JOINTS_PER_SKIN_BLOCK);
|
|
965
|
+
for (let j = 0; j < JOINTS_PER_SKIN_BLOCK; j++) {
|
|
966
|
+
if (j < count) {
|
|
967
|
+
const joint = joints[start + j];
|
|
968
|
+
|
|
969
|
+
assert.isNonNegativeInteger(joint.node, `skin.joints[${start + j}].node`);
|
|
970
|
+
assert.defined(joint.inverse_bind, `skin.joints[${start + j}].inverse_bind`);
|
|
971
|
+
|
|
972
|
+
inline_joints[j] = joint;
|
|
973
|
+
} else {
|
|
974
|
+
inline_joints[j] = ZERO_SKIN_JOINT;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return {
|
|
978
|
+
joints: inline_joints,
|
|
979
|
+
count,
|
|
980
|
+
next,
|
|
981
|
+
skin_matrix_offset: skin_matrix_offset + start,
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
);
|
|
985
|
+
|
|
986
|
+
// Patch the head pointer now that the chain exists. Re-`set`
|
|
987
|
+
// the whole record because the table API doesn't expose
|
|
988
|
+
// per-field updates.
|
|
989
|
+
skins_table.set(skin_id, {
|
|
990
|
+
joint_block_head: head_block_id,
|
|
991
|
+
joint_count,
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
return skin_id;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* High-level skin registration: consumes a {@link Skin} (CPU data
|
|
999
|
+
* with Node3D joint references and a flat inverse-bind matrix
|
|
1000
|
+
* array), allocates a GPU skin record, and binds every entry in
|
|
1001
|
+
* `skin.meshes` through the skinning context.
|
|
1002
|
+
*
|
|
1003
|
+
* **Eventual consistency.** The `skin_id` is allocated and
|
|
1004
|
+
* returned synchronously — callers can immediately pass it to
|
|
1005
|
+
* state mutators or {@link unregister_skin}. If any joint's
|
|
1006
|
+
* Node3D hasn't been added to a scene yet (no `id_mapping` row),
|
|
1007
|
+
* the joint-block chain that drives the deformation is queued
|
|
1008
|
+
* and built on the next {@link update} that sees all joints
|
|
1009
|
+
* resolved. The skin's table row uses a placeholder
|
|
1010
|
+
* `joint_block_head` until then — observationally indistinguishable
|
|
1011
|
+
* from "skin with no joints driving it" (no deformation runs).
|
|
1012
|
+
*
|
|
1013
|
+
* Mesh→skin bindings register immediately via
|
|
1014
|
+
* {@link GPUMeshSkinningContext#bind}; the skinning context
|
|
1015
|
+
* already tolerates pre-scene-build registration. Each mesh also
|
|
1016
|
+
* gets its {@link SkinnedMesh#skin} reference and a fresh set of
|
|
1017
|
+
* bounds off it, synchronously — that part does not wait for
|
|
1018
|
+
* `id_mapping`, because it reads the joints' `transform_global`
|
|
1019
|
+
* rather than any GPU row.
|
|
1020
|
+
*
|
|
1021
|
+
* @param {Skin} skin
|
|
1022
|
+
* @returns {number} skin id (index into the `animation_skins` table)
|
|
1023
|
+
*/
|
|
1024
|
+
register_skin(skin) {
|
|
1025
|
+
assert.defined(skin, 'skin');
|
|
1026
|
+
assert.equal(skin.isSkin, true, 'skin.isSkin !== true');
|
|
1027
|
+
assert.greaterThanOrEqual(skin.meshes.length, 1, 'skin.meshes must contain at least one mesh');
|
|
1028
|
+
|
|
1029
|
+
const joint_count = skin.joints.length;
|
|
1030
|
+
const inverse_bind_matrices = skin.inverse_bind_matrices;
|
|
1031
|
+
|
|
1032
|
+
// Reserve the matrix range up front — block records carry
|
|
1033
|
+
// their absolute slot offset, so the prep shader writes
|
|
1034
|
+
// directly. The base also lands on #skin_matrix_offsets so
|
|
1035
|
+
// skinning-binding upload can look it up.
|
|
1036
|
+
const skin_matrix_offset = this.#next_skin_matrix_offset;
|
|
1037
|
+
this.#next_skin_matrix_offset += joint_count;
|
|
1038
|
+
this.#ensure_skin_matrices_capacity(this.#next_skin_matrix_offset);
|
|
1039
|
+
|
|
1040
|
+
// Reserve the skin row immediately with a placeholder head
|
|
1041
|
+
// pointer. State mutators and the public id are usable from
|
|
1042
|
+
// this point on; the joint chain gets patched in once
|
|
1043
|
+
// id_mapping has every joint (possibly synchronously below,
|
|
1044
|
+
// possibly deferred via the pending queue).
|
|
1045
|
+
const skins_table = this.#database.get('animation_skins');
|
|
1046
|
+
const skin_id = skins_table.add({
|
|
1047
|
+
// NULL placeholder — 0 is a valid block row id
|
|
1048
|
+
joint_block_head: ANIMATION_SKIN_JOINT_BLOCK_NULL,
|
|
1049
|
+
joint_count,
|
|
1050
|
+
});
|
|
1051
|
+
this.#skin_matrix_offsets.set(skin_id, skin_matrix_offset);
|
|
1052
|
+
|
|
1053
|
+
// Bind every mesh into the skinning context. Idempotent and
|
|
1054
|
+
// pre-build tolerant — the binding upload defers until
|
|
1055
|
+
// id_mapping is ready.
|
|
1056
|
+
//
|
|
1057
|
+
// Each mesh also takes a reference to the CPU-side skin and
|
|
1058
|
+
// re-derives its bounds off it. From here on the skin's
|
|
1059
|
+
// formula is what places the mesh's vertices, and `Mesh`'s
|
|
1060
|
+
// composition — rest-pose geometry under `transform_global` —
|
|
1061
|
+
// is the wrong one, because the skinning pass cancels that
|
|
1062
|
+
// transform back out (see {@link SkinnedMesh#updateBoundsBasic}).
|
|
1063
|
+
// Nothing else would notice: bounds are refreshed by
|
|
1064
|
+
// `updateMatrices`, and a character does not move again just
|
|
1065
|
+
// because it finished loading.
|
|
1066
|
+
// Before any of that: put the meshes into the frame this skin actually deforms in. The
|
|
1067
|
+
// skinning pass writes each clone's vertices in `inverse(mesh.global)` space, so
|
|
1068
|
+
// `mesh.global` is that frame — and glTF says a skinned mesh's node transform is ignored,
|
|
1069
|
+
// which makes the frame the engine's to choose rather than the exporter's to get right.
|
|
1070
|
+
// Ahead of the bind loop because it moves the mesh, and the bounds published below have to
|
|
1071
|
+
// be the ones that survive. See `SKINNING_FRAME_PLAN.md`.
|
|
1072
|
+
this.#normalize_skin_frame(skin);
|
|
1073
|
+
|
|
1074
|
+
this.#skins_by_id.set(skin_id, skin);
|
|
1075
|
+
|
|
1076
|
+
for (const clip of this.#scaling_clips.values()) {
|
|
1077
|
+
this.#report_scale_conflicts(skin, clip);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const skinning = this.#scene_context.skinning;
|
|
1081
|
+
const meshes = skin.meshes;
|
|
1082
|
+
for (let i = 0; i < meshes.length; i++) {
|
|
1083
|
+
const mesh = meshes[i];
|
|
1084
|
+
|
|
1085
|
+
skinning.bind(mesh, skin_id);
|
|
1086
|
+
|
|
1087
|
+
mesh.skin = skin;
|
|
1088
|
+
mesh.updateBoundsBasic();
|
|
1089
|
+
|
|
1090
|
+
// The row the scene context published for this mesh holds the pre-skin bounds, and
|
|
1091
|
+
// nothing about binding a skin looks like movement — `updateBoundsBasic` is not
|
|
1092
|
+
// `updateMatrices` and does not touch the version the sync compares against. Without
|
|
1093
|
+
// this the corrected box sits on the CPU object and never reaches the table.
|
|
1094
|
+
mesh.needsUpdate = true;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
// Try to complete now. If id_mapping is ready for every
|
|
1098
|
+
// joint, the chain gets built and patched in. Otherwise the
|
|
1099
|
+
// skin lands on #pending_skins and the next update() drain
|
|
1100
|
+
// retries.
|
|
1101
|
+
const pending = {
|
|
1102
|
+
skin_id,
|
|
1103
|
+
skin,
|
|
1104
|
+
skin_matrix_offset,
|
|
1105
|
+
inverse_bind_matrices,
|
|
1106
|
+
};
|
|
1107
|
+
if (!this.#try_complete_skin(pending)) {
|
|
1108
|
+
this.#pending_skins.push(pending);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
return skin_id;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/**
|
|
1115
|
+
* Put a skin's meshes into the frame it deforms in, and say so when they cannot be.
|
|
1116
|
+
*
|
|
1117
|
+
* The correction itself is {@link skin_normalize_mesh_frame}, which is where the argument lives.
|
|
1118
|
+
* This is the reporting: an asset that renders wrong should say which asset and by how much, on
|
|
1119
|
+
* the frame it is registered, rather than reaching a person as a screenshot of soup.
|
|
1120
|
+
*
|
|
1121
|
+
* @param {Skin} skin
|
|
1122
|
+
*/
|
|
1123
|
+
#normalize_skin_frame(skin) {
|
|
1124
|
+
const report = skin_normalize_mesh_frame(skin);
|
|
1125
|
+
|
|
1126
|
+
// a glTF skin's `name` is optional and often absent; the mesh it deforms is what a person
|
|
1127
|
+
// would recognise, and is what the asset's own hierarchy calls it
|
|
1128
|
+
const label = skin.name !== '' ? skin.name : (skin.meshes[0]?.name ?? '<unnamed>');
|
|
1129
|
+
|
|
1130
|
+
if (report.unwalked.length > 0) {
|
|
1131
|
+
console.error(
|
|
1132
|
+
`skin '${label}': ${report.unwalked.length} of its nodes have never been walked — `
|
|
1133
|
+
+ `'${report.unwalked[0].name}' among them — so their world transforms are the `
|
|
1134
|
+
+ `identity by default rather than by derivation. Call updateMatrices on the scene `
|
|
1135
|
+
+ `before registering. Nothing was moved; the deformation will be wrong.`
|
|
1136
|
+
);
|
|
1137
|
+
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
if (report.frame_defect > 0.001) {
|
|
1142
|
+
console.error(
|
|
1143
|
+
`skin '${label}': no frame can deform it — `
|
|
1144
|
+
+ `inverse(frame) × joint.global × inverse_bind is ${report.frame_defect.toFixed(4)} `
|
|
1145
|
+
+ `away from rigid at its own bind pose, and a dual quaternion carries a rotation and `
|
|
1146
|
+
+ `a translation and nothing else. The rest pose has a non-uniform scale or a shear `
|
|
1147
|
+
+ `in it. Rendering will be wrong; see SKINNING_FRAME_PLAN.md §4.`
|
|
1148
|
+
);
|
|
1149
|
+
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
if (report.residual > 0.001) {
|
|
1154
|
+
console.error(
|
|
1155
|
+
`skin '${label}': its mesh frame did not land — ${report.residual.toFixed(6)} `
|
|
1156
|
+
+ `left over. A correction carrying shear does not survive a Transform64's TRS `
|
|
1157
|
+
+ `components. Rendering will be wrong; see SKINNING_FRAME_PLAN.md §3.`
|
|
1158
|
+
);
|
|
1159
|
+
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
for (const mesh of report.obstructed) {
|
|
1164
|
+
console.warn(
|
|
1165
|
+
`skin '${label}': mesh node '${mesh.name}' carries the skin's frame now, and its `
|
|
1166
|
+
+ `${mesh.children.length} child node(s) inherit it. Sockets belong on bones.`
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
if (report.corrected > 0) {
|
|
1171
|
+
// verbose rather than a warning: this is a legal asset shape, and a crowd of them would
|
|
1172
|
+
// otherwise be a crowd of log lines
|
|
1173
|
+
console.debug(
|
|
1174
|
+
`skin '${label}': ${report.corrected} mesh frame(s) moved onto the skin's bind `
|
|
1175
|
+
+ `transform, absorbing ${report.absorbed.toFixed(4)} of non-rigidity the skinning `
|
|
1176
|
+
+ `pass could not have carried.`
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Say so when a clip scales a skin's joints out from under the frame it is deformed in.
|
|
1183
|
+
*
|
|
1184
|
+
* The frame {@link skin_normalize_mesh_frame} chooses is fixed at registration, and it is sound
|
|
1185
|
+
* because the joints and the mesh share their scaling ancestors. A scale that reaches only some
|
|
1186
|
+
* of them breaks that every frame it plays, on the GPU, where nothing can see it —
|
|
1187
|
+
* {@link skin_clip_scale_conflicts} is that question asked off the clip's own curves instead.
|
|
1188
|
+
*
|
|
1189
|
+
* Nothing is refused: the clip is legal animation and the skin is a legal skin, and it is their
|
|
1190
|
+
* combination the skinning pass cannot carry. Refusing either would be picking one to blame.
|
|
1191
|
+
*
|
|
1192
|
+
* @param {Skin} skin
|
|
1193
|
+
* @param {ShadeAnimationClip} clip
|
|
1194
|
+
*/
|
|
1195
|
+
#report_scale_conflicts(skin, clip) {
|
|
1196
|
+
const conflicts = skin_clip_scale_conflicts(skin, clip);
|
|
1197
|
+
|
|
1198
|
+
if (conflicts.length === 0) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
const skin_label = skin.name !== '' ? skin.name : (skin.meshes[0]?.name ?? '<unnamed>');
|
|
1203
|
+
|
|
1204
|
+
const nodes = conflicts.map(conflict => conflict.node.name || '<unnamed>').join(', ');
|
|
1205
|
+
|
|
1206
|
+
const uniform = conflicts.every(conflict => conflict.uniform);
|
|
1207
|
+
|
|
1208
|
+
console.error(
|
|
1209
|
+
`clip '${clip.name}' scales ${conflicts.length} node(s) of skin '${skin_label}' — `
|
|
1210
|
+
+ `${nodes} — which reach its joints but not its mesh, so the scale enters the joint `
|
|
1211
|
+
+ `matrices and not the frame they are folded against. A dual quaternion cannot carry `
|
|
1212
|
+
+ `it and no choice of frame fixes it: the deformation will be wrong while this clip `
|
|
1213
|
+
+ `plays. `
|
|
1214
|
+
+ (uniform
|
|
1215
|
+
? `The scale is uniform, which SKINNING_FRAME_PLAN.md §4 has a design for.`
|
|
1216
|
+
: `The scale is non-uniform, which no dual quaternion holds — §4's linear-blend `
|
|
1217
|
+
+ `path or an import-time refusal.`)
|
|
1218
|
+
);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Attempt to build the joint-block chain for a pending skin and
|
|
1223
|
+
* patch its head pointer onto the skin row. Returns `true` when
|
|
1224
|
+
* every joint Node3D has resolved to a transforms-table row
|
|
1225
|
+
* (and the chain was built); `false` when at least one joint is
|
|
1226
|
+
* still missing.
|
|
1227
|
+
*
|
|
1228
|
+
* @param {{
|
|
1229
|
+
* skin_id: number,
|
|
1230
|
+
* skin: Skin,
|
|
1231
|
+
* skin_matrix_offset: number,
|
|
1232
|
+
* inverse_bind_matrices: Float32Array,
|
|
1233
|
+
* }} pending
|
|
1234
|
+
* @returns {boolean}
|
|
1235
|
+
*/
|
|
1236
|
+
#try_complete_skin(pending) {
|
|
1237
|
+
const id_mapping = this.#scene_context.id_mapping;
|
|
1238
|
+
const joint_nodes = pending.skin.joints;
|
|
1239
|
+
const joint_count = joint_nodes.length;
|
|
1240
|
+
const inverse_bind_matrices = pending.inverse_bind_matrices;
|
|
1241
|
+
const skin_matrix_offset = pending.skin_matrix_offset;
|
|
1242
|
+
const skin_id = pending.skin_id;
|
|
1243
|
+
|
|
1244
|
+
// All-or-nothing: a single missing row leaves the chain
|
|
1245
|
+
// unbuilt — partial chains aren't valid (the prep shader
|
|
1246
|
+
// walks every block).
|
|
1247
|
+
const joints = new Array(joint_count);
|
|
1248
|
+
for (let i = 0; i < joint_count; i++) {
|
|
1249
|
+
const node = joint_nodes[i];
|
|
1250
|
+
const row = id_mapping.get(node.id);
|
|
1251
|
+
if (row === undefined) return false;
|
|
1252
|
+
|
|
1253
|
+
joints[i] = {
|
|
1254
|
+
node: row,
|
|
1255
|
+
// Per-joint slice of the flat matrix array. The
|
|
1256
|
+
// marshaller copies these bytes into the skin-joint
|
|
1257
|
+
// block record; sub-array views are fine — they
|
|
1258
|
+
// share the underlying buffer but write_struct_value
|
|
1259
|
+
// reads by length, not by offset.
|
|
1260
|
+
inverse_bind: inverse_bind_matrices.subarray(i * 16, (i + 1) * 16),
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const blocks_table = this.#database.get('animation_skin_joint_blocks');
|
|
1265
|
+
const head_block_id = add_linked_chain(
|
|
1266
|
+
blocks_table,
|
|
1267
|
+
joints,
|
|
1268
|
+
JOINTS_PER_SKIN_BLOCK,
|
|
1269
|
+
(start, count, next) => {
|
|
1270
|
+
const inline_joints = new Array(JOINTS_PER_SKIN_BLOCK);
|
|
1271
|
+
for (let j = 0; j < JOINTS_PER_SKIN_BLOCK; j++) {
|
|
1272
|
+
inline_joints[j] = j < count ? joints[start + j] : ZERO_SKIN_JOINT;
|
|
1273
|
+
}
|
|
1274
|
+
return {
|
|
1275
|
+
joints: inline_joints,
|
|
1276
|
+
count,
|
|
1277
|
+
next,
|
|
1278
|
+
skin_matrix_offset: skin_matrix_offset + start,
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
);
|
|
1282
|
+
|
|
1283
|
+
// Patch the head pointer onto the already-allocated skin
|
|
1284
|
+
// row. Read-modify-write so any other fields the user might
|
|
1285
|
+
// have changed via mutators (none today, but future-proof)
|
|
1286
|
+
// are preserved.
|
|
1287
|
+
const skins_table = this.#database.get('animation_skins');
|
|
1288
|
+
const current = skins_table.get(skin_id);
|
|
1289
|
+
skins_table.set(skin_id, {
|
|
1290
|
+
joint_block_head: head_block_id,
|
|
1291
|
+
joint_count: current.joint_count,
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
return true;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/**
|
|
1298
|
+
* High-level clip registration: consumes a {@link ShadeAnimationClip}
|
|
1299
|
+
* (CPU data with Node3D targets and per-component curves), uploads
|
|
1300
|
+
* curves and tracks, and creates the GPU clip record.
|
|
1301
|
+
*
|
|
1302
|
+
* **Eventual consistency.** The `clip_id` is allocated and
|
|
1303
|
+
* returned synchronously — callers can immediately call
|
|
1304
|
+
* {@link start} / {@link stop} / {@link set_time} /
|
|
1305
|
+
* {@link set_playback_rate} / {@link set_flags} / {@link clear_flags}
|
|
1306
|
+
* / {@link set_playback_weight} / {@link unregister_clip}. If
|
|
1307
|
+
* any channel target's Node3D hasn't been added to a scene yet
|
|
1308
|
+
* (no `id_mapping` row), the bindings chain that drives the
|
|
1309
|
+
* apply pass is queued and built on the next {@link update}
|
|
1310
|
+
* that sees all targets resolved. The clip's table row uses a
|
|
1311
|
+
* placeholder `bound_track_group_head` until then — apply
|
|
1312
|
+
* produces no contributions, so the clip is observationally
|
|
1313
|
+
* inert (still subject to time advancement via the tick shader
|
|
1314
|
+
* if `Playing` is set).
|
|
1315
|
+
*
|
|
1316
|
+
* Curves and tracks are interned synchronously since they're
|
|
1317
|
+
* pure data — no `id_mapping` dependency.
|
|
1318
|
+
*
|
|
1319
|
+
* @param {ShadeAnimationClip} clip
|
|
1320
|
+
* @returns {number} clip id
|
|
1321
|
+
*/
|
|
1322
|
+
register_clip(clip) {
|
|
1323
|
+
assert.defined(clip, 'clip');
|
|
1324
|
+
assert.equal(clip.isShadeAnimationClip, true, 'clip.isShadeAnimationClip !== true');
|
|
1325
|
+
|
|
1326
|
+
const channels = clip.channels;
|
|
1327
|
+
|
|
1328
|
+
// Intern every channel's curves + track now. None of this
|
|
1329
|
+
// depends on id_mapping — pure data uploads.
|
|
1330
|
+
//
|
|
1331
|
+
// Each curve goes through #intern_curve so two channels
|
|
1332
|
+
// referencing the same AnimationCurve instance share one
|
|
1333
|
+
// GPU upload. With 324 dancers retargeted at the same base
|
|
1334
|
+
// clip this turns 324 × 195 channel uploads into 1 (the
|
|
1335
|
+
// curves are read-only animation data — identical bytes
|
|
1336
|
+
// wherever they're referenced).
|
|
1337
|
+
const pending_channels = new Array(channels.length);
|
|
1338
|
+
for (let i = 0; i < channels.length; i++) {
|
|
1339
|
+
const channel = channels[i];
|
|
1340
|
+
const curves = channel.curves;
|
|
1341
|
+
const track_channels = {};
|
|
1342
|
+
if (curves.x !== undefined) track_channels.x = this.#intern_curve(curves.x);
|
|
1343
|
+
if (curves.y !== undefined) track_channels.y = this.#intern_curve(curves.y);
|
|
1344
|
+
if (curves.z !== undefined) track_channels.z = this.#intern_curve(curves.z);
|
|
1345
|
+
if (curves.w !== undefined) track_channels.w = this.#intern_curve(curves.w);
|
|
1346
|
+
|
|
1347
|
+
pending_channels[i] = {
|
|
1348
|
+
track: this.#intern_track(track_channels),
|
|
1349
|
+
target: channel.target,
|
|
1350
|
+
property: channel.property,
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// Reserve the clip row immediately with a placeholder head
|
|
1355
|
+
// pointer. State mutators and the public id are usable from
|
|
1356
|
+
// this point on; the bindings chain gets patched in once
|
|
1357
|
+
// id_mapping has every target. `time` defaults to 0 (the
|
|
1358
|
+
// playback offset relative to `time_start`; the apply
|
|
1359
|
+
// shader does `effective_time = clip.time + clip.time_start`).
|
|
1360
|
+
const clips_table = this.#database.get('animation_clips');
|
|
1361
|
+
const clip_id = clips_table.add({
|
|
1362
|
+
time: 0,
|
|
1363
|
+
time_start: clip.start_time,
|
|
1364
|
+
time_end: clip.end_time,
|
|
1365
|
+
bound_track_group_head: ANIMATION_BOUND_TRACK_GROUP_NULL,
|
|
1366
|
+
playback_rate: 1,
|
|
1367
|
+
flags: 0,
|
|
1368
|
+
playback_weight: 1,
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
const pending = { clip_id, channels: pending_channels };
|
|
1372
|
+
if (!this.#try_complete_clip(pending)) {
|
|
1373
|
+
this.#pending_clips.push(pending);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/*
|
|
1377
|
+
Asked cheaply first: a clip with no scale channel at all — which is every clip a character
|
|
1378
|
+
normally carries — is dismissed in one pass over its channels and remembered by nothing. Only
|
|
1379
|
+
a clip that scales something is worth holding against the skins, now and as more arrive.
|
|
1380
|
+
*/
|
|
1381
|
+
if (clip_scale_channels(clip).length > 0) {
|
|
1382
|
+
this.#scaling_clips.set(clip_id, clip);
|
|
1383
|
+
|
|
1384
|
+
for (const skin of this.#skins_by_id.values()) {
|
|
1385
|
+
this.#report_scale_conflicts(skin, clip);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
return clip_id;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Attempt to build the bindings chain for a pending clip and
|
|
1394
|
+
* patch its head pointer onto the clip row. Returns `true` when
|
|
1395
|
+
* every channel target has resolved to a transforms-table row
|
|
1396
|
+
* (and the chain was built); `false` when at least one is still
|
|
1397
|
+
* missing.
|
|
1398
|
+
*
|
|
1399
|
+
* @param {{
|
|
1400
|
+
* clip_id: number,
|
|
1401
|
+
* channels: Array<{ track: number, target: Node3D, property: number }>,
|
|
1402
|
+
* }} pending
|
|
1403
|
+
* @returns {boolean}
|
|
1404
|
+
*/
|
|
1405
|
+
#try_complete_clip(pending) {
|
|
1406
|
+
const id_mapping = this.#scene_context.id_mapping;
|
|
1407
|
+
const channels = pending.channels;
|
|
1408
|
+
const clip_id = pending.clip_id;
|
|
1409
|
+
|
|
1410
|
+
const bindings = new Array(channels.length);
|
|
1411
|
+
for (let i = 0; i < channels.length; i++) {
|
|
1412
|
+
const ch = channels[i];
|
|
1413
|
+
const instance = id_mapping.get(ch.target.id);
|
|
1414
|
+
if (instance === undefined) return false;
|
|
1415
|
+
|
|
1416
|
+
bindings[i] = {
|
|
1417
|
+
track: ch.track,
|
|
1418
|
+
instance,
|
|
1419
|
+
property: ch.property,
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
const groups_table = this.#database.get('animation_bound_track_groups');
|
|
1424
|
+
const head_group_id = add_linked_chain(
|
|
1425
|
+
groups_table,
|
|
1426
|
+
bindings,
|
|
1427
|
+
TRACKS_PER_GROUP_NODE,
|
|
1428
|
+
(start, count, next) => {
|
|
1429
|
+
const inline_bindings = new Array(TRACKS_PER_GROUP_NODE);
|
|
1430
|
+
for (let j = 0; j < TRACKS_PER_GROUP_NODE; j++) {
|
|
1431
|
+
inline_bindings[j] = j < count ? bindings[start + j] : ZERO_BINDING;
|
|
1432
|
+
}
|
|
1433
|
+
return { bindings: inline_bindings, count, next, clip: clip_id };
|
|
1434
|
+
}
|
|
1435
|
+
);
|
|
1436
|
+
|
|
1437
|
+
// Patch the head pointer onto the already-allocated clip
|
|
1438
|
+
// row. Read-modify-write preserves any user-driven state
|
|
1439
|
+
// changes (set_time, set_flags, etc.) made between
|
|
1440
|
+
// register_clip and the drain.
|
|
1441
|
+
this.#patch_clip_field(clip_id, 'bound_track_group_head', head_group_id);
|
|
1442
|
+
|
|
1443
|
+
return true;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
/**
|
|
1447
|
+
* Drop a clip from the manager. Walks the bindings chain and
|
|
1448
|
+
* removes every group-node + the clip row. Tolerates the clip
|
|
1449
|
+
* still being pending (drains it from the queue without GPU
|
|
1450
|
+
* touches besides the original row removal).
|
|
1451
|
+
*
|
|
1452
|
+
* Curves and tracks the clip referenced stay alive — they're
|
|
1453
|
+
* shared via {@link #intern_curve} / {@link #intern_track} and
|
|
1454
|
+
* may be in use by other clips. Removing them would need
|
|
1455
|
+
* reference-counting the manager doesn't carry.
|
|
1456
|
+
*
|
|
1457
|
+
* Safe to call repeatedly on the same id (subsequent calls are
|
|
1458
|
+
* no-ops once the row is gone).
|
|
1459
|
+
*
|
|
1460
|
+
* @param {number} clip_id
|
|
1461
|
+
*/
|
|
1462
|
+
unregister_clip(clip_id) {
|
|
1463
|
+
assert.isNonNegativeInteger(clip_id, 'clip_id');
|
|
1464
|
+
|
|
1465
|
+
// Drop from pending queue if present (skip-and-keep-others
|
|
1466
|
+
// pattern is cheaper than splice for the rare case of
|
|
1467
|
+
// dozens-of-pending; if pending depth grows this can be
|
|
1468
|
+
// revisited).
|
|
1469
|
+
for (let i = this.#pending_clips.length - 1; i >= 0; i--) {
|
|
1470
|
+
if (this.#pending_clips[i].clip_id === clip_id) {
|
|
1471
|
+
this.#pending_clips.splice(i, 1);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
const clips_table = this.#database.get('animation_clips');
|
|
1476
|
+
const groups_table = this.#database.get('animation_bound_track_groups');
|
|
1477
|
+
|
|
1478
|
+
const clip_record = clips_table.get(clip_id);
|
|
1479
|
+
if (clip_record === undefined) return;
|
|
1480
|
+
|
|
1481
|
+
// Walk the bindings chain and remove every node. The chain
|
|
1482
|
+
// may be empty (placeholder head NULL) if the clip is still
|
|
1483
|
+
// pending or has been registered then drained but never
|
|
1484
|
+
// completed; both cases skip the loop.
|
|
1485
|
+
let block_id = clip_record.bound_track_group_head;
|
|
1486
|
+
while (block_id !== ANIMATION_BOUND_TRACK_GROUP_NULL) {
|
|
1487
|
+
const block = groups_table.get(block_id);
|
|
1488
|
+
const next_id = block !== undefined ? block.next : ANIMATION_BOUND_TRACK_GROUP_NULL;
|
|
1489
|
+
groups_table.remove(block_id);
|
|
1490
|
+
block_id = next_id;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
clips_table.remove(clip_id);
|
|
1494
|
+
|
|
1495
|
+
this.#scaling_clips.delete(clip_id);
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
/**
|
|
1499
|
+
* Drop a skin from the manager. Walks the joint-block chain and
|
|
1500
|
+
* removes every block + the skin row, and tears down every
|
|
1501
|
+
* skinning binding pointing at this skin (so the skinning
|
|
1502
|
+
* context doesn't try to read the now-freed skin's matrix
|
|
1503
|
+
* offset on its next upload).
|
|
1504
|
+
*
|
|
1505
|
+
* The skin's reserved matrix range stays allocated — compaction
|
|
1506
|
+
* isn't supported in the MVP. Re-registering after an
|
|
1507
|
+
* `unregister_skin` therefore costs new matrix slots; long-
|
|
1508
|
+
* running spawn/despawn loops accumulate wasted slots.
|
|
1509
|
+
*
|
|
1510
|
+
* Tolerates the skin still being pending. Safe to call
|
|
1511
|
+
* repeatedly on the same id.
|
|
1512
|
+
*
|
|
1513
|
+
* @param {number} skin_id
|
|
1514
|
+
*/
|
|
1515
|
+
unregister_skin(skin_id) {
|
|
1516
|
+
assert.isNonNegativeInteger(skin_id, 'skin_id');
|
|
1517
|
+
|
|
1518
|
+
this.#skins_by_id.delete(skin_id);
|
|
1519
|
+
|
|
1520
|
+
for (let i = this.#pending_skins.length - 1; i >= 0; i--) {
|
|
1521
|
+
if (this.#pending_skins[i].skin_id === skin_id) {
|
|
1522
|
+
this.#pending_skins.splice(i, 1);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// Tear down skinning bindings first so the skinning
|
|
1527
|
+
// context's next upload doesn't reference a freed skin row
|
|
1528
|
+
// (its upload path looks up skin_matrix_offset via
|
|
1529
|
+
// get_skin_matrix_offset, which would assert post-removal).
|
|
1530
|
+
this.#scene_context.skinning.unbind_all_by_skin(skin_id);
|
|
1531
|
+
|
|
1532
|
+
const skins_table = this.#database.get('animation_skins');
|
|
1533
|
+
const blocks_table = this.#database.get('animation_skin_joint_blocks');
|
|
1534
|
+
|
|
1535
|
+
const skin_record = skins_table.get(skin_id);
|
|
1536
|
+
if (skin_record === undefined) {
|
|
1537
|
+
this.#skin_matrix_offsets.delete(skin_id);
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// Walk the joint-block chain, terminating on the NULL
|
|
1542
|
+
// sentinel (also the placeholder for a not-yet-patched head).
|
|
1543
|
+
// Note: 0 is a VALID block row id — the first single-block
|
|
1544
|
+
// skin registered into an empty table gets head 0, and
|
|
1545
|
+
// treating it as a placeholder would leak its block, leaving
|
|
1546
|
+
// the prep shader processing it against a recycled
|
|
1547
|
+
// transforms-table row every frame.
|
|
1548
|
+
let block_id = skin_record.joint_block_head;
|
|
1549
|
+
while (block_id !== ANIMATION_SKIN_JOINT_BLOCK_NULL) {
|
|
1550
|
+
const block = blocks_table.get(block_id);
|
|
1551
|
+
const next_id = block !== undefined ? block.next : ANIMATION_SKIN_JOINT_BLOCK_NULL;
|
|
1552
|
+
blocks_table.remove(block_id);
|
|
1553
|
+
block_id = next_id;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
skins_table.remove(skin_id);
|
|
1557
|
+
this.#skin_matrix_offsets.delete(skin_id);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/**
|
|
1561
|
+
* Cached wrapper around {@link add_curve}: one upload per distinct curve, where distinct means
|
|
1562
|
+
* distinct *content*.
|
|
1563
|
+
*
|
|
1564
|
+
* The instance cache answers first — the common case inside one clip, and free. Otherwise the
|
|
1565
|
+
* curve's keys are hashed and held against every uploaded curve with that hash; a match on
|
|
1566
|
+
* every key, tangents included, reuses that upload, and only a curve nobody has uploaded before
|
|
1567
|
+
* goes through the low-level path. Either way the instance is remembered, so the next look-up
|
|
1568
|
+
* of it is the free one.
|
|
1569
|
+
*
|
|
1570
|
+
* @param {AnimationCurve} curve
|
|
1571
|
+
* @returns {number} curve id (index into the `animation_curves` table)
|
|
1572
|
+
*/
|
|
1573
|
+
#intern_curve(curve) {
|
|
1574
|
+
const cached = this.#curve_id_cache.get(curve);
|
|
1575
|
+
|
|
1576
|
+
if (cached !== undefined) {
|
|
1577
|
+
return cached;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
const hash = curve.hash();
|
|
1581
|
+
|
|
1582
|
+
let bucket = this.#curve_id_by_content.get(hash);
|
|
1583
|
+
|
|
1584
|
+
if (bucket === undefined) {
|
|
1585
|
+
bucket = [];
|
|
1586
|
+
|
|
1587
|
+
this.#curve_id_by_content.set(hash, bucket);
|
|
1588
|
+
} else {
|
|
1589
|
+
for (const entry of bucket) {
|
|
1590
|
+
if (entry.curve.equals(curve)) {
|
|
1591
|
+
this.#curve_id_cache.set(curve, entry.id);
|
|
1592
|
+
|
|
1593
|
+
return entry.id;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
const id = this.add_curve(curve);
|
|
1599
|
+
|
|
1600
|
+
this.#curve_id_cache.set(curve, id);
|
|
1601
|
+
|
|
1602
|
+
bucket.push({ curve, id });
|
|
1603
|
+
|
|
1604
|
+
return id;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Cache-keyed wrapper around {@link add_track}. Two channels that
|
|
1609
|
+
* end up with the same (x, y, z, w, mask) — typical when their
|
|
1610
|
+
* source curves are shared via {@link #intern_curve} — collapse
|
|
1611
|
+
* to one track row instead of one row per channel.
|
|
1612
|
+
*
|
|
1613
|
+
* @param {{ x?: number, y?: number, z?: number, w?: number }} channels
|
|
1614
|
+
* @returns {number} track id
|
|
1615
|
+
*/
|
|
1616
|
+
#intern_track(channels) {
|
|
1617
|
+
// Pack into a deterministic string key. -1 sentinel for
|
|
1618
|
+
// missing channels keeps the (x=undefined) and (x=0) cases
|
|
1619
|
+
// distinct.
|
|
1620
|
+
const cx = channels.x ?? -1;
|
|
1621
|
+
const cy = channels.y ?? -1;
|
|
1622
|
+
const cz = channels.z ?? -1;
|
|
1623
|
+
const cw = channels.w ?? -1;
|
|
1624
|
+
const key = `${cx},${cy},${cz},${cw}`;
|
|
1625
|
+
|
|
1626
|
+
const cached = this.#track_id_cache.get(key);
|
|
1627
|
+
if (cached !== undefined) {
|
|
1628
|
+
return cached;
|
|
1629
|
+
}
|
|
1630
|
+
const id = this.add_track(channels);
|
|
1631
|
+
this.#track_id_cache.set(key, id);
|
|
1632
|
+
return id;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Grow the skinning-matrix scratch buffer if `required_count`
|
|
1637
|
+
* exceeds current capacity. Doubles on grow until the requirement
|
|
1638
|
+
* fits. The buffer's contents are scratch (rewritten every frame by
|
|
1639
|
+
* the prep pass), so growth doesn't need to copy old data — but it
|
|
1640
|
+
* does invalidate the previous {@link #skin_matrices_buffer}
|
|
1641
|
+
* reference, which is why callers re-fetch through the getter.
|
|
1642
|
+
*
|
|
1643
|
+
* @param {number} required_count number of matrices that must fit
|
|
1644
|
+
*/
|
|
1645
|
+
#ensure_skin_matrices_capacity(required_count) {
|
|
1646
|
+
if (required_count <= this.#skin_matrices_capacity) {
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
let new_capacity = Math.max(this.#skin_matrices_capacity, SKIN_MATRICES_INITIAL_CAPACITY);
|
|
1651
|
+
while (new_capacity < required_count) {
|
|
1652
|
+
new_capacity *= 2;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// Grow both ping-pong buffers in lockstep — they always share
|
|
1656
|
+
// capacity. After grow both are zero-initialised, so the next
|
|
1657
|
+
// prep dispatch needs to seed "previous" from "current"
|
|
1658
|
+
// (otherwise velocity would interpolate against zero
|
|
1659
|
+
// matrices). The flag below tells dispatch_skin_matrix_prep
|
|
1660
|
+
// to issue that copy.
|
|
1661
|
+
for (let i = 0; i < 2; i++) {
|
|
1662
|
+
if (this.#skin_matrices_buffers[i] !== null) {
|
|
1663
|
+
this.#skin_matrices_buffers[i].destroy();
|
|
1664
|
+
}
|
|
1665
|
+
this.#skin_matrices_buffers[i] = this.#device.createBuffer({
|
|
1666
|
+
label: `${this.#label}/SkinMatrices/${i}`,
|
|
1667
|
+
size: new_capacity * SKIN_MATRIX_BYTES,
|
|
1668
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
this.#skin_matrices_capacity = new_capacity;
|
|
1672
|
+
this.#first_frame_skin_matrices = true;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
* Flush all pending uploads (curves, keyframe blocks, tracks, clips,
|
|
1677
|
+
* bound-track groups, skins, skin joint blocks) into the GPU
|
|
1678
|
+
* database. Call once per frame, before any shader that reads from
|
|
1679
|
+
* `database.buffer`.
|
|
1680
|
+
*
|
|
1681
|
+
* Also drains the pending-registration queues: skins and clips
|
|
1682
|
+
* whose dependencies (joint Node3D rows, channel-target rows)
|
|
1683
|
+
* weren't ready at register time get one shot per `update` to
|
|
1684
|
+
* complete. Once `id_mapping` has the missing rows, the
|
|
1685
|
+
* deferred chain build runs and the registration becomes
|
|
1686
|
+
* observationally complete — the next-frame `database.update`
|
|
1687
|
+
* picks up the patched head pointer.
|
|
1688
|
+
*
|
|
1689
|
+
* Does not touch the skin-matrices ping-pong buffers — those
|
|
1690
|
+
* are scratch populated each frame by
|
|
1691
|
+
* {@link dispatch_skin_matrix_prep}, not host data.
|
|
1692
|
+
*
|
|
1693
|
+
* @param {ShadeGPUCommandContext} cmd_ctx
|
|
1694
|
+
*/
|
|
1695
|
+
update(cmd_ctx) {
|
|
1696
|
+
this.#drain_pending_skins();
|
|
1697
|
+
this.#drain_pending_clips();
|
|
1698
|
+
this.#database.update(cmd_ctx);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
#drain_pending_skins() {
|
|
1702
|
+
// Walk back-to-front so successful completions can splice
|
|
1703
|
+
// without disturbing the iteration's remaining indices.
|
|
1704
|
+
for (let i = this.#pending_skins.length - 1; i >= 0; i--) {
|
|
1705
|
+
if (this.#try_complete_skin(this.#pending_skins[i])) {
|
|
1706
|
+
this.#pending_skins.splice(i, 1);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
#drain_pending_clips() {
|
|
1712
|
+
for (let i = this.#pending_clips.length - 1; i >= 0; i--) {
|
|
1713
|
+
if (this.#try_complete_clip(this.#pending_clips[i])) {
|
|
1714
|
+
this.#pending_clips.splice(i, 1);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
/**
|
|
1720
|
+
* Run the per-frame skin-matrix-prep dispatch and advance the
|
|
1721
|
+
* ping-pong. Replaces the manual `shader_skin_matrix_prep.dispatch`
|
|
1722
|
+
* the prototypes used to call — wrapping it here is how we get
|
|
1723
|
+
* correct ping-pong behaviour across frames without leaking the
|
|
1724
|
+
* buffer-role bookkeeping into every caller.
|
|
1725
|
+
*
|
|
1726
|
+
* No-op when no skins are registered (`group_count_x === 0`).
|
|
1727
|
+
*
|
|
1728
|
+
* Per-frame ordering:
|
|
1729
|
+
* 1. Flip {@link #skin_matrices_current_index} — the buffer that
|
|
1730
|
+
* was last frame's "current" is about to be overwritten with
|
|
1731
|
+
* this frame's matrices; the other buffer (last frame's prev)
|
|
1732
|
+
* becomes this frame's "previous" implicit data source for
|
|
1733
|
+
* {@link prev_skin_matrices_buffer}.
|
|
1734
|
+
* 2. Wait — clarify: we want last frame's "current" to BECOME
|
|
1735
|
+
* this frame's "previous". So flipping current_index moves
|
|
1736
|
+
* the role tag the correct way: what was current[i] becomes
|
|
1737
|
+
* previous (= buffers[1 - i]), and current[1 - i] is the
|
|
1738
|
+
* write target.
|
|
1739
|
+
* 3. Dispatch the prep shader into the new current.
|
|
1740
|
+
* 4. On the very first frame (or after a grow), copy current →
|
|
1741
|
+
* previous so the first velocity reads see matching matrices
|
|
1742
|
+
* and produce zero velocity.
|
|
1743
|
+
*
|
|
1744
|
+
* @param {ShadeGPUCommandContext} cmd_ctx
|
|
1745
|
+
*/
|
|
1746
|
+
dispatch_skin_matrix_prep(cmd_ctx) {
|
|
1747
|
+
const groups = this.#database
|
|
1748
|
+
.get('animation_skin_joint_blocks')
|
|
1749
|
+
.dispatch_group_count(SKIN_MATRIX_PREP_WORKGROUP_SIZE);
|
|
1750
|
+
if (groups === 0) {
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// Flip the ping-pong: what was "current" last frame is no
|
|
1755
|
+
// longer current, but it still holds valid matrices — and
|
|
1756
|
+
// through the role flip it becomes this frame's
|
|
1757
|
+
// `prev_skin_matrices_buffer`. The buffer we're flipping TO
|
|
1758
|
+
// (the new "current") held two-frames-old matrices, about to
|
|
1759
|
+
// be overwritten.
|
|
1760
|
+
this.#skin_matrices_current_index = 1 - this.#skin_matrices_current_index;
|
|
1761
|
+
|
|
1762
|
+
const current = this.#skin_matrices_buffers[this.#skin_matrices_current_index];
|
|
1763
|
+
const previous = this.#skin_matrices_buffers[1 - this.#skin_matrices_current_index];
|
|
1764
|
+
|
|
1765
|
+
shader_skin_matrix_prep.dispatch({
|
|
1766
|
+
encoder: cmd_ctx,
|
|
1767
|
+
group_count_x: groups,
|
|
1768
|
+
bindings: {
|
|
1769
|
+
animation_database: this.#database.buffer,
|
|
1770
|
+
scene_database: this.#scene_context.scene_database_buffer,
|
|
1771
|
+
skin_matrices: current,
|
|
1772
|
+
},
|
|
1773
|
+
});
|
|
1774
|
+
|
|
1775
|
+
// First-frame init (or post-grow): "previous" buffer is
|
|
1776
|
+
// zero-initialised, which would have the velocity pass
|
|
1777
|
+
// interpolate against the origin and produce huge nonsense
|
|
1778
|
+
// on the first frame the skin appears. Seed prev from
|
|
1779
|
+
// current — first velocity reads then yield zero, which is
|
|
1780
|
+
// the right answer (no motion has happened yet).
|
|
1781
|
+
if (this.#first_frame_skin_matrices) {
|
|
1782
|
+
cmd_ctx.copyBufferToBuffer(
|
|
1783
|
+
current, 0,
|
|
1784
|
+
previous, 0,
|
|
1785
|
+
current.size,
|
|
1786
|
+
);
|
|
1787
|
+
this.#first_frame_skin_matrices = false;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
/**
|
|
1792
|
+
* Per-frame orchestrator: drains pending registrations and the
|
|
1793
|
+
* database queue, runs the GPU tick (advances `clip.time`),
|
|
1794
|
+
* applies tracks into the pose accumulator, resolves the
|
|
1795
|
+
* accumulator into node TRS, propagates the transform
|
|
1796
|
+
* hierarchy, preps skinning matrices, and runs the skinning
|
|
1797
|
+
* compute pass that deforms cloned vertex regions in place.
|
|
1798
|
+
*
|
|
1799
|
+
* One call replaces the ~80-line per-frame dispatch block every
|
|
1800
|
+
* consumer would otherwise duplicate; the shader identities,
|
|
1801
|
+
* workgroup sizes, pose-accumulator sizing, and pass ordering
|
|
1802
|
+
* are all internal.
|
|
1803
|
+
*
|
|
1804
|
+
* `dt_seconds` is wall-clock seconds since the last call (the
|
|
1805
|
+
* caller measures via `performance.now()` or equivalent). It's
|
|
1806
|
+
* clamped to {@link MAX_DT_SECONDS} to keep a stall from
|
|
1807
|
+
* leaking multiple seconds into the next tick.
|
|
1808
|
+
*
|
|
1809
|
+
* Early-outs: the clip passes (tick/apply/resolve/hierarchy)
|
|
1810
|
+
* gate on the `animation_bound_track_groups` table being
|
|
1811
|
+
* non-empty; skin matrix prep + skinning gate on registered
|
|
1812
|
+
* skins instead — a skin whose joints are host-driven (no
|
|
1813
|
+
* clips bound) still gets fresh skinning matrices every frame.
|
|
1814
|
+
* With nothing registered no GPU work is encoded beyond the
|
|
1815
|
+
* database flush — safe to call every frame regardless of
|
|
1816
|
+
* registration state.
|
|
1817
|
+
*
|
|
1818
|
+
* @param {ShadeGPUCommandContext} cmd_ctx
|
|
1819
|
+
* @param {number} dt_seconds wall-clock seconds since last call
|
|
1820
|
+
*/
|
|
1821
|
+
tick(cmd_ctx, dt_seconds) {
|
|
1822
|
+
assert.defined(cmd_ctx, 'cmd_ctx');
|
|
1823
|
+
assert.isNumber(dt_seconds, 'dt_seconds');
|
|
1824
|
+
|
|
1825
|
+
// Cap dt so a long stall doesn't fly the clip through dozens
|
|
1826
|
+
// of loops or clamp it past the meaningful range.
|
|
1827
|
+
const dt = Math.min(dt_seconds, MAX_DT_SECONDS);
|
|
1828
|
+
|
|
1829
|
+
// Flush database + drain pending registrations.
|
|
1830
|
+
this.update(cmd_ctx);
|
|
1831
|
+
|
|
1832
|
+
// Clip-pass gate: no bound tracks → apply has nothing to
|
|
1833
|
+
// do, and resolve + hierarchy propagation cascade from
|
|
1834
|
+
// apply. Skipping them keeps the per-frame cost at "one
|
|
1835
|
+
// database update" when the scene has no clip animation.
|
|
1836
|
+
const apply_groups = this.#database
|
|
1837
|
+
.get('animation_bound_track_groups')
|
|
1838
|
+
.dispatch_group_count(ANIMATION_APPLY_WORKGROUP_SIZE);
|
|
1839
|
+
|
|
1840
|
+
if (apply_groups > 0) {
|
|
1841
|
+
this.#encode_clip_passes(cmd_ctx, dt, apply_groups);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// Skin matrix prep + skinning deformation. Both no-op when
|
|
1845
|
+
// no skins are registered — and both run independent of the
|
|
1846
|
+
// bound-track gate above: a registered skin whose joints
|
|
1847
|
+
// are host-driven (no clips bound) must still be deformed
|
|
1848
|
+
// each frame, otherwise it renders bind pose forever.
|
|
1849
|
+
this.dispatch_skin_matrix_prep(cmd_ctx);
|
|
1850
|
+
this.#scene_context.skinning.update(cmd_ctx);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
/**
|
|
1854
|
+
* Encode the clip-driven passes: GPU tick (advances
|
|
1855
|
+
* `clip.time`), track apply into the pose accumulator, pose
|
|
1856
|
+
* resolve into node TRS, and transform-hierarchy propagation.
|
|
1857
|
+
* Split out of {@link tick} so the skin passes there run
|
|
1858
|
+
* independently of the bound-track early-out.
|
|
1859
|
+
*
|
|
1860
|
+
* @param {ShadeGPUCommandContext} cmd_ctx
|
|
1861
|
+
* @param {number} dt clamped delta time, seconds
|
|
1862
|
+
* @param {number} apply_groups dispatch group count for the
|
|
1863
|
+
* apply pass — caller guarantees `> 0`
|
|
1864
|
+
*/
|
|
1865
|
+
#encode_clip_passes(cmd_ctx, dt, apply_groups) {
|
|
1866
|
+
// Tick: advance clip.time on the GPU.
|
|
1867
|
+
const tick_groups = this.#database
|
|
1868
|
+
.get('animation_clips')
|
|
1869
|
+
.dispatch_group_count(ANIMATION_TICK_WORKGROUP_SIZE);
|
|
1870
|
+
if (tick_groups > 0) {
|
|
1871
|
+
shader_animation_tick.dispatch({
|
|
1872
|
+
encoder: cmd_ctx,
|
|
1873
|
+
group_count_x: tick_groups,
|
|
1874
|
+
bindings: {
|
|
1875
|
+
dt,
|
|
1876
|
+
animation_database: this.#database.buffer,
|
|
1877
|
+
},
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// Size the pose accumulator to cover every allocated row of
|
|
1882
|
+
// the transforms table — apply writes by absolute row index,
|
|
1883
|
+
// resolve iterates the table via page iterator.
|
|
1884
|
+
const transforms_table = this.#scene_context.scene_database.get('transforms');
|
|
1885
|
+
const resolve_groups = transforms_table.dispatch_group_count(
|
|
1886
|
+
ANIMATION_POSE_RESOLVE_WORKGROUP_SIZE
|
|
1887
|
+
);
|
|
1888
|
+
this.ensure_pose_accumulator_capacity(transforms_table.element_capacity);
|
|
1889
|
+
|
|
1890
|
+
// ── Frame graph: apply → pose resolve → hierarchy propagate
|
|
1891
|
+
const graph = new FrameGraph("GPUAnimationManager/Tick");
|
|
1892
|
+
const gr_animation_database = graph_import_buffer(
|
|
1893
|
+
graph, this.#database.buffer, "animation_database"
|
|
1894
|
+
);
|
|
1895
|
+
const gr_scene_database = graph_import_buffer(
|
|
1896
|
+
graph, this.#scene_context.scene_database_buffer, "scene_database"
|
|
1897
|
+
);
|
|
1898
|
+
const gr_materials = graph_import_buffer(
|
|
1899
|
+
graph, this.#scene_context.materials.metadata_table.buffer, "materials"
|
|
1900
|
+
);
|
|
1901
|
+
const gr_pose_accumulator = graph_import_buffer(
|
|
1902
|
+
graph, this.#pose_accumulator_buffer, "pose_accumulator"
|
|
1903
|
+
);
|
|
1904
|
+
|
|
1905
|
+
const apply_data = {};
|
|
1906
|
+
const apply_pass = graph.add("animation/apply", apply_data, (data, resources, ctx) => {
|
|
1907
|
+
shader_animation_apply.dispatch({
|
|
1908
|
+
encoder: ctx.encoder,
|
|
1909
|
+
group_count_x: apply_groups,
|
|
1910
|
+
bindings: {
|
|
1911
|
+
animation_database: resources.get(data.animation_database),
|
|
1912
|
+
pose_accumulator: resources.get(data.pose_accumulator),
|
|
1913
|
+
materials: resources.get(data.materials),
|
|
1914
|
+
},
|
|
1915
|
+
});
|
|
1916
|
+
});
|
|
1917
|
+
apply_data.animation_database = apply_pass.read(gr_animation_database);
|
|
1918
|
+
apply_data.materials = apply_pass.write(apply_pass.read(gr_materials));
|
|
1919
|
+
apply_data.pose_accumulator = apply_pass.write(apply_pass.read(gr_pose_accumulator));
|
|
1920
|
+
|
|
1921
|
+
const resolve_data = {};
|
|
1922
|
+
const resolve_pass = graph.add("animation/pose_resolve", resolve_data, (data, resources, ctx) => {
|
|
1923
|
+
if (resolve_groups === 0) return;
|
|
1924
|
+
shader_animation_pose_resolve.dispatch({
|
|
1925
|
+
encoder: ctx.encoder,
|
|
1926
|
+
group_count_x: resolve_groups,
|
|
1927
|
+
bindings: {
|
|
1928
|
+
scene_database: resources.get(data.scene_database),
|
|
1929
|
+
pose_accumulator: resources.get(data.pose_accumulator),
|
|
1930
|
+
},
|
|
1931
|
+
});
|
|
1932
|
+
});
|
|
1933
|
+
resolve_data.scene_database = resolve_pass.write(resolve_pass.read(gr_scene_database));
|
|
1934
|
+
resolve_data.pose_accumulator = resolve_pass.write(resolve_pass.read(apply_data.pose_accumulator));
|
|
1935
|
+
|
|
1936
|
+
graph_scene_update_transform_hierarchy({
|
|
1937
|
+
graph,
|
|
1938
|
+
scene: this.#scene_context,
|
|
1939
|
+
scene_database: resolve_data.scene_database,
|
|
1940
|
+
});
|
|
1941
|
+
|
|
1942
|
+
cmd_ctx.encodeGraph(graph);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
destroy() {
|
|
1946
|
+
this.#database.destroy();
|
|
1947
|
+
for (let i = 0; i < 2; i++) {
|
|
1948
|
+
if (this.#skin_matrices_buffers[i] !== null) {
|
|
1949
|
+
this.#skin_matrices_buffers[i].destroy();
|
|
1950
|
+
this.#skin_matrices_buffers[i] = null;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
if (this.#pose_accumulator_buffer !== null) {
|
|
1954
|
+
this.#pose_accumulator_buffer.destroy();
|
|
1955
|
+
this.#pose_accumulator_buffer = null;
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
}
|