Example #1
0
        public void RemoveSeries(string name)
        {
            var index = IndexOf(name);

            if (index >= 0)
            {
                graphSeries.RemoveAt(index);
            }
            else
            {
                throw new ArgumentException("No series with the given name exists within the graph.");
            }
        }
Example #2
0
        public override void Update(double dt)
        {
            RigidTransform transform       = new RigidTransform(mesh.Position);
            RigidTransform convexTransform = convex.WorldTransform;

            ContactRefresher.ContactRefresh(contacts, supplementData, ref convexTransform, ref transform, contactIndicesToRemove);
            RemoveQueuedContacts();
            var overlaps = new QuickList <Vector3i>(BufferPools <Vector3i> .Thread);

            mesh.ChunkShape.GetOverlaps(mesh.Position, convex.BoundingBox, ref overlaps);
            var candidatesToAdd = new QuickList <ContactData>(BufferPools <ContactData> .Thread, BufferPool <int> .GetPoolIndex(overlaps.Count));

            for (int i = 0; i < overlaps.Count; i++)
            {
                if (!ActivePairs.TryGetValue(overlaps.Elements[i], out GeneralConvexPairTester manifold))
                {
                    manifold = GetPair(ref overlaps.Elements[i]);
                }
                else
                {
                    ActivePairs.FastRemove(overlaps.Elements[i]);
                }
                activePairsBackBuffer.Add(overlaps.Elements[i], manifold);
                if (manifold.GenerateContactCandidate(out ContactData contactCandidate))
                {
                    candidatesToAdd.Add(ref contactCandidate);
                }
            }
            overlaps.Dispose();
            for (int i = ActivePairs.Count - 1; i >= 0; i--)
            {
                ReturnPair(ActivePairs.Values[i]);
                ActivePairs.FastRemove(ActivePairs.Keys[i]);
            }
            var temp = ActivePairs;

            ActivePairs           = activePairsBackBuffer;
            activePairsBackBuffer = temp;
            if (contacts.Count + candidatesToAdd.Count > 4)
            {
                var reducedCandidates = new QuickList <ContactData>(BufferPools <ContactData> .Thread, 3);
                ContactReducer.ReduceContacts(contacts, ref candidatesToAdd, contactIndicesToRemove, ref reducedCandidates);
                RemoveQueuedContacts();
                for (int i = reducedCandidates.Count - 1; i >= 0; i--)
                {
                    Add(ref reducedCandidates.Elements[i]);
                    reducedCandidates.RemoveAt(i);
                }
                reducedCandidates.Dispose();
            }
            else if (candidatesToAdd.Count > 0)
            {
                for (int i = 0; i < candidatesToAdd.Count; i++)
                {
                    Add(ref candidatesToAdd.Elements[i]);
                }
            }
            candidatesToAdd.Dispose();
        }
Example #3
0
    public T Fetch()
    {
        if (pool.Count > 0)
        {
            var t = pool[pool.Count - 1];
            pool.RemoveAt(pool.Count - 1);

            return(t);
        }
        else
        {
            return(new T());
        }
    }
Example #4
0
        internal static void PruneAsset <T>(T asset)
        {
            switch (asset)
            {
            case Texture2D texture: {
                for (int i = 0; i < LookupArray.Count; i++)
                {
                    Texture2D existingTexture = LookupArray.Array[i].Texture;

                    // Compare name and ContentManager to check for equality.
                    if (existingTexture.Name == texture.Name && existingTexture.ContentManager == texture.ContentManager)
                    {
                        drawCallDictionary.Remove(LookupArray.Array[i]);
                        LookupArray.RemoveAt(i);
                    }
                }
                break;
            }

            case Effect effect: {
                for (int i = 0; i < LookupArray.Count; i++)
                {
                    Effect existingEffect = LookupArray.Array[i].Effect;

                    // Compare name and ContentManager to check for equality.
                    if (existingEffect.Name == effect.Name && existingEffect.ContentManager == effect.ContentManager)
                    {
                        drawCallDictionary.Remove(LookupArray.Array[i]);
                        LookupArray.RemoveAt(i);
                    }
                }
                break;
            }
            }

            // TODO: Regenerate lookup dictionary.
        }
        public static void TestListResizing(IUnmanagedMemoryPool pool)
        {
            Random     random      = new Random(5);
            var        list        = new QuickList <int>(4, pool);
            List <int> controlList = new List <int>();

            for (int iterationIndex = 0; iterationIndex < 100000; ++iterationIndex)
            {
                if (random.NextDouble() < 0.7)
                {
                    list.Add(iterationIndex, pool);
                    controlList.Add(iterationIndex);
                }
                if (random.NextDouble() < 0.2)
                {
                    var indexToRemove = random.Next(list.Count);
                    list.RemoveAt(indexToRemove);
                    controlList.RemoveAt(indexToRemove);
                }
                if (iterationIndex % 1000 == 0)
                {
                    list.EnsureCapacity(list.Count * 3, pool);
                }
                else if (iterationIndex % 7777 == 0)
                {
                    list.Compact(pool);
                }
            }

            Debug.Assert(list.Count == controlList.Count);
            for (int i = 0; i < list.Count; ++i)
            {
                var a = list[i];
                var b = controlList[i];
                Debug.Assert(a == b);
                Debug.Assert(list.Count == controlList.Count);
            }

            list.Dispose(pool);
        }
