Beispiel #1
0
        // Resets the simulation storage
        // - Reallocates input velocities storage if necessary
        // - Disposes event streams and allocates new ones with a single work item
        // NOTE: Reset or ScheduleReset needs to be called before passing the SimulationContext
        // to a simulation step job. If you don't then you may get initialization errors.
        public void Reset(ref PhysicsWorld world)
        {
            m_Bodies = world.Bodies;

            int numDynamicBodies = world.NumDynamicBodies;

            if (InputVelocities.Length < numDynamicBodies)
            {
                if (InputVelocities.IsCreated)
                {
                    InputVelocities.Dispose();
                }
                InputVelocities = new NativeArray <Velocity>(numDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            }

            if (CollisionEventDataStream.IsCreated)
            {
                CollisionEventDataStream.Dispose();
            }
            if (TriggerEventDataStream.IsCreated)
            {
                TriggerEventDataStream.Dispose();
            }

            {
                if (!WorkItemCount.IsCreated)
                {
                    WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent);
                }
                CollisionEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Persistent);
                TriggerEventDataStream   = new NativeStream(WorkItemCount[0], Allocator.Persistent);
            }
        }
        protected override void OnDestroy()
        {
            base.OnDestroy();

            if (_effectStream.IsCreated)
            {
                _effectStream.Dispose(Dependency);
            }
            if (_effects.IsCreated)
            {
                _effects.Dispose(Dependency);
            }
        }
        // Resets the simulation storage
        // - Reallocates input velocities storage if necessary
        // - Disposes event streams and allocates new ones with a single work item
        // NOTE: Reset or ScheduleReset needs to be called before passing the SimulationContext
        // to a simulation step job. If you don't then you may get initialization errors.
        public void Reset(SimulationStepInput stepInput)
        {
            m_NumDynamicBodies = stepInput.World.NumDynamicBodies;
            if (!m_InputVelocities.IsCreated || m_InputVelocities.Length < m_NumDynamicBodies)
            {
                if (m_InputVelocities.IsCreated)
                {
                    m_InputVelocities.Dispose();
                }
                m_InputVelocities = new NativeArray <Velocity>(m_NumDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            }

            // Solver stabilization data
            if (stepInput.SolverStabilizationHeuristicSettings.EnableSolverStabilization)
            {
                if (!m_SolverStabilizationMotionData.IsCreated || m_SolverStabilizationMotionData.Length < m_NumDynamicBodies)
                {
                    if (m_SolverStabilizationMotionData.IsCreated)
                    {
                        m_SolverStabilizationMotionData.Dispose();
                    }
                    m_SolverStabilizationMotionData = new NativeArray <Solver.StabilizationMotionData>(m_NumDynamicBodies, Allocator.Persistent, NativeArrayOptions.ClearMemory);
                }
                else if (m_NumDynamicBodies > 0)
                {
                    unsafe
                    {
                        UnsafeUtility.MemClear(m_SolverStabilizationMotionData.GetUnsafePtr(), m_NumDynamicBodies * UnsafeUtility.SizeOf <Solver.StabilizationMotionData>());
                    }
                }
            }

            if (CollisionEventDataStream.IsCreated)
            {
                CollisionEventDataStream.Dispose();
            }
            if (TriggerEventDataStream.IsCreated)
            {
                TriggerEventDataStream.Dispose();
            }

            {
                if (!WorkItemCount.IsCreated)
                {
                    WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent);
                }
                CollisionEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Persistent);
                TriggerEventDataStream   = new NativeStream(WorkItemCount[0], Allocator.Persistent);
            }
        }
