@woosh/meep-engine 3.29.0 → 3.30.0
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/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +14 -2
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +14 -1
- package/src/core/cache/FrequencySketch.d.ts +3 -1
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +10 -4
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
- package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +10 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +16 -10
- package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
- package/src/core/model/object/ImmutableObjectPool.js +17 -7
- package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +95 -1
- package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
- package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
- package/src/core/process/task/task_find_dependency_cycle.js +81 -0
- package/src/core/wfc/WFCCellChoice.d.ts +17 -0
- package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
- package/src/core/wfc/WFCCellChoice.js +36 -0
- package/src/core/wfc/WFCLattice.d.ts +105 -0
- package/src/core/wfc/WFCLattice.d.ts.map +1 -0
- package/src/core/wfc/WFCLattice.js +235 -0
- package/src/core/wfc/WFCRuleTable.d.ts +172 -0
- package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
- package/src/core/wfc/WFCRuleTable.js +334 -0
- package/src/core/wfc/WFCState.d.ts +273 -0
- package/src/core/wfc/WFCState.d.ts.map +1 -0
- package/src/core/wfc/WFCState.js +552 -0
- package/src/core/wfc/WFCStatus.d.ts +11 -0
- package/src/core/wfc/WFCStatus.d.ts.map +1 -0
- package/src/core/wfc/WFCStatus.js +28 -0
- package/src/core/wfc/WFCTileWeights.d.ts +48 -0
- package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
- package/src/core/wfc/WFCTileWeights.js +86 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
- package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
- package/src/core/wfc/wfc_estimate_bytes.js +47 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
- package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
- package/src/core/wfc/wfc_solve.d.ts +21 -0
- package/src/core/wfc/wfc_solve.d.ts.map +1 -0
- package/src/core/wfc/wfc_solve.js +154 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
- package/src/core/wfc/wfc_state_assign.d.ts +11 -0
- package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_assign.js +36 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_ban_bits.js +81 -0
- package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
- package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_collapse.js +73 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
- package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
- package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_propagate.js +155 -0
- package/src/core/wfc/wfc_state_read.d.ts +11 -0
- package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_read.js +38 -0
- package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
- package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_restrict.js +39 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_set_eligible.js +49 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_undo_to.js +84 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
- package/src/core/wfc/wfc_words_per_cell.js +16 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +37 -14
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
- package/src/engine/ecs/guid/UUID.js +45 -17
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
- package/src/engine/interpolation/Interpoland.d.ts +7 -1
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/Interpoland.js +8 -1
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +3 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/pose_interpoland.js +2 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
- package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
- package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
- package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
- package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
- package/src/format/image/avif/av1/util/round2.d.ts +19 -2
- package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
- package/src/format/image/avif/av1/util/round2.js +51 -27
- package/src/format/image/avif/heif/parse_avif_file.js +24 -0
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
- package/src/shade/renderer/particles/DESIGN.md +14 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +8 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
- package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
- package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipManager.js +22 -0
- package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipObserver.js +13 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
|
@@ -1,360 +1,366 @@
|
|
|
1
|
-
import { assert } from "../../../../../core/assert.js";
|
|
2
|
-
import { Deque } from "../../../../../core/collection/queue/Deque.js";
|
|
3
|
-
import { SurfacePoint3 } from "../../../../../core/geom/3d/SurfacePoint3.js";
|
|
4
|
-
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
5
|
-
|
|
6
|
-
import Vector3 from '../../../../../core/geom/Vector3.js';
|
|
7
|
-
import { clamp01 } from "../../../../../core/math/clamp01.js";
|
|
8
|
-
import { EPSILON } from "../../../../../core/math/EPSILON.js";
|
|
9
|
-
import { min2 } from "../../../../../core/math/min2.js";
|
|
10
|
-
import { ResourceAccessKind } from "../../../../../core/model/ResourceAccessKind.js";
|
|
11
|
-
import { ResourceAccessSpecification } from "../../../../../core/model/ResourceAccessSpecification.js";
|
|
12
|
-
import { System } from '../../../System.js';
|
|
13
|
-
import { Transform64 } from '../../../transform/Transform64.js';
|
|
14
|
-
import { obtainTerrain } from "../../util/obtainTerrain.js";
|
|
15
|
-
import Terrain from "../Terrain.js";
|
|
16
|
-
|
|
17
|
-
import ClingToTerrain from './ClingToTerrain.js';
|
|
18
|
-
import { TRANSFORM64_EVENT_CHANGE } from "../../../transform/TRANSFORM64_EVENT_CHANGE.js";
|
|
19
|
-
import { t64_announce_change } from "../../../transform/t64_announce_change.js";
|
|
20
|
-
import { t64_read_rotation } from "../../../transform/t64_read_rotation.js";
|
|
21
|
-
import { t64_read_translation } from "../../../transform/t64_read_translation.js";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
* @type {SurfacePoint3}
|
|
27
|
-
*/
|
|
28
|
-
const temp_sp = new SurfacePoint3();
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @param {{update:function,ecd:EntityComponentDataset,entity:number}} datum
|
|
32
|
-
*/
|
|
33
|
-
function deregister(datum) {
|
|
34
|
-
datum.ecd.removeEntityEventListener(
|
|
35
|
-
datum.entity, TRANSFORM64_EVENT_CHANGE, datum.update
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* How many entities can be updated in a single tick, this is useful for performance optimization.
|
|
41
|
-
* If you have a large number of entities that need to be updated, updates can be executed over several ticks
|
|
42
|
-
* @readonly
|
|
43
|
-
* @type {number}
|
|
44
|
-
*/
|
|
45
|
-
const DEFAULT_UPDATE_LIMIT = 1024;
|
|
46
|
-
|
|
47
|
-
class ClingToTerrainSystem extends System {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
dependencies = [ClingToTerrain, Transform64];
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
components_used = [
|
|
54
|
-
ResourceAccessSpecification.from(Transform64, ResourceAccessKind.Read | ResourceAccessKind.Write),
|
|
55
|
-
ResourceAccessSpecification.from(Terrain, ResourceAccessKind.Read)
|
|
56
|
-
];
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
*
|
|
60
|
-
* @type {Deque<number>}
|
|
61
|
-
*/
|
|
62
|
-
updateQueue = new Deque();
|
|
63
|
-
|
|
64
|
-
data = [];
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* How many entities can be updated in a single tick, this is useful for performance optimization, if you have a large number of entities that need to be updated, updates can be executed over several ticks
|
|
68
|
-
* @type {number}
|
|
69
|
-
*/
|
|
70
|
-
updateBatchLimit = DEFAULT_UPDATE_LIMIT;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
*
|
|
74
|
-
* @param {number} entity
|
|
75
|
-
*/
|
|
76
|
-
requestUpdate(entity) {
|
|
77
|
-
if (!this.updateQueue.has(entity)) {
|
|
78
|
-
//queue up update
|
|
79
|
-
this.updateQueue.addLast(entity);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
*
|
|
85
|
-
* @param {Transform64} transform
|
|
86
|
-
* @param {ClingToTerrain} cling
|
|
87
|
-
* @param {number} entityId
|
|
88
|
-
*/
|
|
89
|
-
link(cling, transform, entityId) {
|
|
90
|
-
|
|
91
|
-
const ecd = this.entityManager.dataset;
|
|
92
|
-
|
|
93
|
-
/*
|
|
94
|
-
The transform used to carry three signals and this listened to two of them. It carries
|
|
95
|
-
none now, so the interest is registered against the entity and the transform's own change
|
|
96
|
-
event: one listener where there were two, and it hears a write from anywhere - a spawner,
|
|
97
|
-
a script, a physics step - rather than only one that went through a sub-object.
|
|
98
|
-
*/
|
|
99
|
-
const update = () => this.requestUpdate(entityId);
|
|
100
|
-
|
|
101
|
-
this.data[entityId] = {
|
|
102
|
-
update,
|
|
103
|
-
transform,
|
|
104
|
-
component: cling,
|
|
105
|
-
ecd,
|
|
106
|
-
entity: entityId
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
ecd.addEntityEventListener(entityId, TRANSFORM64_EVENT_CHANGE, update);
|
|
110
|
-
|
|
111
|
-
this.requestUpdate(entityId);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
*
|
|
116
|
-
* @param {Transform64} transform
|
|
117
|
-
* @param {ClingToTerrain} cling
|
|
118
|
-
* @param {number} entityId
|
|
119
|
-
*/
|
|
120
|
-
unlink(cling, transform, entityId) {
|
|
121
|
-
const datum = this.data[entityId];
|
|
122
|
-
|
|
123
|
-
if (datum === undefined) {
|
|
124
|
-
console.error(`Tried to remove entity ${entityId}, but it was not registered. This is an inconsistency bug.`, transform, cling, `component dump:`, this.entityManager.getComponents(entityId));
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
deregister(datum);
|
|
129
|
-
|
|
130
|
-
delete this.data[entityId];
|
|
131
|
-
|
|
132
|
-
//clear update request if one is pending
|
|
133
|
-
this.updateQueue.remove(entityId);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
update(timeDelta) {
|
|
137
|
-
const em = this.entityManager;
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
*
|
|
141
|
-
* @type {EntityComponentDataset}
|
|
142
|
-
*/
|
|
143
|
-
const dataset = em.dataset;
|
|
144
|
-
|
|
145
|
-
if (dataset === null) {
|
|
146
|
-
//no dataset attached
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const updateCandidates = this.updateQueue;
|
|
151
|
-
|
|
152
|
-
const terrain = obtainTerrain(dataset);
|
|
153
|
-
|
|
154
|
-
if (terrain === null) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const batchSize = min2(
|
|
159
|
-
updateCandidates.size(),
|
|
160
|
-
this.updateBatchLimit
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
for (let i = 0; i < batchSize; i++) {
|
|
164
|
-
const entity = updateCandidates.removeFirst();
|
|
165
|
-
|
|
166
|
-
const c = this.data[entity];
|
|
167
|
-
|
|
168
|
-
if (c === undefined) {
|
|
169
|
-
/*
|
|
170
|
-
this should never happen as update queue is cleaned up when component is removed
|
|
171
|
-
the entity is gone
|
|
172
|
-
*/
|
|
173
|
-
|
|
174
|
-
//console.warn("ClingToTerrain component was in the update queue, but no data found. Skipping");
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const position_updated = doCling(c, terrain, timeDelta);
|
|
179
|
-
|
|
180
|
-
if (!position_updated) {
|
|
181
|
-
// no change, move back to update candidates
|
|
182
|
-
this.requestUpdate(entity);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const v3_temp = new Vector3();
|
|
190
|
-
const v3_forward = new Vector3();
|
|
191
|
-
const v3_up = new Vector3();
|
|
192
|
-
|
|
193
|
-
const q_temp = new Quaternion();
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* The pose of whichever entity is being clung right now, read out of its transform.
|
|
197
|
-
*
|
|
198
|
-
* @type {Vector3}
|
|
199
|
-
*/
|
|
200
|
-
const scratch_position = new Vector3();
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* @type {Quaternion}
|
|
204
|
-
*/
|
|
205
|
-
const scratch_rotation = new Quaternion();
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* TODO look into "swing-twist decomposition"
|
|
209
|
-
* @param {Quaternion} rotation
|
|
210
|
-
* @param {Vector3} direction
|
|
211
|
-
* @param {number} angularLimit
|
|
212
|
-
* @param up
|
|
213
|
-
* @param forward
|
|
214
|
-
*/
|
|
215
|
-
export function alignToVector(rotation, direction, angularLimit, up = Vector3.up, forward = Vector3.forward) {
|
|
216
|
-
assert.isNumber(angularLimit, 'angularLimit');
|
|
217
|
-
assert.notNaN(angularLimit, 'angularLimit');
|
|
218
|
-
|
|
219
|
-
//compute old facing direction vector
|
|
220
|
-
v3_forward.copy(forward);
|
|
221
|
-
|
|
222
|
-
v3_forward.applyQuaternion(rotation);
|
|
223
|
-
|
|
224
|
-
//compute perpendicular vector between old and desired alignment
|
|
225
|
-
v3_temp.crossVectors(direction, v3_forward);
|
|
226
|
-
|
|
227
|
-
//compute new facing vector that is perpendicular to alignment direction
|
|
228
|
-
v3_temp.crossVectors(v3_temp, direction);
|
|
229
|
-
|
|
230
|
-
q_temp.lookRotation(v3_temp, direction);
|
|
231
|
-
|
|
232
|
-
v3_up.copy(up);
|
|
233
|
-
|
|
234
|
-
v3_up.applyQuaternion(rotation);
|
|
235
|
-
|
|
236
|
-
const angle = v3_up.angleTo(direction);
|
|
237
|
-
|
|
238
|
-
assert.notNaN(angle, 'angle');
|
|
239
|
-
|
|
240
|
-
if (angle === 0) {
|
|
241
|
-
//no change
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const t = clamp01(angularLimit / angle);
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (cling.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
t.
|
|
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
|
-
* @type {
|
|
333
|
-
*/
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
1
|
+
import { assert } from "../../../../../core/assert.js";
|
|
2
|
+
import { Deque } from "../../../../../core/collection/queue/Deque.js";
|
|
3
|
+
import { SurfacePoint3 } from "../../../../../core/geom/3d/SurfacePoint3.js";
|
|
4
|
+
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
5
|
+
|
|
6
|
+
import Vector3 from '../../../../../core/geom/Vector3.js';
|
|
7
|
+
import { clamp01 } from "../../../../../core/math/clamp01.js";
|
|
8
|
+
import { EPSILON } from "../../../../../core/math/EPSILON.js";
|
|
9
|
+
import { min2 } from "../../../../../core/math/min2.js";
|
|
10
|
+
import { ResourceAccessKind } from "../../../../../core/model/ResourceAccessKind.js";
|
|
11
|
+
import { ResourceAccessSpecification } from "../../../../../core/model/ResourceAccessSpecification.js";
|
|
12
|
+
import { System } from '../../../System.js';
|
|
13
|
+
import { Transform64 } from '../../../transform/Transform64.js';
|
|
14
|
+
import { obtainTerrain } from "../../util/obtainTerrain.js";
|
|
15
|
+
import Terrain from "../Terrain.js";
|
|
16
|
+
|
|
17
|
+
import ClingToTerrain from './ClingToTerrain.js';
|
|
18
|
+
import { TRANSFORM64_EVENT_CHANGE } from "../../../transform/TRANSFORM64_EVENT_CHANGE.js";
|
|
19
|
+
import { t64_announce_change } from "../../../transform/t64_announce_change.js";
|
|
20
|
+
import { t64_read_rotation } from "../../../transform/t64_read_rotation.js";
|
|
21
|
+
import { t64_read_translation } from "../../../transform/t64_read_translation.js";
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @type {SurfacePoint3}
|
|
27
|
+
*/
|
|
28
|
+
const temp_sp = new SurfacePoint3();
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {{update:function,ecd:EntityComponentDataset,entity:number}} datum
|
|
32
|
+
*/
|
|
33
|
+
function deregister(datum) {
|
|
34
|
+
datum.ecd.removeEntityEventListener(
|
|
35
|
+
datum.entity, TRANSFORM64_EVENT_CHANGE, datum.update
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* How many entities can be updated in a single tick, this is useful for performance optimization.
|
|
41
|
+
* If you have a large number of entities that need to be updated, updates can be executed over several ticks
|
|
42
|
+
* @readonly
|
|
43
|
+
* @type {number}
|
|
44
|
+
*/
|
|
45
|
+
const DEFAULT_UPDATE_LIMIT = 1024;
|
|
46
|
+
|
|
47
|
+
class ClingToTerrainSystem extends System {
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
dependencies = [ClingToTerrain, Transform64];
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
components_used = [
|
|
54
|
+
ResourceAccessSpecification.from(Transform64, ResourceAccessKind.Read | ResourceAccessKind.Write),
|
|
55
|
+
ResourceAccessSpecification.from(Terrain, ResourceAccessKind.Read)
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @type {Deque<number>}
|
|
61
|
+
*/
|
|
62
|
+
updateQueue = new Deque();
|
|
63
|
+
|
|
64
|
+
data = [];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* How many entities can be updated in a single tick, this is useful for performance optimization, if you have a large number of entities that need to be updated, updates can be executed over several ticks
|
|
68
|
+
* @type {number}
|
|
69
|
+
*/
|
|
70
|
+
updateBatchLimit = DEFAULT_UPDATE_LIMIT;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
* @param {number} entity
|
|
75
|
+
*/
|
|
76
|
+
requestUpdate(entity) {
|
|
77
|
+
if (!this.updateQueue.has(entity)) {
|
|
78
|
+
//queue up update
|
|
79
|
+
this.updateQueue.addLast(entity);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
*
|
|
85
|
+
* @param {Transform64} transform
|
|
86
|
+
* @param {ClingToTerrain} cling
|
|
87
|
+
* @param {number} entityId
|
|
88
|
+
*/
|
|
89
|
+
link(cling, transform, entityId) {
|
|
90
|
+
|
|
91
|
+
const ecd = this.entityManager.dataset;
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
The transform used to carry three signals and this listened to two of them. It carries
|
|
95
|
+
none now, so the interest is registered against the entity and the transform's own change
|
|
96
|
+
event: one listener where there were two, and it hears a write from anywhere - a spawner,
|
|
97
|
+
a script, a physics step - rather than only one that went through a sub-object.
|
|
98
|
+
*/
|
|
99
|
+
const update = () => this.requestUpdate(entityId);
|
|
100
|
+
|
|
101
|
+
this.data[entityId] = {
|
|
102
|
+
update,
|
|
103
|
+
transform,
|
|
104
|
+
component: cling,
|
|
105
|
+
ecd,
|
|
106
|
+
entity: entityId
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
ecd.addEntityEventListener(entityId, TRANSFORM64_EVENT_CHANGE, update);
|
|
110
|
+
|
|
111
|
+
this.requestUpdate(entityId);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
*
|
|
116
|
+
* @param {Transform64} transform
|
|
117
|
+
* @param {ClingToTerrain} cling
|
|
118
|
+
* @param {number} entityId
|
|
119
|
+
*/
|
|
120
|
+
unlink(cling, transform, entityId) {
|
|
121
|
+
const datum = this.data[entityId];
|
|
122
|
+
|
|
123
|
+
if (datum === undefined) {
|
|
124
|
+
console.error(`Tried to remove entity ${entityId}, but it was not registered. This is an inconsistency bug.`, transform, cling, `component dump:`, this.entityManager.getComponents(entityId));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
deregister(datum);
|
|
129
|
+
|
|
130
|
+
delete this.data[entityId];
|
|
131
|
+
|
|
132
|
+
//clear update request if one is pending
|
|
133
|
+
this.updateQueue.remove(entityId);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
update(timeDelta) {
|
|
137
|
+
const em = this.entityManager;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
*
|
|
141
|
+
* @type {EntityComponentDataset}
|
|
142
|
+
*/
|
|
143
|
+
const dataset = em.dataset;
|
|
144
|
+
|
|
145
|
+
if (dataset === null) {
|
|
146
|
+
//no dataset attached
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const updateCandidates = this.updateQueue;
|
|
151
|
+
|
|
152
|
+
const terrain = obtainTerrain(dataset);
|
|
153
|
+
|
|
154
|
+
if (terrain === null) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const batchSize = min2(
|
|
159
|
+
updateCandidates.size(),
|
|
160
|
+
this.updateBatchLimit
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < batchSize; i++) {
|
|
164
|
+
const entity = updateCandidates.removeFirst();
|
|
165
|
+
|
|
166
|
+
const c = this.data[entity];
|
|
167
|
+
|
|
168
|
+
if (c === undefined) {
|
|
169
|
+
/*
|
|
170
|
+
this should never happen as update queue is cleaned up when component is removed
|
|
171
|
+
the entity is gone
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
//console.warn("ClingToTerrain component was in the update queue, but no data found. Skipping");
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const position_updated = doCling(c, terrain, timeDelta);
|
|
179
|
+
|
|
180
|
+
if (!position_updated) {
|
|
181
|
+
// no change, move back to update candidates
|
|
182
|
+
this.requestUpdate(entity);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
const v3_temp = new Vector3();
|
|
190
|
+
const v3_forward = new Vector3();
|
|
191
|
+
const v3_up = new Vector3();
|
|
192
|
+
|
|
193
|
+
const q_temp = new Quaternion();
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The pose of whichever entity is being clung right now, read out of its transform.
|
|
197
|
+
*
|
|
198
|
+
* @type {Vector3}
|
|
199
|
+
*/
|
|
200
|
+
const scratch_position = new Vector3();
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @type {Quaternion}
|
|
204
|
+
*/
|
|
205
|
+
const scratch_rotation = new Quaternion();
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* TODO look into "swing-twist decomposition"
|
|
209
|
+
* @param {Quaternion} rotation
|
|
210
|
+
* @param {Vector3} direction
|
|
211
|
+
* @param {number} angularLimit
|
|
212
|
+
* @param up
|
|
213
|
+
* @param forward
|
|
214
|
+
*/
|
|
215
|
+
export function alignToVector(rotation, direction, angularLimit, up = Vector3.up, forward = Vector3.forward) {
|
|
216
|
+
assert.isNumber(angularLimit, 'angularLimit');
|
|
217
|
+
assert.notNaN(angularLimit, 'angularLimit');
|
|
218
|
+
|
|
219
|
+
//compute old facing direction vector
|
|
220
|
+
v3_forward.copy(forward);
|
|
221
|
+
|
|
222
|
+
v3_forward.applyQuaternion(rotation);
|
|
223
|
+
|
|
224
|
+
//compute perpendicular vector between old and desired alignment
|
|
225
|
+
v3_temp.crossVectors(direction, v3_forward);
|
|
226
|
+
|
|
227
|
+
//compute new facing vector that is perpendicular to alignment direction
|
|
228
|
+
v3_temp.crossVectors(v3_temp, direction);
|
|
229
|
+
|
|
230
|
+
q_temp.lookRotation(v3_temp, direction);
|
|
231
|
+
|
|
232
|
+
v3_up.copy(up);
|
|
233
|
+
|
|
234
|
+
v3_up.applyQuaternion(rotation);
|
|
235
|
+
|
|
236
|
+
const angle = v3_up.angleTo(direction);
|
|
237
|
+
|
|
238
|
+
assert.notNaN(angle, 'angle');
|
|
239
|
+
|
|
240
|
+
if (angle === 0) {
|
|
241
|
+
//no change
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const t = clamp01(angularLimit / angle);
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* `slerp` and not `lerp`: a componentwise lerp neither renormalises nor takes the shortest arc,
|
|
249
|
+
* and `Transform64#setRotation` states that the quaternion is expected to be of unit length and
|
|
250
|
+
* that nothing there normalises it. A short quaternion composes into a sheared, non-orthogonal
|
|
251
|
+
* basis that `updateComponents()` then decomposes into the entity's scale and carries down every
|
|
252
|
+
* attachment below it. Measured worst case here was |q| = 0.707, against a near-antipodal normal.
|
|
253
|
+
*/
|
|
254
|
+
rotation.slerp(q_temp, t);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
*
|
|
260
|
+
* @param {Vector3} point
|
|
261
|
+
* @param {Transform64} t
|
|
262
|
+
* @param {Vector3} normal
|
|
263
|
+
* @param {ClingToTerrain} cling
|
|
264
|
+
* @param {number} timeDelta
|
|
265
|
+
*/
|
|
266
|
+
function processRaycastHit(point, t, normal, cling, timeDelta, el) {
|
|
267
|
+
assert.defined(point, 'point');
|
|
268
|
+
assert.equal(point.isVector3, true, 'point.isVector3 !== true');
|
|
269
|
+
assert.isNumber(timeDelta, 'timeDelta');
|
|
270
|
+
|
|
271
|
+
// filled by the caller, which had to read them to decide there was anything to do
|
|
272
|
+
const position = scratch_position;
|
|
273
|
+
const rotation = scratch_rotation;
|
|
274
|
+
|
|
275
|
+
const hitDistance = position.distanceTo(point);
|
|
276
|
+
|
|
277
|
+
//cache current position
|
|
278
|
+
cling.__lastPosition.copy(position);
|
|
279
|
+
cling.__lastRotation.copy(rotation);
|
|
280
|
+
|
|
281
|
+
let moved = false;
|
|
282
|
+
|
|
283
|
+
if (hitDistance > EPSILON) {
|
|
284
|
+
t.setTranslation(position.x, point.y, position.z);
|
|
285
|
+
|
|
286
|
+
moved = true;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
let angularLimit;
|
|
290
|
+
|
|
291
|
+
if (Number.isFinite(cling.rotationSpeed)) {
|
|
292
|
+
angularLimit = cling.rotationSpeed * timeDelta;
|
|
293
|
+
} else {
|
|
294
|
+
angularLimit = Number.POSITIVE_INFINITY;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (cling.normalAlign) {
|
|
298
|
+
alignToVector(rotation, normal, angularLimit);
|
|
299
|
+
|
|
300
|
+
if (
|
|
301
|
+
rotation.x !== t.rotation_x || rotation.y !== t.rotation_y
|
|
302
|
+
|| rotation.z !== t.rotation_z || rotation.w !== t.rotation_w
|
|
303
|
+
) {
|
|
304
|
+
t.setRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
305
|
+
|
|
306
|
+
// the rotation is the only write that leaves the matrix behind
|
|
307
|
+
t.updateMatrix();
|
|
308
|
+
|
|
309
|
+
moved = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*
|
|
314
|
+
Announced only when something actually changed. The system is listening to this entity itself,
|
|
315
|
+
so an announcement it did not earn would queue the entity again, find nothing to do, and queue
|
|
316
|
+
it again - a spin that never settles.
|
|
317
|
+
*/
|
|
318
|
+
if (moved) {
|
|
319
|
+
t64_announce_change(el.ecd, el.entity);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
*
|
|
325
|
+
* @param {{component:ClingToTerrain,transform:Transform}} el
|
|
326
|
+
* @param {Terrain} terrain
|
|
327
|
+
* @param {number} timeDelta
|
|
328
|
+
* @returns {boolean} whether position was updated or not
|
|
329
|
+
*/
|
|
330
|
+
function doCling(el, terrain, timeDelta) {
|
|
331
|
+
/**
|
|
332
|
+
* @type {ClingToTerrain}
|
|
333
|
+
*/
|
|
334
|
+
const cling = el.component;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
*
|
|
338
|
+
* @type {Transform64}
|
|
339
|
+
*/
|
|
340
|
+
const t = el.transform;
|
|
341
|
+
|
|
342
|
+
// read out once; the comparison, the cast and the write below all want the same numbers, and
|
|
343
|
+
// reading them through the component's view accessors would allocate two arrays per entity
|
|
344
|
+
t64_read_translation(scratch_position, t);
|
|
345
|
+
t64_read_rotation(scratch_rotation, t);
|
|
346
|
+
|
|
347
|
+
if (
|
|
348
|
+
cling.__lastPosition.roughlyEquals(scratch_position, 0.001)
|
|
349
|
+
&& cling.__lastRotation.roughlyEquals(scratch_rotation, 0.0001)
|
|
350
|
+
) {
|
|
351
|
+
//do nothing, cached position matches with existing position
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const hit_found = terrain.raycastVerticalFirstSync(
|
|
356
|
+
temp_sp, scratch_position.x, scratch_position.z
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
if (hit_found) {
|
|
360
|
+
processRaycastHit(temp_sp.position, t, temp_sp.normal, cling, timeDelta, el);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return hit_found;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export default ClingToTerrainSystem;
|