Example #6
0
        public static void TestListResizing()
        {
            Random random = new Random(5);
            UnsafeBufferPool <int> pool        = new UnsafeBufferPool <int>();
            QuickList <int>        list        = new QuickList <int>(pool, 2);
            List <int>             controlList = new List <int>();

            for (int iterationIndex = 0; iterationIndex < 100000; ++iterationIndex)
            {
                if (random.NextDouble() < 0.7)
                {
                    list.Add(iterationIndex);
                    controlList.Add(iterationIndex);
                }
                if (random.NextDouble() < 0.2)
                {
                    var indexToRemove = random.Next(list.Count);
                    list.RemoveAt(indexToRemove);
                    controlList.RemoveAt(indexToRemove);
                }
                if (iterationIndex % 1000 == 0)
                {
                    list.EnsureCapacity(list.Count * 3);
                }
                else if (iterationIndex % 7777 == 0)
                {
                    list.Compact();
                }
            }

            Assert.IsTrue(list.Count == controlList.Count);
            for (int i = 0; i < list.Count; ++i)
            {
                var a = list[i];
                var b = controlList[i];
                Assert.IsTrue(a == b);
                Assert.IsTrue(list.Count == controlList.Count);
            }
        }
Example #7
0
 public override void Update(double dt)
 {
     RigidTransform transform = new RigidTransform(mesh.Position);
     RigidTransform convexTransform = convex.WorldTransform;
     ContactRefresher.ContactRefresh(contacts, supplementData, ref convexTransform, ref transform, contactIndicesToRemove);
     RemoveQueuedContacts();
     var overlaps = new QuickList<Vector3i>(BufferPools<Vector3i>.Thread);
     mesh.ChunkShape.GetOverlaps(mesh.Position, convex.BoundingBox, ref overlaps);
     var candidatesToAdd = new QuickList<ContactData>(BufferPools<ContactData>.Thread, BufferPool<int>.GetPoolIndex(overlaps.Count));
     for (int i = 0; i < overlaps.Count; i++)
     {
         GeneralConvexPairTester manifold;
         if (!ActivePairs.TryGetValue(overlaps.Elements[i], out manifold))
         {
             manifold = GetPair(ref overlaps.Elements[i]);
         }
         else
         {
             ActivePairs.FastRemove(overlaps.Elements[i]);
         }
         activePairsBackBuffer.Add(overlaps.Elements[i], manifold);
         ContactData contactCandidate;
         if (manifold.GenerateContactCandidate(out contactCandidate))
         {
             candidatesToAdd.Add(ref contactCandidate);
         }
     }
     overlaps.Dispose();
     for (int i = ActivePairs.Count - 1; i >= 0; i--)
     {
         ReturnPair(ActivePairs.Values[i]);
         ActivePairs.FastRemove(ActivePairs.Keys[i]);
     }
     var temp = ActivePairs;
     ActivePairs = activePairsBackBuffer;
     activePairsBackBuffer = temp;
     if (contacts.Count + candidatesToAdd.Count > 4)
     {
         var reducedCandidates = new QuickList<ContactData>(BufferPools<ContactData>.Thread, 3);
         ContactReducer.ReduceContacts(contacts, ref candidatesToAdd, contactIndicesToRemove, ref reducedCandidates);
         RemoveQueuedContacts();
         for (int i = reducedCandidates.Count - 1; i >= 0; i--)
         {
             Add(ref reducedCandidates.Elements[i]);
             reducedCandidates.RemoveAt(i);
         }
         reducedCandidates.Dispose();
     }
     else if (candidatesToAdd.Count > 0)
     {
         for (int i = 0; i < candidatesToAdd.Count; i++)
         {
             Add(ref candidatesToAdd.Elements[i]);
         }
     }
     candidatesToAdd.Dispose();
 }