Beispiel #4
0
    public void ToArray([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
    {
        var stream   = new NativeStream(count, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };

        fillInts.Schedule(count, batchSize).Complete();

        var array     = stream.ToNativeArray <int>(Allocator.Temp);
        int itemIndex = 0;

        for (int i = 0; i != count; ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                Assert.AreEqual(j, array[itemIndex]);
                itemIndex++;
            }
        }

        array.Dispose();

        stream.Dispose();
    }
Beispiel #5
0
 public void Dispose()
 {
     if (m_Stream.IsCreated)
     {
         m_Stream.Dispose();
     }
 }
 public void Dispose()
 {
     if (NativeStream.IsCreated)
     {
         NativeStream.Dispose();
     }
 }
Beispiel #7
0
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            if (m_CharacterControllersGroup.CalculateEntityCount() == 0)
            {
                return(inputDeps);
            }

            var chunks = m_CharacterControllersGroup.CreateArchetypeChunkArray(Allocator.TempJob);

            var characterMoveType   = GetArchetypeChunkComponentType <CharacterMoveSetting>();
            var userCommandType     = GetArchetypeChunkComponentType <UserCommand>();
            var movePredictedType   = GetArchetypeChunkComponentType <CharacterMovePredictedState>();
            var transformType       = GetArchetypeChunkComponentType <TransformPredictedState>();
            var velocityType        = GetArchetypeChunkComponentType <VelocityPredictedState>();
            var physicsColliderType = GetArchetypeChunkComponentType <PhysicsCollider>();
            var entityType          = GetArchetypeChunkEntityType();

            var deferredImpulses = new NativeStream(chunks.Length, Allocator.TempJob);
            var tickDuration     = GetSingleton <WorldTime>().TickDuration;
            var ccJob            = new CharacterControllerJob
            {
                EntityType = entityType,
                // Archetypes
                CharacterMoveType          = characterMoveType,
                UserCommandComponentType   = userCommandType,
                CharacterMovePredictedType = movePredictedType,
                PhysicsColliderType        = physicsColliderType,
                TransformType = transformType,
                VelocityType  = velocityType,

                // Input
                DeltaTime             = tickDuration,
                PhysicsWorld          = m_BuildPhysicsWorldSystem.PhysicsWorld,
                DeferredImpulseWriter = deferredImpulses.AsWriter()
            };

            inputDeps = JobHandle.CombineDependencies(inputDeps, m_ExportPhysicsWorldSystem.FinalJobHandle);
            inputDeps = ccJob.Schedule(m_CharacterControllersGroup, inputDeps);

            var applyJob = new ApplyDefferedPhysicsUpdatesJob
            {
                Chunks = chunks,
                DeferredImpulseReader      = deferredImpulses.AsReader(),
                PhysicsMassData            = GetComponentDataFromEntity <PhysicsMass>(),
                TransformPredictedData     = GetComponentDataFromEntity <TransformPredictedState>(),
                VelocityPredictedData      = GetComponentDataFromEntity <VelocityPredictedState>(),
                CharacterMovePredictedData = GetComponentDataFromEntity <CharacterMovePredictedState>()
            };

            inputDeps = applyJob.Schedule(inputDeps);
            var disposeHandle = deferredImpulses.Dispose(inputDeps);

            disposeHandle.Complete();

            // Must finish all jobs before physics step end
            //  m_EndFramePhysicsSystem.HandlesToWaitFor.Add(disposeHandle);

            return(inputDeps);
        }
Beispiel #8
0
    public void WriteWithoutBeginThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        Assert.Throws <ArgumentException>(() => writer.Write(5));

        stream.Dispose();
    }
Beispiel #9
0
    public void OutOfBoundsWriteThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        Assert.Throws <ArgumentException>(() => writer.BeginForEachIndex(-1));
        Assert.Throws <ArgumentException>(() => writer.BeginForEachIndex(2));

        stream.Dispose();
    }
    protected override void OnUpdate()
    {
        if (m_CharacterControllersGroup.CalculateEntityCount() == 0)
        {
            return;
        }

        var chunks = m_CharacterControllersGroup.CreateArchetypeChunkArray(Allocator.TempJob);

        var ccComponentType          = GetComponentTypeHandle <CharacterControllerComponentData>();
        var ccInternalType           = GetComponentTypeHandle <CharacterControllerInternalData>();
        var physicsColliderType      = GetComponentTypeHandle <PhysicsCollider>();
        var translationType          = GetComponentTypeHandle <Translation>();
        var rotationType             = GetComponentTypeHandle <Rotation>();
        var collisionEventBufferType = GetBufferTypeHandle <StatefulCollisionEvent>();
        var triggerEventBufferType   = GetBufferTypeHandle <StatefulTriggerEvent>();

        var deferredImpulses = new NativeStream(chunks.Length, Allocator.TempJob);

        var ccJob = new CharacterControllerJob
        {
            // Archetypes
            CharacterControllerComponentType = ccComponentType,
            CharacterControllerInternalType  = ccInternalType,
            PhysicsColliderType      = physicsColliderType,
            TranslationType          = translationType,
            RotationType             = rotationType,
            CollisionEventBufferType = collisionEventBufferType,
            TriggerEventBufferType   = triggerEventBufferType,

            // Input
            DeltaTime             = UnityEngine.Time.fixedDeltaTime,
            PhysicsWorld          = m_BuildPhysicsWorldSystem.PhysicsWorld,
            DeferredImpulseWriter = deferredImpulses.AsWriter()
        };

        Dependency = JobHandle.CombineDependencies(Dependency, m_ExportPhysicsWorldSystem.GetOutputDependency());
        Dependency = ccJob.Schedule(m_CharacterControllersGroup, Dependency);

        var applyJob = new ApplyDefferedPhysicsUpdatesJob()
        {
            Chunks = chunks,
            DeferredImpulseReader = deferredImpulses.AsReader(),
            PhysicsVelocityData   = GetComponentDataFromEntity <PhysicsVelocity>(),
            PhysicsMassData       = GetComponentDataFromEntity <PhysicsMass>(),
            TranslationData       = GetComponentDataFromEntity <Translation>(),
            RotationData          = GetComponentDataFromEntity <Rotation>()
        };

        Dependency = applyJob.Schedule(Dependency);
        var disposeHandle = deferredImpulses.Dispose(Dependency);

        // Must finish all jobs before physics step end
        m_EndFramePhysicsSystem.AddInputDependency(disposeHandle);
    }
