@woosh/meep-engine 2.33.21 → 2.33.25
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/core/assert.js +3 -1
- package/core/bvh2/BinaryNode.js +1 -1
- package/core/bvh2/aabb3/AABB3.js +18 -0
- package/core/bvh2/aabb3/AABB3Math.js +1 -1
- package/core/bvh2/binary/2/BinaryUint32BVH.js +498 -0
- package/core/bvh2/binary/2/BinaryUint32BVH.spec.js +54 -0
- package/core/bvh2/binary/IndexedBinaryBVH.js +22 -26
- package/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +5 -1
- package/core/bvh2/traversal/__detailed_box_volume_intersection.js +31 -11
- package/core/collection/ArrayUtils.js +1 -1
- package/core/collection/array/arrayQuickSort.js +9 -6
- package/core/collection/array/array_swap.js +22 -0
- package/core/collection/array/binarySearchHighIndex.js +1 -1
- package/core/collection/array/computeHashArray.js +22 -0
- package/core/collection/array/computeHashIntegerArray.js +15 -0
- package/core/collection/array/copyArray.js +2 -2
- package/core/collection/table/DataType2TypedArrayConstructorMapping.js +15 -0
- package/core/color/Color.js +2 -1
- package/core/function/FunctionCompiler.js +2 -1
- package/core/geom/3d/aabb/aabb3_computeDistanceAbovePlane.js +9 -33
- package/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +10 -2
- package/core/geom/3d/line/line3_computeSegmentPointDistance_sqr.js +41 -0
- package/core/geom/3d/morton/mortonEncode_magicbits.js +2 -1
- package/core/geom/3d/morton/reinterpret_float32_as_int32.js +13 -0
- package/core/geom/3d/morton/v3_morton_encode_transformed.js +33 -0
- package/core/geom/3d/normal/hemioct/unit_hemioct.spec.js +1 -1
- package/core/geom/3d/plane/plane_computeConvex3PlaneIntersection.js +13 -14
- package/core/geom/3d/ray/ray_computeNearestPointToPoint.js +37 -0
- package/core/geom/3d/shape/AbstractShape3D.js +38 -0
- package/core/geom/3d/shape/CompositeShape.js +240 -0
- package/core/geom/3d/shape/TransformedShape3D.js +126 -0
- package/core/geom/3d/shape/UnitCubeShape3D.js +24 -0
- package/core/geom/3d/shape/UnitSphereShape3D.js +24 -0
- package/core/geom/3d/shape/util/shape_to_visual_entity.js +159 -0
- package/core/geom/3d/voxel/DenseBitVolume3D.js +87 -0
- package/core/geom/3d/voxel/buildVolumeFromProjectedGeometry.js +23 -0
- package/core/geom/AABB2.js +1 -1
- package/core/geom/ConicRay.js +3 -1
- package/core/geom/LineSegment.js +0 -78
- package/core/geom/Matrix4.js +7 -8
- package/core/geom/Plane.js +14 -9
- package/core/geom/Rectangle.js +2 -1
- package/core/geom/Vector1.js +1 -1
- package/core/geom/Vector3.js +2 -1
- package/core/geom/Vector4.js +2 -1
- package/core/geom/random/randomPointInBox.js +7 -3
- package/core/geom/random/randomPointInPoint.js +6 -3
- package/core/geom/random/randomPointInSphere.js +9 -5
- package/core/geom/random/randomPointOnBox.js +7 -3
- package/core/geom/random/randomPointOnSphere.js +6 -3
- package/core/geom/v3_length.js +8 -3
- package/core/graph/graph_k_means_cluster.js +1 -1
- package/core/json/resolvePathByArray.js +2 -2
- package/core/math/MathUtils.js +0 -354
- package/core/math/MathUtils.spec.js +7 -1
- package/core/math/gaussian.js +9 -0
- package/core/math/hash/computeHashFloat.js +17 -0
- package/core/math/hash/computeHashFloatArray.js +34 -0
- package/core/math/hash/computeObjectHash.js +54 -0
- package/core/math/intersects1D.js +19 -0
- package/core/math/interval/NumericInterval.js +2 -2
- package/core/math/isValueBetween.js +10 -0
- package/core/math/isValueBetweenInclusive.js +10 -0
- package/core/math/noise/curl_noise_3dt.js +1 -1
- package/core/math/noise/sdnoise.js +10 -10
- package/core/math/overlap1D.js +19 -0
- package/core/math/pingpong.js +17 -0
- package/core/math/random/makeRangedRandom.js +19 -0
- package/core/math/random/randomFloatBetween.js +14 -0
- package/core/math/random/randomFromArray.js +19 -0
- package/core/math/random/randomGaussian.js +15 -0
- package/core/math/random/randomIntegerBetween.js +14 -0
- package/core/math/random/roundFair.js +15 -0
- package/core/math/separation1D.js +21 -0
- package/core/math/solveQuadratic.js +25 -0
- package/core/model/BoundedValue.js +1 -1
- package/core/model/node-graph/node/NodeInstancePortReference.js +1 -1
- package/core/model/node-graph/node/Port.js +1 -1
- package/core/model/reactive/evaluation/MultiPredicateEvaluator.spec.js +3 -1
- package/core/model/reactive/model/ReactiveBinaryExpression.js +1 -1
- package/core/model/reactive/model/terminal/ReactiveLiteralNumber.js +1 -1
- package/core/model/reactive/model/terminal/ReactiveReference.js +1 -1
- package/core/model/reactive/model/util/createRandomReactiveExpression.js +1 -1
- package/core/model/stat/LinearModifier.js +1 -1
- package/core/primitives/array/computeIntegerArrayHash.js +1 -1
- package/{engine/graphics/render/forward_plus/materials → core/primitives/strings}/insert_after.js +3 -0
- package/core/primitives/strings/insert_after_or_replace.js +27 -0
- package/editor/process/symbolic/makeHelperBoxGeometry.js +44 -0
- package/editor/view/ecs/EntityEditor.js +2 -2
- package/editor/view/ecs/components/particles/ParticleEmitterController.js +2 -2
- package/engine/EngineHarness.js +1 -0
- package/engine/animation/AnimationUtils.js +5 -5
- package/engine/animation/curve/AnimationCurve.js +72 -0
- package/engine/animation/curve/Keyframe.js +27 -0
- package/engine/animation/keyed2/AnimationTrack.js +27 -3
- package/engine/asset/Asset.js +1 -1
- package/engine/asset/loaders/GLTFAssetLoader.d.ts +1 -1
- package/engine/asset/loaders/GLTFAssetLoader.js +10 -0
- package/engine/asset/loaders/image/ImageRGBADataAsset.js +8 -1
- package/engine/asset/loaders/material/computeImageBitmapEquality.js +11 -0
- package/engine/asset/loaders/material/computeImageBitmapHash.js +22 -28
- package/engine/asset/loaders/material/computeMaterialHash.js +3 -1
- package/engine/asset/loaders/material/computeTextureHash.js +2 -1
- package/engine/ecs/EntityBuilder.js +25 -5
- package/engine/ecs/animation/Animation.js +2 -1
- package/engine/ecs/animation/InverseKinematics.js +2 -1
- package/engine/ecs/attachment/AttachmentBinding.js +8 -0
- package/engine/ecs/attachment/AttachmentSystem.js +4 -0
- package/engine/ecs/attachment/TransformAttachmentBinding.js +14 -44
- package/engine/ecs/components/Tag.js +27 -6
- package/engine/ecs/dynamic_actions/DynamicActorSystem.js +2 -1
- package/engine/ecs/dynamic_actions/DynamicRuleDescriptionTable.spec.js +3 -5
- package/engine/ecs/dynamic_actions/actions/definition/WeightedRandomActionDescription.js +1 -1
- package/engine/ecs/evaluation/complex/PointFitnessGaussianBlur.js +1 -1
- package/engine/ecs/foliage/ecs/Foliage2.js +1 -1
- package/engine/ecs/fow/FogOfWar.js +4 -0
- package/engine/ecs/fow/FogOfWarSystem.js +2 -0
- package/engine/ecs/fow/shader/FogOfWarRenderer.js +1 -1
- package/engine/ecs/gui/GUIElement.js +1 -1
- package/engine/ecs/gui/hud/HeadsUpDisplay.js +1 -1
- package/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +2 -0
- package/engine/ecs/gui/position/ViewportPosition.js +2 -1
- package/engine/ecs/system/AbstractContextSystem.js +1 -1
- package/engine/ecs/systems/RangedAttackSystem.js +1 -1
- package/engine/ecs/systems/SteeringSystem.js +1 -1
- package/engine/ecs/systems/TagSystem.js +17 -0
- package/engine/ecs/terrain/tiles/TerrainTileManager.js +1 -1
- package/engine/ecs/tooltip/TooltipComponent.js +15 -0
- package/engine/ecs/transform/Transform.js +19 -6
- package/engine/ecs/util/hideEntityGracefully.js +18 -0
- package/engine/graphics/GraphicsEngine.js +11 -23
- package/engine/graphics/camera/testClippingPlaneComputation.js +2 -2
- package/engine/graphics/composit/CompositLayer.js +17 -4
- package/engine/graphics/composit/CompositingStages.js +8 -0
- package/engine/graphics/composit/LayerCompositer.js +35 -6
- package/engine/graphics/ecs/animation/animator/AnimationClip.js +2 -1
- package/engine/graphics/ecs/animation/animator/AnimationClipDefinition.js +2 -1
- package/engine/graphics/ecs/animation/animator/AnimationNotification.js +2 -1
- package/engine/graphics/ecs/animation/animator/AnimationNotificationDefinition.js +2 -1
- package/engine/graphics/ecs/animation/animator/graph/AnimationGraph.js +2 -1
- package/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +2 -1
- package/engine/graphics/ecs/animation/animator/graph/definition/AnimationStateDefinition.js +1 -1
- package/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.js +2 -1
- package/engine/graphics/ecs/camera/CameraClippingPlaneComputer.js +1 -1
- package/engine/graphics/ecs/highlight/HighlightDefinition.js +2 -1
- package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +11 -7
- package/engine/graphics/ecs/light/Light.d.ts +1 -1
- package/engine/graphics/ecs/light/Light.js +5 -0
- package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +5 -1
- package/engine/graphics/ecs/mesh/Mesh.js +2 -1
- package/engine/graphics/ecs/mesh-v2/DrawMode.js +5 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +13 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +32 -18
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts +6 -0
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +98 -98
- package/engine/graphics/ecs/trail2d/Trail2D.js +17 -4
- package/engine/graphics/ecs/trail2d/Trail2DSystem.d.ts +2 -3
- package/engine/graphics/ecs/trail2d/Trail2DSystem.js +34 -118
- package/engine/graphics/geometry/AttributeSpec.js +105 -0
- package/engine/graphics/{micron/format/MicronVertexDataSpec.js → geometry/VertexDataSpec.js} +56 -25
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +7 -7
- package/engine/graphics/micron/build/fill_patch_geometry_data.js +1 -1
- package/engine/graphics/micron/buildPatchwork.js +1 -1
- package/engine/graphics/micron/format/MicronGeometry.js +3 -3
- package/engine/graphics/micron/format/serialization/MicronGeometryBinarySerializationAdapter.js +2 -2
- package/engine/graphics/micron/format/serialization/deserialize_attribute_spec.js +1 -1
- package/engine/graphics/micron/format/serialization/serialize_attribute_spec.js +1 -1
- package/engine/graphics/micron/render/PatchCacheKey.js +1 -1
- package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +5 -5
- package/engine/graphics/micron/render/v1/ThreeVirtualGeometryAdapter.js +1 -1
- package/engine/graphics/particles/ParticleEmitterLibrary.js +3 -0
- package/engine/graphics/particles/ecs/{ParticleEmitterSystem2.js → ParticleEmitterSystem.js} +17 -9
- package/engine/graphics/particles/particular/engine/ParticularEngine.js +12 -4
- package/engine/graphics/particles/particular/engine/emitter/PARTICULAR_PARTICLE_SPECIFICATION.js +84 -0
- package/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +106 -169
- package/engine/graphics/particles/particular/engine/emitter/ParticleEmitterFlag.js +5 -0
- package/engine/graphics/particles/particular/engine/emitter/ParticleLayer.js +14 -3
- package/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +141 -14
- package/engine/graphics/particles/particular/engine/emitter/ParticlePool.spec.js +8 -7
- package/engine/graphics/particles/particular/engine/emitter/computeEmissionFunction.js +37 -0
- package/engine/graphics/particles/particular/engine/emitter/distance_to_camera.js +25 -0
- package/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.js +8 -2
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -1
- package/engine/graphics/particles/particular/engine/parameter/ParameterTrack.js +1 -1
- package/engine/graphics/particles/particular/engine/parameter/ParticleParameter.js +1 -1
- package/engine/graphics/particles/particular/engine/renderers/billboard/BILLBOARD_PARTICLE_SPECIFICATION.js +24 -0
- package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +262 -71
- package/engine/graphics/particles/particular/engine/renderers/billboard/prototypeBillboardRenderer.js +9 -9
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +80 -46
- package/engine/graphics/particles/particular/engine/shader/debugAtlas.js +14 -0
- package/engine/graphics/particles/particular/engine/simulator/SimulationStepApplyForce.js +2 -5
- package/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseAcceleration.js +2 -6
- package/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.js +2 -7
- package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +2 -5
- package/engine/graphics/particles/particular/engine/simulator/update_parameters.js +1 -1
- package/engine/graphics/particles/particular/engine/utils/distributeParticlesOnObject3D.js +1 -1
- package/engine/graphics/particles/particular/engine/utils/distrubuteParticlesOnMesh.js +1 -1
- package/engine/graphics/particles/particular/engine/utils/volume/AttributeValue.js +141 -0
- package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +478 -0
- package/engine/graphics/particles/particular/engine/utils/volume/lut_to_sampler.js +27 -0
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +935 -0
- package/engine/graphics/particles/particular/group/Operation.js +18 -0
- package/engine/graphics/particles/particular/group/OperationType.js +9 -0
- package/engine/graphics/particles/particular/group/ParticleAttribute.js +2 -1
- package/engine/graphics/particles/particular/group/ParticleAttributeType.js +11 -0
- package/engine/graphics/particles/particular/group/ParticleDataType.js +10 -0
- package/engine/graphics/particles/particular/group/ParticleGroup.js +7 -245
- package/engine/graphics/particles/particular/group/ParticleGroup.spec.js +3 -1
- package/engine/graphics/particles/particular/group/ParticleSpecification.js +21 -14
- package/engine/graphics/particles/particular/group/itemSizeFromAttributeType.js +20 -0
- package/engine/graphics/particles/particular/group/optimizeCommandQueue.js +162 -0
- package/engine/graphics/particles/particular/group/typedArrayConstructorFromDataType.js +19 -0
- package/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +2 -2
- package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +13 -7
- package/engine/graphics/render/buffer/slot/parameter/ProgramValueSlotParameter.js +2 -1
- package/engine/graphics/render/buffer/slot/parameter/ProgramValueSlotParameterSet.js +1 -1
- package/engine/graphics/render/forward_plus/LightManager.js +126 -95
- package/engine/graphics/render/forward_plus/PointLight.js +9 -0
- package/engine/graphics/render/forward_plus/PointLightData.js +1 -1
- package/engine/graphics/render/forward_plus/SpotLight.js +9 -0
- package/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.js +2 -2
- package/engine/graphics/render/forward_plus/computeFrustumCorners.js +14 -32
- package/engine/graphics/render/forward_plus/materials/FP_INJECTION_POINT_ACCUMULATION.js +1 -0
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +32 -0
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_DECODE_PARS.js +51 -0
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +25 -0
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +31 -120
- package/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.js +35 -0
- package/engine/graphics/render/forward_plus/materials/fp_build_vertex_shader.js +4 -5
- package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +1 -1
- package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +10 -3
- package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +595 -60
- package/engine/graphics/render/forward_plus/prototypeLightManager.js +256 -136
- package/engine/graphics/render/forward_plus/query/analytical_triplanar_corner_mapping.js +8 -0
- package/engine/graphics/render/forward_plus/query/cube_mapping.js +38 -0
- package/engine/graphics/render/forward_plus/query/detailed_sphere_frustum_intersection_test.js +86 -0
- package/engine/graphics/render/forward_plus/query/point_light_inside_volume.js +73 -0
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_objects.js +131 -0
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +129 -0
- package/engine/graphics/render/forward_plus/query/spot_light_inside_volume.js +33 -0
- package/engine/graphics/render/forward_plus/read_frustum_corner.js +14 -0
- package/engine/graphics/render/forward_plus/testClusterEquality.js +22 -0
- package/engine/graphics/render/layers/RenderLayerUtils.js +7 -4
- package/engine/graphics/render/visibility/IncrementalDeltaSet.js +11 -0
- package/engine/graphics/render/visibility/hiz/prototypeHiZ.js +2 -2
- package/engine/graphics/shaders/TerrainShader.js +4 -5
- package/engine/graphics/texture/atlas/AtlasPatch.js +7 -2
- package/engine/graphics/texture/atlas/TextureAtlas.js +2 -2
- package/engine/graphics/texture/sampler/HarmonicDiffusionGrid.spec.js +1 -1
- package/engine/graphics/texture/sampler/SampleTraverser.js +1 -1
- package/engine/graphics/texture/sampler/Sampler2D.js +8 -7
- package/engine/graphics/texture/sampler/distanceField.spec.js +1 -1
- package/engine/graphics/texture/sampler/scaleSampler2D.js +7 -10
- package/engine/graphics/trail/x/RibbonMaterialX.js +3 -3
- package/engine/graphics/trail/x/RibbonX.js +17 -2
- package/engine/graphics/trail/x/RibbonXPlugin.js +51 -1
- package/engine/graphics/util/composeMatrix4.js +33 -23
- package/engine/graphics/util/decompose_matrix_4_array.js +61 -0
- package/engine/grid/components/GridObstacle.js +3 -10
- package/engine/intelligence/behavior/ecs/BehaviorComponent.js +30 -14
- package/engine/intelligence/behavior/selector/WeightedElement.js +2 -1
- package/engine/intelligence/optimization/RandomOptimizer.js +1 -1
- package/engine/knowledge/database/StaticKnowledgeDataTable.js +6 -1
- package/engine/navigation/ecs/components/Path.js +1 -6
- package/engine/navigation/grid/FastBinaryHeap.spec.js +1 -1
- package/engine/reference/v2/Reference.js +6 -0
- package/engine/sound/ecs/emitter/SoundEmitter.js +2 -1
- package/engine/sound/ecs/emitter/SoundTrack.js +2 -1
- package/engine/sound/material/concrete/RandomSoundMaterial.js +1 -1
- package/engine/ui/notification/notificationGenerator.js +1 -1
- package/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +1 -1
- package/generation/grid/generation/GridTaskExecuteRuleTimes.js +2 -1
- package/generation/markers/actions/MarkerNodeActionSelectRandom.js +1 -1
- package/generation/markers/transform/MarkerNodeTransformerRecordUniqueRandomEnum.js +1 -1
- package/generation/placement/action/random/CellActionSelectRandom.js +1 -1
- package/generation/theme/ThemeEngine.js +2 -2
- package/misc/makeMaterialIconCached.js +2 -2
- package/package.json +3 -3
- package/view/View.js +4 -2
- package/view/elements/image/HTMLElementCacheKey.js +2 -1
- package/view/elements/radial/RadialText.js +2 -1
- package/view/minimap/gl/MinimapMarkersGL.js +6 -100
- package/view/minimap/gl/buildMaterial.js +94 -0
- package/engine/graphics/micron/format/MicronGeometryBufferAttributeSpec.js +0 -71
- package/engine/graphics/render/forward_plus/queryBVH_Frustum.js +0 -345
|
@@ -2,19 +2,21 @@ import { v3_dot } from "../../v3_dot.js";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
5
|
-
* @param {
|
|
5
|
+
* @param {number[]} result
|
|
6
|
+
* @param {number} result_offset
|
|
6
7
|
* @param {Plane} a
|
|
7
8
|
* @param {Plane} b
|
|
8
9
|
* @param {Plane} c
|
|
9
10
|
* @returns {boolean}
|
|
10
11
|
*/
|
|
11
|
-
export function plane_three_computeConvex3PlaneIntersection(result, a, b, c) {
|
|
12
|
+
export function plane_three_computeConvex3PlaneIntersection(result, result_offset, a, b, c) {
|
|
12
13
|
const a_normal = a.normal;
|
|
13
14
|
const b_normal = b.normal;
|
|
14
15
|
const c_normal = c.normal;
|
|
15
16
|
|
|
16
17
|
return plane_computeConvex3PlaneIntersection(
|
|
17
18
|
result,
|
|
19
|
+
result_offset,
|
|
18
20
|
a_normal.x, a_normal.y, a_normal.z, a.constant,
|
|
19
21
|
b_normal.x, b_normal.y, b_normal.z, b.constant,
|
|
20
22
|
c_normal.x, c_normal.y, c_normal.z, c.constant,
|
|
@@ -23,7 +25,8 @@ export function plane_three_computeConvex3PlaneIntersection(result, a, b, c) {
|
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* NOTE: Based on Intersection of 3 planes, Graphics Gems 1 pg 305
|
|
26
|
-
* @param {
|
|
28
|
+
* @param {Float32Array|number[]|vec3} result
|
|
29
|
+
* @param {number} result_offset
|
|
27
30
|
* @param {number} a_normal_x
|
|
28
31
|
* @param {number} a_normal_y
|
|
29
32
|
* @param {number} a_normal_z
|
|
@@ -39,7 +42,7 @@ export function plane_three_computeConvex3PlaneIntersection(result, a, b, c) {
|
|
|
39
42
|
* @returns {boolean} true if planes intersect, false otherwise
|
|
40
43
|
*/
|
|
41
44
|
export function plane_computeConvex3PlaneIntersection(
|
|
42
|
-
result,
|
|
45
|
+
result, result_offset,
|
|
43
46
|
a_normal_x, a_normal_y, a_normal_z, a_constant,
|
|
44
47
|
b_normal_x, b_normal_y, b_normal_z, b_constant,
|
|
45
48
|
c_normal_x, c_normal_y, c_normal_z, c_constant
|
|
@@ -74,18 +77,14 @@ export function plane_computeConvex3PlaneIntersection(
|
|
|
74
77
|
const d = 1 / determinant;
|
|
75
78
|
|
|
76
79
|
const neg_a_constant = -a_constant;
|
|
77
|
-
const neg_b_constant = -b_constant;
|
|
78
|
-
const neg_c_constant = -c_constant;
|
|
79
80
|
|
|
80
|
-
const x = (bxc_x * neg_a_constant
|
|
81
|
-
const y = (bxc_y * neg_a_constant
|
|
82
|
-
const z = (bxc_z * neg_a_constant
|
|
81
|
+
const x = (bxc_x * neg_a_constant - cxa_x * b_constant - axb_x * c_constant) * d;
|
|
82
|
+
const y = (bxc_y * neg_a_constant - cxa_y * b_constant - axb_y * c_constant) * d;
|
|
83
|
+
const z = (bxc_z * neg_a_constant - cxa_z * b_constant - axb_z * c_constant) * d;
|
|
83
84
|
|
|
84
|
-
result
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
z
|
|
88
|
-
);
|
|
85
|
+
result[result_offset] = x;
|
|
86
|
+
result[result_offset + 1] = y;
|
|
87
|
+
result[result_offset + 2] = z;
|
|
89
88
|
|
|
90
89
|
return true;
|
|
91
90
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { v3_dot } from "../../v3_dot.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {Vector3} result
|
|
6
|
+
* @param {number} origin_x
|
|
7
|
+
* @param {number} origin_y
|
|
8
|
+
* @param {number} origin_z
|
|
9
|
+
* @param {number} direction_x
|
|
10
|
+
* @param {number} direction_y
|
|
11
|
+
* @param {number} direction_z
|
|
12
|
+
* @param {number} px
|
|
13
|
+
* @param {number} py
|
|
14
|
+
* @param {number} pz
|
|
15
|
+
* @returns {number} distance from origin, negative means that the point lies behind the origin in the direction opposite to the ray's own
|
|
16
|
+
*/
|
|
17
|
+
export function ray_computeNearestPointToPoint(result, origin_x, origin_y, origin_z, direction_x, direction_y, direction_z, px, py, pz) {
|
|
18
|
+
// find closest point
|
|
19
|
+
const sp0_x = px - origin_x;
|
|
20
|
+
const sp0_y = py - origin_y;
|
|
21
|
+
const sp0_z = pz - origin_z;
|
|
22
|
+
|
|
23
|
+
//
|
|
24
|
+
const d2 = v3_dot(direction_x, direction_y, direction_z, direction_x, direction_y, direction_z);
|
|
25
|
+
const d3 = v3_dot(direction_x, direction_y, direction_z, sp0_x, sp0_y, sp0_z);
|
|
26
|
+
|
|
27
|
+
const t = d3 / d2;
|
|
28
|
+
|
|
29
|
+
// compute point on the ray
|
|
30
|
+
const lp_x = direction_x * t + origin_x;
|
|
31
|
+
const lp_y = direction_y * t + origin_y;
|
|
32
|
+
const lp_z = direction_z * t + origin_z;
|
|
33
|
+
|
|
34
|
+
result.set(lp_x, lp_y, lp_z);
|
|
35
|
+
|
|
36
|
+
return t;
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export class AbstractShape3D {
|
|
2
|
+
constructor() {
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {number[]} result
|
|
8
|
+
* @param {number} result_offset
|
|
9
|
+
* @param {function} random
|
|
10
|
+
*/
|
|
11
|
+
sample_random_point_in_volume(result, result_offset, random) {
|
|
12
|
+
throw new Error('Not Implemented');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether or not given point is inside the shape
|
|
17
|
+
* @param {number[]} point
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
contains_point(point) {
|
|
21
|
+
throw new Error('Not Implemented');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Total volume of the shape
|
|
26
|
+
* @returns {number}
|
|
27
|
+
*/
|
|
28
|
+
get volume() {
|
|
29
|
+
throw new Error('Not Implemented');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @returns {number}
|
|
34
|
+
*/
|
|
35
|
+
get surface_area() {
|
|
36
|
+
throw new Error('Not Implemented');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { AbstractShape3D } from "./AbstractShape3D.js";
|
|
2
|
+
import { seededRandom } from "../../../math/random/seededRandom.js";
|
|
3
|
+
import { binarySearchHighIndex } from "../../../collection/array/binarySearchHighIndex.js";
|
|
4
|
+
import { compareNumbers } from "../../../primitives/numbers/compareNumbers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* To avoid severe performance overhead, we limit number of possible rejections
|
|
8
|
+
* @type {number}
|
|
9
|
+
*/
|
|
10
|
+
const SAMPLE_REJECTION_ATTEMPT_MAX = 4;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Number of samples taken to estimate overlap level
|
|
14
|
+
* @type {number}
|
|
15
|
+
*/
|
|
16
|
+
const VOLUME_OVERLAP_ESTIMATION_TAPS = 1024;
|
|
17
|
+
const VOLUME_OVERLAP_ESTIMATION_SUB_TAPS = 4;
|
|
18
|
+
|
|
19
|
+
const scratch_array = [];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param {AbstractShape3D} shape
|
|
24
|
+
* @return {number}
|
|
25
|
+
*/
|
|
26
|
+
function getVolume(shape) {
|
|
27
|
+
return shape.volume;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class CompositeShape3D extends AbstractShape3D {
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @type {AbstractShape3D[]}
|
|
37
|
+
*/
|
|
38
|
+
this.children = [];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Estimator of how much volume is in overlap,
|
|
42
|
+
* expressed as fraction of volume occupied by overlapping region of 2 shapes over the sum of volume occupied by each child
|
|
43
|
+
* @type {number}
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
this.__volume_overlap_fraction = -1;
|
|
47
|
+
|
|
48
|
+
this.__volume_sum = -1;
|
|
49
|
+
this.__volume_sums = [];
|
|
50
|
+
this.__child_volumes = [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
__compute_volume_variables() {
|
|
54
|
+
this.__volume_sum = 0;
|
|
55
|
+
|
|
56
|
+
const children = this.children;
|
|
57
|
+
const child_count = children.length;
|
|
58
|
+
|
|
59
|
+
const child_volumes = this.__child_volumes = new Float32Array(child_count);
|
|
60
|
+
const child_volume_sums = this.__volume_sums = new Float32Array(child_count);
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < child_count; i++) {
|
|
63
|
+
const child_volume = children[i].volume;
|
|
64
|
+
|
|
65
|
+
child_volumes[i] = child_volume;
|
|
66
|
+
this.__volume_sum += child_volume;
|
|
67
|
+
|
|
68
|
+
child_volume_sums[i] = this.__volume_sum;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Monte-carlo-style volume overlap estimation
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
__estimate_volume_overlap_fraction() {
|
|
78
|
+
|
|
79
|
+
if (this.__volume_sum === -1) {
|
|
80
|
+
this.__compute_volume_variables();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const children = this.children;
|
|
84
|
+
const child_count = children.length;
|
|
85
|
+
|
|
86
|
+
const random = seededRandom(1);
|
|
87
|
+
|
|
88
|
+
const child_volume_sums = this.__volume_sums;
|
|
89
|
+
const child_volume_sum = this.__volume_sum;
|
|
90
|
+
|
|
91
|
+
let i = 0, j = 0, k = 0, tap_overlaps = 0;
|
|
92
|
+
|
|
93
|
+
for (i = 0; i < VOLUME_OVERLAP_ESTIMATION_TAPS; i++) {
|
|
94
|
+
|
|
95
|
+
const target_weight = random() * child_volume_sum;
|
|
96
|
+
|
|
97
|
+
// weighted search for a sample candidate, preferring larger volumes, resulting in more uniform sample distribution
|
|
98
|
+
const target_child_index = binarySearchHighIndex(child_volume_sums, target_weight, compareNumbers, 0, child_count - 1);
|
|
99
|
+
|
|
100
|
+
const child_0 = children[target_child_index];
|
|
101
|
+
|
|
102
|
+
for (j = 0; j < VOLUME_OVERLAP_ESTIMATION_SUB_TAPS; j++, i++) {
|
|
103
|
+
|
|
104
|
+
child_0.sample_random_point_in_volume(scratch_array, 0, random);
|
|
105
|
+
|
|
106
|
+
for (k = 0; k < child_count; k++) {
|
|
107
|
+
if (target_child_index === k) {
|
|
108
|
+
// skip self
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const child_1 = children[k];
|
|
113
|
+
|
|
114
|
+
if (child_1.contains_point(scratch_array)) {
|
|
115
|
+
tap_overlaps++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.__volume_overlap_fraction = tap_overlaps / (VOLUME_OVERLAP_ESTIMATION_TAPS);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static from(children) {
|
|
126
|
+
const r = new CompositeShape3D();
|
|
127
|
+
|
|
128
|
+
r.children = children;
|
|
129
|
+
|
|
130
|
+
return r;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
get volume() {
|
|
134
|
+
if (this.__volume_overlap_fraction < 0) {
|
|
135
|
+
this.__estimate_volume_overlap_fraction();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let volume_sum = 0;
|
|
139
|
+
|
|
140
|
+
const children = this.children;
|
|
141
|
+
const child_count = children.length;
|
|
142
|
+
|
|
143
|
+
for (let i = 0; i < child_count; i++) {
|
|
144
|
+
const child = children[i];
|
|
145
|
+
|
|
146
|
+
volume_sum += child.volume;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Unbias the volume by taking overlap into account
|
|
151
|
+
* @type {number}
|
|
152
|
+
*/
|
|
153
|
+
const unbiased_volume = volume_sum / (this.__volume_overlap_fraction + 1);
|
|
154
|
+
|
|
155
|
+
return unbiased_volume;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get surface_area() {
|
|
159
|
+
let r = 0;
|
|
160
|
+
|
|
161
|
+
const children = this.children;
|
|
162
|
+
const child_count = children.length;
|
|
163
|
+
for (let i = 0; i < child_count; i++) {
|
|
164
|
+
const child = children[i];
|
|
165
|
+
|
|
166
|
+
r += child.surface_area;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return r;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
contains_point(point) {
|
|
173
|
+
const children = this.children;
|
|
174
|
+
const n = children.length;
|
|
175
|
+
for (let i = 0; i < n; i++) {
|
|
176
|
+
const child = children[i];
|
|
177
|
+
|
|
178
|
+
if (child.contains_point(point)) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
sample_random_point_in_volume(result, result_offset, random) {
|
|
188
|
+
const children = this.children;
|
|
189
|
+
const child_count = children.length;
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
const target_weight = random() * this.__volume_sum;
|
|
193
|
+
|
|
194
|
+
// weighted search for a sample candidate, preferring larger volumes, resulting in more uniform sample distribution
|
|
195
|
+
const target_child_index = binarySearchHighIndex(this.__volume_sums, target_weight, compareNumbers, 0, child_count - 1);
|
|
196
|
+
|
|
197
|
+
const child = children[target_child_index];
|
|
198
|
+
|
|
199
|
+
let collision_count, i, j;
|
|
200
|
+
|
|
201
|
+
for (i = 0; i < SAMPLE_REJECTION_ATTEMPT_MAX; i++) {
|
|
202
|
+
|
|
203
|
+
// sample shape
|
|
204
|
+
child.sample_random_point_in_volume(result, result_offset, random);
|
|
205
|
+
|
|
206
|
+
/*
|
|
207
|
+
because underlying shapes can overlap and we wish to offer a union, just returning the sample would result in over-sampling in areas where shapes overlap
|
|
208
|
+
to avoid this oversampling, we reject samples in such areas with probability proportional to number of overlapping shapes at the sampled point
|
|
209
|
+
*/
|
|
210
|
+
collision_count = 0;
|
|
211
|
+
|
|
212
|
+
for (j = 0; j < child_count; j++) {
|
|
213
|
+
const child_1 = children[j];
|
|
214
|
+
|
|
215
|
+
if (child_1 === child) {
|
|
216
|
+
// exclude sampled child itself
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (child_1.contains_point(result)) {
|
|
221
|
+
collision_count++;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (collision_count > 0) {
|
|
226
|
+
const rejection_chance = collision_count / (collision_count + 1);
|
|
227
|
+
|
|
228
|
+
const rejection_roll = random();
|
|
229
|
+
|
|
230
|
+
if (rejection_roll < rejection_chance) {
|
|
231
|
+
//reject
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// no collisions, or survived rejection
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { mat4, vec3 } from "gl-matrix";
|
|
2
|
+
import { AbstractShape3D } from "./AbstractShape3D.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @type {number[]|Float32Array|vec3}
|
|
7
|
+
*/
|
|
8
|
+
const scratch_v3 = [];
|
|
9
|
+
|
|
10
|
+
export class TransformedShape3D extends AbstractShape3D {
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @type {number[]|Float32Array|mat4}
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
this.__matrix = new Float32Array(16);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @type {Float32Array|mat4}
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
26
|
+
this.__inverse_matrix = new Float32Array(16);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @type {AbstractShape3D|null}
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
this.__subject = null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @returns {AbstractShape3D|null}
|
|
39
|
+
*/
|
|
40
|
+
get subject() {
|
|
41
|
+
return this.__subject;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
* @param {number[]|Float32Array|mat4} m4
|
|
47
|
+
* @param {AbstractShape3D} subject
|
|
48
|
+
* @returns {TransformedShape3D}
|
|
49
|
+
*/
|
|
50
|
+
static from_m4(subject, m4) {
|
|
51
|
+
const r = new TransformedShape3D();
|
|
52
|
+
|
|
53
|
+
r.__subject = subject;
|
|
54
|
+
r.transform = m4;
|
|
55
|
+
|
|
56
|
+
return r;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* @param {AbstractShape3D} subject
|
|
62
|
+
* @param {number[]} translation
|
|
63
|
+
* @param {number[]} scale
|
|
64
|
+
*/
|
|
65
|
+
static from_translation_scale(subject, translation, scale) {
|
|
66
|
+
|
|
67
|
+
const mat = mat4.create();
|
|
68
|
+
mat4.fromRotationTranslationScale(mat, [0, 0, 0, 1], translation, scale);
|
|
69
|
+
|
|
70
|
+
return TransformedShape3D.from_m4(subject, mat);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
*
|
|
75
|
+
* @returns {TransformedShape3D}
|
|
76
|
+
* @param {AbstractShape3D} subject
|
|
77
|
+
* @param {number[]|Float32Array|vec3} scale
|
|
78
|
+
*/
|
|
79
|
+
static from_scale(subject, scale) {
|
|
80
|
+
const mat = mat4.create();
|
|
81
|
+
mat4.fromScaling(mat, scale);
|
|
82
|
+
|
|
83
|
+
return TransformedShape3D.from_m4(subject, mat);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @param {number[]|Float32Array} m
|
|
89
|
+
*/
|
|
90
|
+
set transform(m) {
|
|
91
|
+
this.__matrix.set(m);
|
|
92
|
+
|
|
93
|
+
mat4.invert(this.__inverse_matrix, this.__matrix);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get transform() {
|
|
97
|
+
return this.__matrix;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get volume() {
|
|
101
|
+
mat4.getScaling(scratch_v3, this.__matrix);
|
|
102
|
+
|
|
103
|
+
const scale_modifier = scratch_v3[0] * scratch_v3[1] * scratch_v3[2];
|
|
104
|
+
|
|
105
|
+
return this.__subject.volume * scale_modifier;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
contains_point(point) {
|
|
109
|
+
// transform point to subject's local space
|
|
110
|
+
vec3.transformMat4(scratch_v3, point, this.__inverse_matrix);
|
|
111
|
+
|
|
112
|
+
return this.__subject.contains_point(scratch_v3);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
sample_random_point_in_volume(result, result_offset, random) {
|
|
116
|
+
this.__subject.sample_random_point_in_volume(scratch_v3, 0, random);
|
|
117
|
+
|
|
118
|
+
// apply transform
|
|
119
|
+
vec3.transformMat4(scratch_v3, scratch_v3, this.__matrix);
|
|
120
|
+
|
|
121
|
+
// write out
|
|
122
|
+
result[0] = scratch_v3[0];
|
|
123
|
+
result[1] = scratch_v3[1];
|
|
124
|
+
result[2] = scratch_v3[2];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AbstractShape3D } from "./AbstractShape3D.js";
|
|
2
|
+
import { randomPointInBox } from "../../random/randomPointInBox.js";
|
|
3
|
+
|
|
4
|
+
export class UnitCubeShape3D extends AbstractShape3D {
|
|
5
|
+
|
|
6
|
+
get volume() {
|
|
7
|
+
return 1;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
contains_point(point) {
|
|
11
|
+
const x = point[0];
|
|
12
|
+
const y = point[1];
|
|
13
|
+
const z = point[2];
|
|
14
|
+
|
|
15
|
+
return x > -0.5 && x < 0.5
|
|
16
|
+
&& y > -0.5 && y < 0.5
|
|
17
|
+
&& z > -0.5 && z < 0.5
|
|
18
|
+
;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
sample_random_point_in_volume(result, result_offset, random) {
|
|
22
|
+
randomPointInBox(random, result, result_offset);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AbstractShape3D } from "./AbstractShape3D.js";
|
|
2
|
+
import { randomPointInSphere } from "../../random/randomPointInSphere.js";
|
|
3
|
+
|
|
4
|
+
export class UnitSphereShape3D extends AbstractShape3D {
|
|
5
|
+
get volume() {
|
|
6
|
+
return 0.523598776;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get surface_area() {
|
|
10
|
+
return 3.14159265;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
contains_point(point) {
|
|
14
|
+
const x = point[0];
|
|
15
|
+
const y = point[1];
|
|
16
|
+
const z = point[2];
|
|
17
|
+
|
|
18
|
+
return (x * x + y * y + z * z) < 1;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
sample_random_point_in_volume(result, result_offset, random) {
|
|
22
|
+
randomPointInSphere(random, result, result_offset);
|
|
23
|
+
}
|
|
24
|
+
}
|