Example #8
0
		public override void Update( float dt )
		{
			//Refresh the contact manifold for this frame.
			var transform = new RigidTransform( voxelBlob.Position );
			var convexTransform = convex.WorldTransform;
			ContactRefresher.ContactRefresh( contacts, supplementData, ref convexTransform, ref transform, contactIndicesToRemove );
			RemoveQueuedContacts();

			//Collect the set of overlapped cell indices.
			//Not the fastest way to do this, but it's relatively simple and easy.
			var overlaps = new QuickList<Int3>( BufferPools<Int3>.Thread );
			voxelBlob.Shape.GetOverlaps( voxelBlob.Position, convex.BoundingBox, ref overlaps );

			var candidatesToAdd = new QuickList<ContactData>( BufferPools<ContactData>.Thread, BufferPool<int>.GetPoolIndex( overlaps.Count ) );
			for( int i = 0; i < overlaps.Count; ++i )
			{
				GeneralConvexPairTester manifold;
				if( !ActivePairs.TryGetValue( overlaps.Elements[i], out manifold ) )
				{
					//This manifold did not previously exist.
					manifold = GetPair( ref overlaps.Elements[i] );
				}
				else
				{
					//It did previously exist.
					ActivePairs.FastRemove( overlaps.Elements[i] );
				}
				activePairsBackBuffer.Add( overlaps.Elements[i], manifold );
				ContactData contactCandidate;
				if( manifold.GenerateContactCandidate( out contactCandidate ) )
				{

					candidatesToAdd.Add( ref contactCandidate );
				}
			}
			overlaps.Dispose();
			//Any pairs remaining in the activePairs set no longer exist. Clean them up.
			for( int i = ActivePairs.Count - 1; i >= 0; --i )
			{
				ReturnPair( ActivePairs.Values[i] );
				ActivePairs.FastRemove( ActivePairs.Keys[i] );
			}
			//Swap the pair sets.
			var temp = ActivePairs;
			ActivePairs = activePairsBackBuffer;
			activePairsBackBuffer = temp;

			//Check if adding the new contacts would overflow the manifold.
			if( contacts.Count + candidatesToAdd.Count > 4 )
			{
				//Adding all the contacts would overflow the manifold.  Reduce to the best subset.
				var reducedCandidates = new QuickList<ContactData>( BufferPools<ContactData>.Thread, 3 );
				ContactReducer.ReduceContacts( contacts, ref candidatesToAdd, contactIndicesToRemove, ref reducedCandidates );
				RemoveQueuedContacts();
				for( int i = reducedCandidates.Count - 1; i >= 0; i-- )
				{
					Add( ref reducedCandidates.Elements[i] );
					reducedCandidates.RemoveAt( i );
				}
				reducedCandidates.Dispose();
			}
			else if( candidatesToAdd.Count > 0 )
			{
				//Won't overflow the manifold, so just toss it in.
				for( int i = 0; i < candidatesToAdd.Count; i++ )
				{
					Add( ref candidatesToAdd.Elements[i] );
				}
			}


			candidatesToAdd.Dispose();

		}