Beispiel #11
0
    public void UnbalancedBeginThrows()
    {
        var stream = new NativeStream(2, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);
        // Missing EndForEachIndex();
        Assert.Throws <ArgumentException>(() => writer.BeginForEachIndex(1));

        stream.Dispose();
    }
Beispiel #12
0
    public void CreateAndDestroy([Values(1, 100, 200)] int count)
    {
        var stream = new NativeStream(count, Allocator.Temp);

        Assert.IsTrue(stream.IsCreated);
        Assert.IsTrue(stream.ForEachCount == count);
        Assert.IsTrue(stream.ComputeItemCount() == 0);

        stream.Dispose();
        Assert.IsFalse(stream.IsCreated);
    }
Beispiel #13
0
        public void JacobianIteratorHasJacobiansLeftTest()
        {
            var jacobianStream = new NativeStream(1, Allocator.Temp);

            NativeStream.Reader jacobianStreamReader = jacobianStream.AsReader();
            int workItemIndex = 0;
            var jacIterator   = new JacobianIterator(jacobianStreamReader, workItemIndex);

            Assert.IsFalse(jacIterator.HasJacobiansLeft());

            jacobianStream.Dispose();
        }
Beispiel #14
0
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        if (m_CharacterControllersGroup.CalculateEntityCount() == 0)
        {
            return(inputDeps);
        }

        var chunks = m_CharacterControllersGroup.CreateArchetypeChunkArray(Allocator.TempJob);

        var ccComponentType     = GetArchetypeChunkComponentType <CharacterControllerComponentData>();
        var ccInternalType      = GetArchetypeChunkComponentType <CharacterControllerInternalData>();
        var physicsColliderType = GetArchetypeChunkComponentType <PhysicsCollider>();
        var translationType     = GetArchetypeChunkComponentType <Translation>();
        var rotationType        = GetArchetypeChunkComponentType <Rotation>();

        var deferredImpulses = new NativeStream(chunks.Length, Allocator.TempJob);

        var ccJob = new CharacterControllerJob
        {
            // Archetypes
            CharacterControllerComponentType = ccComponentType,
            CharacterControllerInternalType  = ccInternalType,
            PhysicsColliderType = physicsColliderType,
            TranslationType     = translationType,
            RotationType        = rotationType,
            // Input
            DeltaTime             = UnityEngine.Time.fixedDeltaTime,
            cameraWorldPoint      = mainCamera.ScreenToWorldPoint(Input.mousePosition),
            PhysicsWorld          = m_BuildPhysicsWorldSystem.PhysicsWorld,
            DeferredImpulseWriter = deferredImpulses.AsWriter()
        };

        inputDeps = JobHandle.CombineDependencies(inputDeps, m_ExportPhysicsWorldSystem.FinalJobHandle);
        inputDeps = ccJob.Schedule(m_CharacterControllersGroup, inputDeps);

        var applyJob = new ApplyDefferedPhysicsUpdatesJob()
        {
            Chunks = chunks,
            DeferredImpulseReader = deferredImpulses.AsReader(),
            PhysicsVelocityData   = GetComponentDataFromEntity <PhysicsVelocity>(),
            PhysicsMassData       = GetComponentDataFromEntity <PhysicsMass>(),
            TranslationData       = GetComponentDataFromEntity <Translation>(),
            RotationData          = GetComponentDataFromEntity <Rotation>()
        };

        inputDeps = applyJob.Schedule(inputDeps);
        var disposeHandle = deferredImpulses.Dispose(inputDeps);

        // Must finish all jobs before physics step end
        m_EndFramePhysicsSystem.HandlesToWaitFor.Add(disposeHandle);

        return(inputDeps);
    }
            public void Dispose()
            {
                if (PixelData.IsCreated)
                {
                    PixelData.Dispose();
                }

                //reset isCreated
                PixelData   = default;
                m_Assigned  = false;
                m_JobHandle = default;
            }
Beispiel #16
0
    public void ItemCount([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
    {
        var stream   = new NativeStream(count, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };

        fillInts.Schedule(count, batchSize).Complete();

        Assert.AreEqual(count * (count - 1) / 2, stream.ComputeItemCount());

        stream.Dispose();
    }
    public void ItemCount([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
    {
        var stream   = new NativeStream(count, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };

        fillInts.Schedule(count, batchSize).Complete();

        ExpectedCount(ref stream, count * (count - 1) / 2);

        stream.Dispose();
    }
Beispiel #18
0
    public void WriteAfterEndThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);
        writer.Write(2);
        writer.EndForEachIndex();

        Assert.Throws <ArgumentException>(() => writer.Write(5));

        stream.Dispose();
    }
Beispiel #19
0
    public void DisposeAfterSchedule()
    {
        var stream   = new NativeStream(100, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };
        var writerJob = fillInts.Schedule(100, 16);

        var disposeJob = stream.Dispose(writerJob);

        Assert.IsFalse(stream.IsCreated);

        disposeJob.Complete();
    }
Beispiel #20
0
    public void ParallelWriteThrows()
    {
        var stream   = new NativeStream(100, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };

        var writerJob = fillInts.Schedule(100, 16);

        Assert.Throws <InvalidOperationException>(() => fillInts.Schedule(100, 16));

        writerJob.Complete();
        stream.Dispose();
    }
Beispiel #21
0
    public void WriteManagedThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);

        Assert.Throws <ArgumentException>(() =>
        {
            writer.Write(new ManagedRef());
        });

        stream.Dispose();
    }
Beispiel #22
0
        // Schedule jobs to build Jacobians from the contacts stored in the simulation context
        internal static SimulationJobHandles ScheduleBuildJacobiansJobs(ref PhysicsWorld world, float timeStep, float3 gravity,
                                                                        int numSolverIterations, JobHandle inputDeps, ref NativeList <DispatchPairSequencer.DispatchPair> dispatchPairs,
                                                                        ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo,
                                                                        ref NativeStream contacts, ref NativeStream jacobians, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                returnHandles.FinalExecutionHandle = new BuildJacobiansJob
                {
                    ContactsReader      = contacts.AsReader(),
                    JacobiansWriter     = jacobians.AsWriter(),
                    TimeStep            = timeStep,
                    Gravity             = gravity,
                    NumSolverIterations = numSolverIterations,
                    World               = world,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo
                }.Schedule(inputDeps);
            }
            else
            {
                var buildJob = new BuildJacobiansJob
                {
                    ContactsReader      = contacts.AsReader(),
                    JacobiansWriter     = jacobians.AsWriter(),
                    TimeStep            = timeStep,
                    InvTimeStep         = timeStep > 0.0f ? 1.0f / timeStep : 0.0f,
                    GravityAcceleration = math.length(gravity),
                    NumSolverIterations = numSolverIterations,
                    World               = world,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo
                };

                JobHandle handle = buildJob.ScheduleUnsafeIndex0(solverSchedulerInfo.NumWorkItems, 1, inputDeps);

                returnHandles.FinalDisposeHandle = JobHandle.CombineDependencies(
                    dispatchPairs.Dispose(handle),
                    contacts.Dispose(handle));
                returnHandles.FinalExecutionHandle = handle;
            }

            return(returnHandles);
        }