Example #9
0
        ///<summary>
        /// Updates the manifold.
        ///</summary>
        ///<param name="dt">Timestep duration.</param>
        public override void Update(float dt)
        {
            //First, refresh all existing contacts.  This is an incremental manifold.
            var transform = MeshTransform;

            ContactRefresher.ContactRefresh(contacts, supplementData, ref convex.worldTransform, ref transform, contactIndicesToRemove);

            RemoveQueuedContacts();


            CleanUpOverlappingTriangles();
            //Get all the overlapped triangle indices.
            //Note that the collection of triangles is left up to the child implementation.
            //We're basically treating the child class like an indexable collection.
            //A little gross to have it organized this way instead of an explicit collection to separate the logic up. Would be nice to improve someday!
            int triangleCount = FindOverlappingTriangles(dt);

            //Just use 32 elements for all the lists and sets in this system.
            const int    bufferPoolSizePower = 5;
            BoundarySets boundarySets;

            if (UseImprovedBoundaryHandling)
            {
                boundarySets = new BoundarySets(bufferPoolSizePower);
            }
            else
            {
                boundarySets = new BoundarySets();
            }

            var candidatesToAdd = new QuickList <ContactData>(BufferPools <ContactData> .Thread, bufferPoolSizePower);

            //A single triangle shape will be reused for all operations. It's pulled from a thread local pool to avoid holding a TriangleShape around for every single contact manifold or pair tester.
            var localTriangleShape = PhysicsThreadResources.GetTriangle();

            //Precompute the transform to take triangles from their native local space to the convex's local space.
            RigidTransform inverseConvexWorldTransform;

            RigidTransform.Invert(ref convex.worldTransform, out inverseConvexWorldTransform);
            AffineTransform convexInverseWorldTransform;

            AffineTransform.CreateFromRigidTransform(ref inverseConvexWorldTransform, out convexInverseWorldTransform);
            AffineTransform fromMeshLocalToConvexLocal;

            PrecomputeTriangleTransform(ref convexInverseWorldTransform, out fromMeshLocalToConvexLocal);

            //Grab the convex's local space bounding box up front. This will be used for a secondary pruning step.
            BoundingBox convexLocalBoundingBox;

            convex.Shape.GetBoundingBox(ref Toolbox.RigidIdentity, out convexLocalBoundingBox);

            Matrix3x3 orientation;

            Matrix3x3.CreateFromQuaternion(ref convex.worldTransform.Orientation, out orientation);
            var guaranteedContacts = 0;

            for (int i = 0; i < triangleCount; i++)
            {
                //Initialize the local triangle.
                TriangleIndices indices;
                if (ConfigureLocalTriangle(i, localTriangleShape, out indices))
                {
                    //Put the triangle into the local space of the convex.
                    AffineTransform.Transform(ref localTriangleShape.vA, ref fromMeshLocalToConvexLocal, out localTriangleShape.vA);
                    AffineTransform.Transform(ref localTriangleShape.vB, ref fromMeshLocalToConvexLocal, out localTriangleShape.vB);
                    AffineTransform.Transform(ref localTriangleShape.vC, ref fromMeshLocalToConvexLocal, out localTriangleShape.vC);

                    //Do one last AABB test between the convex and triangle in the convex's local space.
                    //This can prune out a lot of triangles when dealing with larger objects, and it's pretty cheap to do.
                    BoundingBox triangleBoundingBox;
                    Toolbox.GetTriangleBoundingBox(ref localTriangleShape.vA, ref localTriangleShape.vB, ref localTriangleShape.vC, out triangleBoundingBox);

                    bool intersecting;
                    triangleBoundingBox.Intersects(ref convexLocalBoundingBox, out intersecting);
                    if (!intersecting)
                    {
                        continue;
                    }

                    //Find a pairtester for the triangle.
                    TrianglePairTester pairTester;
                    if (!activePairTesters.TryGetValue(indices, out pairTester))
                    {
                        pairTester = GetTester();
                        pairTester.Initialize(convex.Shape);
                        activePairTesters.Add(indices, pairTester);
                    }
                    pairTester.Updated = true;


                    //Now, generate a contact between the two shapes.
                    TinyStructList <ContactData> contactList;
                    if (pairTester.GenerateContactCandidates(localTriangleShape, out contactList))
                    {
                        for (int j = 0; j < contactList.Count; j++)
                        {
                            ContactData contact;
                            contactList.Get(j, out contact);


                            if (UseImprovedBoundaryHandling)
                            {
                                if (AnalyzeCandidate(ref indices, localTriangleShape, pairTester, ref contact, ref boundarySets))
                                {
                                    //This is let through if there's a face contact. Face contacts cannot be blocked.
                                    guaranteedContacts++;
                                    AddLocalContact(ref contact, ref orientation, ref candidatesToAdd);
                                }
                            }
                            else
                            {
                                AddLocalContact(ref contact, ref orientation, ref candidatesToAdd);
                            }
                        }
                    }

                    //Get the voronoi region from the contact candidate generation.  Possibly just recalculate, since most of the systems don't calculate it.
                    //Depending on which voronoi region it is in (Switch on enumeration), identify the indices composing that region.  For face contacts, don't bother- just add it if unique.
                    //For AB, AC, or BC, add an Edge to the blockedEdgeRegions set with the corresponding indices.
                    //For A, B, or C, add the index of the vertex to the blockedVertexRegions set.
                    //If the edge/vertex is already present in the set, then DO NOT add the contact.
                    //When adding a contact, add ALL other voronoi regions to the blocked sets.
                }
            }



            if (UseImprovedBoundaryHandling)
            {
                //If there were no face contacts that absolutely must be included, we may get into a very rare situation
                //where absolutely no contacts get created.  For example, a sphere falling directly on top of a vertex in a flat terrain.
                //It will generally get locked out of usage by belonging only to restricted regions (numerical issues make it visible by both edges and vertices).
                //In some cases, the contacts will be ignored instead of corrected (e.g. spheres).
                //To prevent objects from just falling through the ground in such a situation, force-correct the contacts regardless of the pair tester's desires.
                //Sure, it might not be necessary under normal circumstances, but it's a better option than having no contacts.
                //TODO: There is another option: Changing restricted regions so that a vertex only restricts the other two vertices and the far edge,
                //and an edge only restricts the far vertex and other two edges.  This introduces an occasional bump though...

                //It's possible, in very specific instances, for an object to wedge itself between two adjacent triangles.
                //For this state to continue beyond a brief instant generally requires the object be orientation locked and slender.
                //However, some characters fit this description, so it can't be ignored!

                //Conceptually, this issue can occur at either a vertex junction or a shared edge (usually on extremely flat surfaces only).
                //However, an object stuck between multiple triangles is not in a stable state.  In the edge case, the object gets shoved to one side
                //as one contact 'wins' the solver war.  That's not enough to escape, unfortunately.
                //The vertex case, on the other hand, is degenerate and decays into an edge case rapidly thanks to this lack of stability.
                //So, we don't have to explicitly handle the somewhat more annoying and computationally expensive vertex unstucking case, because the edge case handles both! :)

                //This isn't a completely free operation, but it's guarded behind pretty rare conditions.
                //Essentially, we will check to see if there's just edge contacts fighting against each other.
                //If they are, then we will correct any stuck-contributing normals to the triangle normal.
                if (boundarySets.VertexContacts.Count == 0 && guaranteedContacts == 0 && boundarySets.EdgeContacts.Count > 1)
                {
                    //There are only edge contacts, check to see if:
                    //all normals are coplanar, and
                    //at least one normal faces against the other normals (meaning it's probably stuck, as opposed to just colliding on a corner).

                    bool allNormalsInSamePlane   = true;
                    bool atLeastOneNormalAgainst = false;

                    var firstNormal = boundarySets.EdgeContacts.Elements[0].ContactData.Normal;
                    boundarySets.EdgeContacts.Elements[0].CorrectedNormal.Normalize();
                    float dot;
                    Vector3Ex.Dot(ref firstNormal, ref boundarySets.EdgeContacts.Elements[0].CorrectedNormal, out dot);
                    if (Math.Abs(dot) > .01f)
                    {
                        //Go ahead and test the first contact separately, since we're using its contact normal to determine coplanarity.
                        allNormalsInSamePlane = false;
                    }
                    else
                    {
                        //TODO: Note that we're only checking the new edge contacts, not the existing contacts.
                        //It's possible that some existing contacts could interfere and cause issues, but for the sake of simplicity and due to rarity
                        //we'll ignore that possibility for now.
                        for (int i = 1; i < boundarySets.EdgeContacts.Count; i++)
                        {
                            Vector3Ex.Dot(ref boundarySets.EdgeContacts.Elements[i].ContactData.Normal, ref firstNormal, out dot);
                            if (dot < 0)
                            {
                                atLeastOneNormalAgainst = true;
                            }
                            //Check to see if the normal is outside the plane.
                            Vector3Ex.Dot(ref boundarySets.EdgeContacts.Elements[i].ContactData.Normal, ref boundarySets.EdgeContacts.Elements[0].CorrectedNormal, out dot);

                            if (Math.Abs(dot) > .01f)
                            {
                                //We are not stuck!
                                allNormalsInSamePlane = false;
                                break;
                            }
                        }
                    }

                    if (allNormalsInSamePlane && atLeastOneNormalAgainst)
                    {
                        //Uh oh! all the normals are parallel... The object is probably in a weird situation.
                        //Let's correct the normals!

                        //Already normalized the first contact above.
                        //We don't need to perform the perpendicularity test here- we did that before! We know it's perpendicular already.
                        boundarySets.EdgeContacts.Elements[0].ContactData.Normal = boundarySets.EdgeContacts.Elements[0].CorrectedNormal;
                        boundarySets.EdgeContacts.Elements[0].ShouldCorrect      = true;

                        for (int i = 1; i < boundarySets.EdgeContacts.Count; i++)
                        {
                            //Must normalize the corrected normal before using it.
                            boundarySets.EdgeContacts.Elements[i].CorrectedNormal.Normalize();
                            Vector3Ex.Dot(ref boundarySets.EdgeContacts.Elements[i].CorrectedNormal, ref boundarySets.EdgeContacts.Elements[i].ContactData.Normal, out dot);
                            if (dot < .01)
                            {
                                //Only bother doing the correction if the normal appears to be pointing nearly horizontally- implying that it's a contributor to the stuckness!
                                //If it's blocked, the next section will use the corrected normal- if it's not blocked, the next section will use the direct normal.
                                //Make them the same thing :)
                                boundarySets.EdgeContacts.Elements[i].ContactData.Normal = boundarySets.EdgeContacts.Elements[i].CorrectedNormal;
                                boundarySets.EdgeContacts.Elements[i].ShouldCorrect      = true;
                                //Note that the penetration depth is NOT corrected.  The contact's depth no longer represents the true depth.
                                //However, we only need to have some penetration depth to get the object to escape the rut.
                                //Furthermore, the depth computed from the horizontal opposing contacts is known to be less than the depth in the perpendicular direction.
                                //If the current depth was NOT less than the true depth along the corrected normal, then the collision detection system
                                //would have picked a different depth, as it finds a reasonable approximation of the minimum penetration!
                                //As a consequence, this contact will not be active beyond the object's destuckification, because its contact depth will be negative (or very close to it).
                            }
                        }
                    }
                }



                for (int i = 0; i < boundarySets.EdgeContacts.Count; i++)
                {
                    //Only correct if it's allowed AND it's blocked.
                    //If it's not blocked, the contact being created is necessary!
                    //The normal generated by the triangle-convex tester is already known not to
                    //violate the triangle sidedness.
                    if (!boundarySets.BlockedEdgeRegions.Contains(boundarySets.EdgeContacts.Elements[i].Edge))
                    {
                        //If it's not blocked, use the contact as-is without correcting it.
                        AddLocalContact(ref boundarySets.EdgeContacts.Elements[i].ContactData, ref orientation, ref candidatesToAdd);
                    }
                    else if (boundarySets.EdgeContacts.Elements[i].ShouldCorrect || guaranteedContacts == 0)
                    {
                        //If it is blocked, we can still make use of the contact.  But first, we need to change the contact normal to ensure that
                        //it will not interfere (and cause a bump or something).
                        float dot;
                        boundarySets.EdgeContacts.Elements[i].CorrectedNormal.Normalize();
                        Vector3Ex.Dot(ref boundarySets.EdgeContacts.Elements[i].CorrectedNormal, ref boundarySets.EdgeContacts.Elements[i].ContactData.Normal, out dot);
                        boundarySets.EdgeContacts.Elements[i].ContactData.Normal            = boundarySets.EdgeContacts.Elements[i].CorrectedNormal;
                        boundarySets.EdgeContacts.Elements[i].ContactData.PenetrationDepth *= MathHelper.Max(0, dot); //Never cause a negative penetration depth.
                        AddLocalContact(ref boundarySets.EdgeContacts.Elements[i].ContactData, ref orientation, ref candidatesToAdd);
                    }
                    //If it's blocked AND it doesn't allow correction, ignore its existence.
                }



                for (int i = 0; i < boundarySets.VertexContacts.Count; i++)
                {
                    if (!boundarySets.BlockedVertexRegions.Contains(boundarySets.VertexContacts.Elements[i].Vertex))
                    {
                        //If it's not blocked, use the contact as-is without correcting it.
                        AddLocalContact(ref boundarySets.VertexContacts.Elements[i].ContactData, ref orientation, ref candidatesToAdd);
                    }
                    else if (boundarySets.VertexContacts.Elements[i].ShouldCorrect || guaranteedContacts == 0)
                    {
                        //If it is blocked, we can still make use of the contact.  But first, we need to change the contact normal to ensure that
                        //it will not interfere (and cause a bump or something).
                        float dot;
                        boundarySets.VertexContacts.Elements[i].CorrectedNormal.Normalize();
                        Vector3Ex.Dot(ref boundarySets.VertexContacts.Elements[i].CorrectedNormal, ref boundarySets.VertexContacts.Elements[i].ContactData.Normal, out dot);
                        boundarySets.VertexContacts.Elements[i].ContactData.Normal            = boundarySets.VertexContacts.Elements[i].CorrectedNormal;
                        boundarySets.VertexContacts.Elements[i].ContactData.PenetrationDepth *= MathHelper.Max(0, dot); //Never cause a negative penetration depth.
                        AddLocalContact(ref boundarySets.VertexContacts.Elements[i].ContactData, ref orientation, ref candidatesToAdd);
                    }
                    //If it's blocked AND it doesn't allow correction, ignore its existence.
                }


                boundarySets.Dispose();
            }



            //Remove stale pair testers.
            for (int i = activePairTesters.Count - 1; i >= 0; --i)
            {
                var tester = activePairTesters.Values[i];
                if (!tester.Updated)
                {
                    tester.CleanUp();
                    GiveBackTester(tester);
                    activePairTesters.FastRemove(activePairTesters.Keys[i]);
                }
                else
                {
                    tester.Updated = false;
                }
            }

            //Some child types will want to do some extra post processing on the manifold.
            ProcessCandidates(ref candidatesToAdd);


            //Check if adding the new contacts would overflow the manifold.
            if (contacts.Count + candidatesToAdd.Count > 4)
            {
                //Adding all the contacts would overflow the manifold.  Reduce to the best subset.
                var reducedCandidates = new QuickList <ContactData>(BufferPools <ContactData> .Thread, bufferPoolSizePower);
                ContactReducer.ReduceContacts(contacts, ref candidatesToAdd, contactIndicesToRemove, ref reducedCandidates);
                RemoveQueuedContacts();
                for (int i = reducedCandidates.Count - 1; i >= 0; i--)
                {
                    Add(ref reducedCandidates.Elements[i]);
                    reducedCandidates.RemoveAt(i);
                }
                reducedCandidates.Dispose();
            }
            else if (candidatesToAdd.Count > 0)
            {
                //Won't overflow the manifold, so just toss it in PROVIDED that it isn't too close to something else.
                for (int i = 0; i < candidatesToAdd.Count; i++)
                {
                    Add(ref candidatesToAdd.Elements[i]);
                }
            }


            PhysicsThreadResources.GiveBack(localTriangleShape);
            candidatesToAdd.Dispose();
        }
        public override void Update(float dt)
        {
            //Refresh the contact manifold for this frame.
            var transform       = new RigidTransform(voxelGrid.Position);
            var convexTransform = convex.WorldTransform;

            ContactRefresher.ContactRefresh(contacts, supplementData, ref convexTransform, ref transform, contactIndicesToRemove);
            RemoveQueuedContacts();

            //Collect the set of overlapped cell indices.
            //Not the fastest way to do this, but it's relatively simple and easy.
            var overlaps = new QuickList <Int3>(BufferPools <Int3> .Thread);

            voxelGrid.Shape.GetOverlaps(voxelGrid.Position, convex.BoundingBox, ref overlaps);

            var candidatesToAdd = new QuickList <ContactData>(BufferPools <ContactData> .Thread, BufferPool <int> .GetPoolIndex(overlaps.Count));

            for (int i = 0; i < overlaps.Count; ++i)
            {
                GeneralConvexPairTester manifold;
                if (!ActivePairs.TryGetValue(overlaps.Elements[i], out manifold))
                {
                    //This manifold did not previously exist.
                    manifold = GetPair(ref overlaps.Elements[i]);
                }
                else
                {
                    //It did previously exist.
                    ActivePairs.FastRemove(overlaps.Elements[i]);
                }
                activePairsBackBuffer.Add(overlaps.Elements[i], manifold);
                ContactData contactCandidate;
                if (manifold.GenerateContactCandidate(out contactCandidate))
                {
                    candidatesToAdd.Add(ref contactCandidate);
                }
            }
            overlaps.Dispose();
            //Any pairs remaining in the activePairs set no longer exist. Clean them up.
            for (int i = ActivePairs.Count - 1; i >= 0; --i)
            {
                ReturnPair(ActivePairs.Values[i]);
                ActivePairs.FastRemove(ActivePairs.Keys[i]);
            }
            //Swap the pair sets.
            var temp = ActivePairs;

            ActivePairs           = activePairsBackBuffer;
            activePairsBackBuffer = temp;

            //Check if adding the new contacts would overflow the manifold.
            if (contacts.Count + candidatesToAdd.Count > 4)
            {
                //Adding all the contacts would overflow the manifold.  Reduce to the best subset.
                var reducedCandidates = new QuickList <ContactData>(BufferPools <ContactData> .Thread, 3);
                ContactReducer.ReduceContacts(contacts, ref candidatesToAdd, contactIndicesToRemove, ref reducedCandidates);
                RemoveQueuedContacts();
                for (int i = reducedCandidates.Count - 1; i >= 0; i--)
                {
                    Add(ref reducedCandidates.Elements[i]);
                    reducedCandidates.RemoveAt(i);
                }
                reducedCandidates.Dispose();
            }
            else if (candidatesToAdd.Count > 0)
            {
                //Won't overflow the manifold, so just toss it in.
                for (int i = 0; i < candidatesToAdd.Count; i++)
                {
                    Add(ref candidatesToAdd.Elements[i]);
                }
            }


            candidatesToAdd.Dispose();
        }
Example #11
0
        public override void Update(Window window, Camera camera, Input input, float dt)
        {
            base.Update(window, camera, input, dt);
            #region  KeyInput

            //Delete all boxes;
            if (input.WasPushed(Key.Z))
            {
                for (var i = _createdObjects.Count - 1; i > 0; --i)
                {
                    var bodiIndex = _createdObjects[i];
                    var reference = new BodyReference(bodiIndex, Simulation.Bodies);
                    if (reference.LocalInertia.InverseMass > 0)
                    {
                        Simulation.Bodies.Remove(bodiIndex);
                        _createdObjects.RemoveAt(i);
                    }
                }
            }

            if (input.WasPushed(Key.X))
            {
                for (var j = 0; j < _numberOfLevels; j++)
                {
                    var startPosition = new Vector3(0, _floorHeight * j, _verticalHalfLenght * j);
                    for (int i = 0; i < _numberOfLoops * 2; i++)
                    {
                        CreateBoxes(startPosition);
                        startPosition.Z += _verticalHalfLenght * 2;
                    }
                }
            }
            var random = new Random(Guid.NewGuid().GetHashCode());


            //Randomly destroy
            if (input.WasPushed(Key.C))
            {
                for (var i = _createdObjects.Count - 1; i > 0; --i)
                {
                    var bodiIndex = _createdObjects[i];
                    var reference = new BodyReference(bodiIndex, Simulation.Bodies);
                    if ((reference.LocalInertia.InverseMass > 0) && random.Next(100) > 50)
                    {
                        Simulation.Bodies.Remove(bodiIndex);
                        _createdObjects.RemoveAt(i);
                    }
                }
            }

            _spawnCount += dt;
            if (_spawnCount >= _spawnTime)
            {
                _spawnCount -= _spawnTime;
                var boxPosition = new Vector3(-_horizontalHalfLenght + 1, 2, 0);
                var identity    = Quaternion.Identity;
                Instantiate(_boxDescription, ref boxPosition, ref identity);



                var deleteObject = random.Next(_createdObjects.Count - 1);
                var reference    = new BodyReference(deleteObject, Simulation.Bodies);
                if ((reference.LocalInertia.InverseMass > 0))
                {
                    Simulation.Bodies.Remove(deleteObject);
                    _createdObjects.Remove(deleteObject);
                }
            }


            for (var i = 0; i < _movingObjects.Count; i++)
            {
                ref var movingObject = ref _movingObjects[i];


                if (movingObject.IsMoving)
                {
                    var bodyReference  = new BodyReference(movingObject.BodyIndex, Simulation.Bodies);
                    var targetPosition = movingObject.StartPosition;
                    if (movingObject.IsMovingToOffset)
                    {
                        targetPosition += MovingOffset;
                    }

                    var linearError = targetPosition - bodyReference.Pose.Position;

                    if (linearError.LengthSquared() < .0001f)
                    {
                        bodyReference.Velocity.Linear = Vector3.Zero;
                        movingObject.IsMoving         = false;
                        movingObject.IsMovingToOffset = !movingObject.IsMovingToOffset;
                    }
                    else
                    {
                        var linearVelocity = linearError / dt;
                        bodyReference.Velocity.Linear = linearVelocity;
                        Simulation.Awakener.AwakenBody(bodyReference.Handle);
                    }
                }
                else
                {
                    movingObject.ToggleSleepTimer += dt;
                    if (movingObject.ToggleSleepTimer > SleepTime)
                    {
                        movingObject.ToggleSleepTimer = SleepTime * (float)random.NextDouble();
                        movingObject.IsMoving         = true;
                    }
                }
            }
Example #12
0
 public void RemoveQuickList()
 {
     quickList.RemoveAt(0);
 }
        public static void TestListResizing()
        {
            Random random = new Random(5);
            UnsafeBufferPool<int> pool = new UnsafeBufferPool<int>();
            QuickList<int> list = new QuickList<int>(pool, 2);
            List<int> controlList = new List<int>();

            for (int iterationIndex = 0; iterationIndex < 100000; ++iterationIndex)
            {
                if (random.NextDouble() < 0.7)
                {
                    list.Add(iterationIndex);
                    controlList.Add(iterationIndex);
                }
                if (random.NextDouble() < 0.2)
                {
                    var indexToRemove = random.Next(list.Count);
                    list.RemoveAt(indexToRemove);
                    controlList.RemoveAt(indexToRemove);
                }
                if (iterationIndex % 1000 == 0)
                {
                    list.EnsureCapacity(list.Count * 3);
                }
                else if (iterationIndex % 7777 == 0)
                {
                    list.Compact();
                }
            }

            Assert.IsTrue(list.Count == controlList.Count);
            for (int i = 0; i < list.Count; ++i)
            {
                var a = list[i];
                var b = controlList[i];
                Assert.IsTrue(a == b);
                Assert.IsTrue(list.Count == controlList.Count);
            }
        }