Beispiel #23
0
    public void PopulateInts([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
    {
        var stream   = new NativeStream(count, Allocator.TempJob);
        var fillInts = new WriteInts {
            Writer = stream.AsWriter()
        };
        var jobHandle = fillInts.Schedule(count, batchSize);

        var compareInts = new ReadInts {
            Reader = stream.AsReader()
        };
        var res0 = compareInts.Schedule(count, batchSize, jobHandle);
        var res1 = compareInts.Schedule(count, batchSize, jobHandle);

        res0.Complete();
        res1.Complete();

        stream.Dispose();
    }
Beispiel #24
0
    public void CopyWriterByValueThrows()
    {
        var stream = new NativeStream(1, Allocator.Temp);
        var writer = stream.AsWriter();

        writer.BeginForEachIndex(0);

        Assert.Throws <ArgumentException>(() =>
        {
            var writerCopy = writer;
            writerCopy.Write(5);
        });

        Assert.Throws <ArgumentException>(() =>
        {
            var writerCopy = writer;
            writerCopy.BeginForEachIndex(1);
            writerCopy.Write(5);
        });

        stream.Dispose();
    }
        public void TreeOverlapPerfTest(int elementCount, bool newOverlap)
        {
            // Execute dummy job just to get Burst compilation out of the way.
            {
                var dummyStream  = new NativeStream(1, Allocator.TempJob);
                var dummyNodes   = new NativeArray <Node>(0, Allocator.TempJob);
                var dummyFilters = new NativeArray <CollisionFilter>(0, Allocator.TempJob);
                new TestTreeOverlapJob
                {
                    CollisionPairWriter = dummyStream.AsWriter(),
                    Nodes      = dummyNodes,
                    Filter     = dummyFilters,
                    NumObjects = 0,
                    DummyRun   = true
                }.Run();
                dummyStream.Dispose();
                dummyNodes.Dispose();
                dummyFilters.Dispose();
            }

            elementCount *= 2;
            int numNodes = elementCount / 3 * 2 + 4;
            var points   = new NativeArray <PointAndIndex>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var aabbs    = new NativeArray <Aabb>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var filters  = new NativeArray <CollisionFilter>(elementCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            // Override filter data with default filters.
            for (int i = 0; i < filters.Length; i++)
            {
                filters[i] = CollisionFilter.Default;
            }

            InitInputWithCopyArrays(points, aabbs, filters);

            var nodes = new NativeArray <Node>(numNodes, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            var bvh = new BoundingVolumeHierarchy(nodes);

            bvh.Build(points, aabbs, out int numNodesOut);
            bvh.CheckIntegrity();

            var collisionPairs = new NativeStream(1, Allocator.TempJob);

            var job = new TestTreeOverlapJob
            {
                Nodes               = nodes,
                Filter              = filters,
                NumObjects          = elementCount,
                CollisionPairWriter = collisionPairs.AsWriter(),
                DummyRun            = false
            };

            Measure.Method(() =>
            {
                job.Run();
            }).MeasurementCount(1)
            .Run();

            points.Dispose();
            aabbs.Dispose();
            nodes.Dispose();
            collisionPairs.Dispose();
            filters.Dispose();
        }
        public unsafe void OverlapTaskFilteringTest([Values(2, 10, 33, 100)] int elementCount)
        {
            elementCount *= 2;
            int numNodes = elementCount + Constants.MaxNumTreeBranches;

            var points      = new NativeArray <PointAndIndex>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var aabbs       = new NativeArray <Aabb>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var bodyFilters = new NativeArray <CollisionFilter>(elementCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

            InitInputWithCopyArrays(points, aabbs, bodyFilters);

            var   nodes    = new NativeArray <Node>(numNodes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            Node *nodesPtr = (Node *)nodes.GetUnsafePtr();

            var seenUnfiltered = new HashSet <BodyIndexPair>();
            {
                var bvhUnfiltered = new BoundingVolumeHierarchy(nodes);
                bvhUnfiltered.Build(points, aabbs, out int numNodesOut);
                bvhUnfiltered.CheckIntegrity();

                EverythingWriter pairWriter = new EverythingWriter {
                    SeenPairs = seenUnfiltered
                };
                BoundingVolumeHierarchy.TreeOverlap(ref pairWriter, nodesPtr, nodesPtr);
            }

            var nodeFilters = new NativeArray <CollisionFilter>(numNodes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var bvhFiltered = new BoundingVolumeHierarchy(nodes, nodeFilters);
            int numNodesFilteredTree;

            bvhFiltered.Build(points, aabbs, out numNodesFilteredTree);
            bvhFiltered.BuildCombinedCollisionFilter(bodyFilters, 0, numNodesFilteredTree - 1);

            var filteredCollisionPairs = new NativeStream(1, Allocator.TempJob);

            NativeStream.Writer filteredPairWriter = filteredCollisionPairs.AsWriter();
            filteredPairWriter.BeginForEachIndex(0);
            CollisionFilter *bodyFiltersPtr = (CollisionFilter *)bodyFilters.GetUnsafePtr();
            var bufferedPairs = new Broadphase.BodyPairWriter(&filteredPairWriter, bodyFiltersPtr, bodyFiltersPtr, 0, 0);

            CollisionFilter *nodeFiltersPtr = (CollisionFilter *)nodeFilters.GetUnsafePtr();

            BoundingVolumeHierarchy.TreeOverlap(ref bufferedPairs, nodesPtr, nodesPtr, nodeFiltersPtr, nodeFiltersPtr);
            bufferedPairs.Close();
            filteredPairWriter.EndForEachIndex();

            NativeStream.Reader filteredPairReader = filteredCollisionPairs.AsReader();
            filteredPairReader.BeginForEachIndex(0);

            // Check that every pair in our filtered set also appears in the unfiltered set
            while (filteredPairReader.RemainingItemCount > 0)
            {
                var pair = filteredPairReader.Read <BodyIndexPair>();

                Assert.IsTrue(seenUnfiltered.Contains(pair));
                seenUnfiltered.Remove(pair); // Remove the pair
            }

            // Pairs were removed, so the only remaining ones should be filtered
            foreach (BodyIndexPair pair in seenUnfiltered)
            {
                bool shouldCollide = CollisionFilter.IsCollisionEnabled(bodyFilters[pair.BodyIndexA], bodyFilters[pair.BodyIndexB]);
                Assert.IsFalse(shouldCollide);
            }

            nodeFilters.Dispose();
            nodes.Dispose();
            bodyFilters.Dispose();
            aabbs.Dispose();
            points.Dispose();
            filteredCollisionPairs.Dispose();
        }
        public unsafe void BuildTreeAndOverlapTasks([Values(2, 10, 33, 100)] int elementCount)
        {
            const int threadCount = 8;

            elementCount *= 2;

            var tree = new Broadphase.Tree(elementCount);

            var points      = new NativeArray <PointAndIndex>(elementCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var aabbs       = new NativeArray <Aabb>(elementCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var branchCount = new NativeArray <int>(1, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            InitInputWithCopyArrays(points, aabbs, tree.BodyFilters);

            // Override filter data with default filters.
            for (int i = 0; i < tree.BodyFilters.Length; i++)
            {
                tree.BodyFilters[i] = CollisionFilter.Default;
            }

            for (int i = 0; i < tree.NodeFilters.Length; i++)
            {
                tree.NodeFilters[i] = CollisionFilter.Default;
            }

            var branchNodeOffset = new NativeArray <int>(Constants.MaxNumTreeBranches, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var shouldDoWork     = new NativeArray <int>(1, Allocator.Persistent);

            shouldDoWork[0] = 1;
            NativeArray <int> oldBranchCount = new NativeArray <int>(1, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            JobHandle handle = new BuildFirstNLevelsJob
            {
                Points            = points,
                Nodes             = (Node *)tree.Nodes.GetUnsafePtr(),
                Ranges            = tree.Ranges,
                BranchNodeOffsets = branchNodeOffset,
                BranchCount       = branchCount,
                OldBranchCount    = oldBranchCount,
                ThreadCount       = threadCount,
                ShouldDoWork      = shouldDoWork
            }.Schedule();

            handle = new BuildBranchesJob
            {
                Points            = points,
                Aabbs             = aabbs,
                BodyFilters       = tree.BodyFilters,
                Nodes             = (Node *)tree.Nodes.GetUnsafePtr(),
                Ranges            = tree.Ranges,
                BranchNodeOffsets = branchNodeOffset,
                BranchCount       = branchCount
            }.ScheduleUnsafeIndex0(branchCount, 1, handle);

            new FinalizeTreeJob
            {
                Aabbs             = aabbs,
                LeafFilters       = tree.BodyFilters,
                Nodes             = (Node *)tree.Nodes.GetUnsafePtr(),
                BranchNodeOffsets = branchNodeOffset,
                NumNodes          = tree.Nodes.Length,
                BranchCount       = branchCount,
                ShouldDoWork      = shouldDoWork,
                OldBranchCount    = oldBranchCount
            }.Schedule(handle).Complete();

            int numBranchOverlapPairs = branchCount[0] * (branchCount[0] + 1) / 2;
            var nodePairIndices       = new NativeList <int2>(Allocator.TempJob);

            nodePairIndices.ResizeUninitialized(numBranchOverlapPairs);
            var collisionPairs = new NativeStream(numBranchOverlapPairs, Allocator.TempJob);

            handle = new Broadphase.DynamicVsDynamicBuildBranchNodePairsJob
            {
                Ranges          = tree.Ranges,
                NumBranches     = branchCount,
                NodePairIndices = nodePairIndices
            }.Schedule();

            handle = new Broadphase.DynamicVsDynamicFindOverlappingPairsJob
            {
                DynamicTree     = tree,
                NodePairIndices = nodePairIndices,
                PairWriter      = collisionPairs.AsWriter()
            }.Schedule(nodePairIndices, numBranchOverlapPairs, handle);

            handle.Complete();

            int numPairs = collisionPairs.Count();

            Assert.AreEqual(elementCount / 2, numPairs);
            //Debug.Log($"Num colliding pairs: {numPairs}");

            tree.BoundingVolumeHierarchy.CheckIntegrity();

            nodePairIndices.Dispose();
            tree.Dispose();
            collisionPairs.Dispose();
            branchCount.Dispose();
            shouldDoWork.Dispose();
        }
 public void Dispose()
 {
     NativeStream.Dispose();
 }
        protected unsafe override void OnUpdate()
        {
            var    contexts     = new NativeList <UIContextData>(8, Allocator.TempJob);
            var    graphData    = new NativeList <UIGraphData>(8, Allocator.TempJob);
            Entity schemaEntity = Entity.Null;
            int    nodeCount    = 0;

            meshes.Clear();
            Entities.ForEach((UIObject obj) =>
            {
                //TODO: Writes every conversion frame but will crash under certain conditions otherwise. Crashes observed involving opening and closing subscenes without modifying anything after script reload.

                var guid = obj.model?.GetOutputGuid();

                if (!string.IsNullOrEmpty(guid))
                {
                    IntPtr ptr;
                    long allocatedLength;
                    using (var fs = File.OpenRead(UnityEditor.AssetDatabase.GUIDToAssetPath(guid))) {
                        allocatedLength = math.ceilpow2(fs.Length);
                        ptr             = (IntPtr)UnsafeUtility.Malloc(allocatedLength, 0, Allocator.Persistent);
                        using (var us = new UnmanagedMemoryStream((byte *)ptr.ToPointer(), 0, fs.Length, FileAccess.Write)) {
                            fs.CopyTo(us);
                        }
                    }
                    var gd = new UIGraphData {
                        value = ptr, allocatedLength = allocatedLength
                    };
                    graphData.Add(gd);
                    nodeCount += gd.GetNodeCount();
                    contexts.Add(UIContextData.CreateContext(obj.camera));
                    meshes.Add(new Mesh());
                    if (schemaEntity == Entity.Null)
                    {
                        schemaEntity = CreateAdditionalEntity(obj);
                        DstEntityManager.SetName(schemaEntity, "UI Schema");
                        DstEntityManager.AddSharedComponentData(schemaEntity, new UISchemaData {
                            value = schema
                        });
                    }
                    DeclareAssetDependency(obj.gameObject, schema);
                }
                obj.cachedGuid = guid;
            });

            if (graphData.Length > 0)
            {
                var graphDataArray = graphData.AsArray();
                var meshData       = Mesh.AllocateWritableMeshData(graphData.Length);
                var submeshes      = new NativeArray <int>(graphData.Length, Allocator.TempJob);
                var stream         = new NativeStream(nodeCount, Allocator.TempJob);
                new UILayoutJob
                {
                    schema        = compiledSchema,
                    graphs        = graphDataArray,
                    contexts      = contexts,
                    meshDataArray = meshData
                }.Schedule(graphData.Length, 1).Complete();
                new UINodeDecompositionJob
                {
                    schema       = compiledSchema,
                    graphs       = graphDataArray,
                    nodes        = stream.AsWriter(),
                    submeshCount = submeshes
                }.Schedule(graphData.Length, 1).Complete();
                Mesh.ApplyAndDisposeWritableMeshData(meshData, meshes);
                var result = stream.ToNativeArray <DedicatedNodeInfo>(Allocator.Temp);
                var nodes  = new NativeMultiHashMap <int, DedicatedNodeInfo>(graphData.Length, Allocator.Temp);
                for (int i = 0; i < result.Length; i++)
                {
                    nodes.Add(result[i].graphIndex, result[i]);
                }
                stream.Dispose();
                submeshes.Dispose();
                int index        = 0;
                var nodeEntities = new NativeList <Entity>(Allocator.Temp);
                Entities.ForEach((UIObject obj) =>
                {
                    if (!string.IsNullOrEmpty(obj.cachedGuid))
                    {
                        var entity = GetPrimaryEntity(obj);
                        var gd     = graphDataArray[index];
                        DstEntityManager.AddComponentData(entity, new UIGraph {
                            value = new BlittableAssetReference(obj.cachedGuid)
                        });
                        DstEntityManager.AddSharedComponentData <UIDirtyState>(entity, false);
                        Material material;
                        if (gd.TryGetConfigBlock(0, UIConfigLayoutTable.MaterialConfig, out IntPtr result))
                        {
                            material = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(UnityEditor.AssetDatabase.GUIDToAssetPath(((MaterialConfig *)(result.ToPointer()))->material.ToHex()));
                        }
                        else
                        {
                            material = obj.model.GetMaterial();
                        }



                        DeclareAssetDependency(obj.gameObject, obj.model);


                        DeclareAssetDependency(obj.gameObject, material);

                        DstEntityManager.AddSharedComponentData(entity, new RenderMesh
                        {
                            mesh                 = meshes[index],
                            material             = material,
                            subMesh              = 0,
                            castShadows          = ShadowCastingMode.Off,
                            receiveShadows       = false,
                            needMotionVectorPass = false,
                            layer                = obj.gameObject.layer
                        });
                        DstEntityManager.AddComponentData(entity, new UIPixelScale {
                            value = obj.pixelScale
                        });
                        var bounds = meshes[index].GetSubMesh(0).bounds.ToAABB();
                        DstEntityManager.AddComponentData(entity, new RenderBounds {
                            Value = bounds
                        });

                        DstEntityManager.AddComponent <UIContext>(entity);

                        if (obj.camera != null)
                        {
                            DstEntityManager.AddComponentData(entity, new UIContextSource {
                                value = GetPrimaryEntity(obj.camera)
                            });
                            var ltc = new LocalToCamera
                            {
                                cameraLTW = obj.camera.transform.localToWorldMatrix,
                                clipPlane = new float2(obj.camera.nearClipPlane, obj.camera.farClipPlane),
                                alignment = obj.alignment,
                                offsetX   = obj.offsetX,
                                offsetY   = obj.offsetY
                            };
                            DstEntityManager.AddComponentData(entity, ltc);
                            var rotation  = quaternion.LookRotation(ltc.cameraLTW.c2.xyz, ltc.cameraLTW.c1.xyz);
                            var translate = ltc.cameraLTW.c3.xyz + new float3(ltc.alignment.GetOffset(bounds.Size.xy, new float2(Screen.currentResolution.height * obj.camera.aspect, Screen.currentResolution.height)), 0) + math.mul(rotation, math.forward() * ltc.clipPlane.x * 2f) + (math.mul(rotation, math.right()) * ltc.offsetX.Normalize(contexts[index])) + (math.mul(rotation, math.up()) * ltc.offsetY.Normalize(contexts[index]));
                            DstEntityManager.SetComponentData(entity, new LocalToWorld {
                                Value = float4x4.TRS(translate, rotation, obj.pixelScale)
                            });
                            DeclareDependency(obj, obj.camera);
                        }

                        DstEntityManager.AddComponent <PerInstanceCullingTag>(entity);

                        nodeEntities.Clear();
                        var nodeInfoIter = nodes.GetValuesForKey(index);
                        while (nodeInfoIter.MoveNext())
                        {
                            var nodeInfo   = nodeInfoIter.Current;
                            var nodeEntity = CreateAdditionalEntity(obj);
                            var name       = graphData[index].GetNodeName(nodeInfo.nodeIndex);
                            if (string.IsNullOrEmpty(name))
                            {
                                name = $"Node#{nodeInfo.nodeIndex}";
                            }
                            DstEntityManager.SetName(nodeEntity, $"{DstEntityManager.GetName(entity)}[{name}]");
                            DstEntityManager.AddComponentData(nodeEntity, new UINodeInfo {
                                index = nodeInfo.nodeIndex, submesh = nodeInfo.submesh
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new UIParent {
                                value = entity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new Parent {
                                Value = entity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new LocalToWorld {
                                Value = float4x4.identity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new Rotation {
                                Value = quaternion.identity
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new Scale {
                                Value = 1f
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new LocalToParent {
                                Value = float4x4.identity
                            });
                            if (gd.TryGetConfigBlock(0, UIConfigLayoutTable.MaterialConfig, out result))
                            {
                                material = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(UnityEditor.AssetDatabase.GUIDToAssetPath(((MaterialConfig *)result.ToPointer())->material.ToHex()));
                            }
                            else
                            {
                                material = obj.model.GetMaterial();
                            }
                            DstEntityManager.AddSharedComponentData(nodeEntity, new RenderMesh
                            {
                                mesh                 = meshes[index],
                                material             = material,
                                subMesh              = nodeInfo.submesh,
                                castShadows          = ShadowCastingMode.Off,
                                receiveShadows       = false,
                                needMotionVectorPass = false,
                                layer                = obj.gameObject.layer
                            });
                            DstEntityManager.AddComponentData(nodeEntity, new RenderBounds {
                                Value = meshes[index].GetSubMesh(nodeInfo.submesh).bounds.ToAABB()
                            });
                            DstEntityManager.AddComponent <PerInstanceCullingTag>(nodeEntity);
                            nodeEntities.Add(nodeEntity);
                            ConfigureEditorRenderData(nodeEntity, obj.gameObject, true);
                        }
                        var buffer = DstEntityManager.AddBuffer <UINode>(entity);
                        buffer.AddRange(nodeEntities.AsArray().Reinterpret <UINode>());
                        UnsafeUtility.Free(graphData[index].value.ToPointer(), Allocator.TempJob);
                        index++;
                        ConfigureEditorRenderData(entity, obj.gameObject, true);
                    }
                });
            }

            contexts.Dispose();
            graphData.Dispose();
        }
 public void Dispose()
 {
     PixelData.Dispose();
     // setting default will reset PixelData.IsCreated
     PixelData = default;
 }