Code/HumanoidRetargeter/Core/Formats/Mmd/Bullet/BulletCollision/SimpleBroadphase.cs

A C# implementation of a simple broadphase collision manager (part of a Bullet physics port). It manages a fixed pool of SimpleBroadphaseProxy handles, creates/destroys proxies, tests AABB overlaps, builds overlapping pairs in a pair cache, and provides simple ray/AABB query iteration.

NetworkingFile AccessProcess ExecutionNative InteropObfuscated CodeEncoded DataExternal DownloadCredential AccessSelf Modifying CodeHttp Calls
/*
 * C# / XNA  port of Bullet (c) 2011 Mark Neale <[email protected]>
 *
 * Bullet Continuous Collision Detection and Physics Library
 * Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */
// Adapted from BulletXNA 73b2e1b9: namespace isolation, no XNA rendering, one type per file.
#nullable disable
#pragma warning disable CS1591, CS0168, CS0219, CS0414, CS0660, CS0661, CS0659, CS0693, CS8981, CS0108, CS0114
using System;
using System.Collections.Generic;
using System.Diagnostics;
using HumanoidRetargeter.Core.Formats.Mmd.Bullet.LinearMath;

namespace HumanoidRetargeter.Core.Formats.Mmd.Bullet.BulletCollision;

internal class SimpleBroadphase : IBroadphaseInterface
{
	public SimpleBroadphase(int maxProxies, IOverlappingPairCache overlappingPairCache)
	{
		if (overlappingPairCache == null)
		{
			overlappingPairCache = new HashedOverlappingPairCache();
			m_ownsPairCache = true;
		}

		m_pHandles = new SimpleBroadphaseProxy[maxProxies];
		m_pairCache = overlappingPairCache;
		m_maxHandles = maxProxies;
		m_numHandles = 0;
		m_firstFreeHandle = 0;
		m_LastHandleIndex = -1;
		for (int i = m_firstFreeHandle; i < maxProxies; i++)
		{
			m_pHandles[i] = new SimpleBroadphaseProxy(i);
			m_pHandles[i].SetNextFree(i + 1);
			m_pHandles[i].m_uniqueId = ++m_proxyCounter;
			; //any UID will do, we just avoid too trivial values (0,1) for debugging purposes
		}

		m_pHandles[maxProxies - 1].SetNextFree(0);
	}

	public virtual void Cleanup()
	{
		for (int i = 0; i < m_pHandles.Length; ++i)
		{
			if (m_pHandles[i] != null)
			{
				m_pHandles[i].Cleanup();
			}

			m_pHandles[i] = null;
		}

		if (m_ownsPairCache)
		{
			m_pairCache.Cleanup();
			m_pairCache = null;
			m_ownsPairCache = false;
		}
	}

	public static bool AabbOverlap(SimpleBroadphaseProxy proxy0, SimpleBroadphaseProxy proxy1)
	{
		IndexedVector3 p0Min = proxy0.GetMinAABB();
		IndexedVector3 p0Max = proxy0.GetMaxAABB();
		IndexedVector3 p1Min = proxy1.GetMinAABB();
		IndexedVector3 p1Max = proxy1.GetMaxAABB();
		return p0Min.X <= p1Max.X && p1Min.X <= p0Max.X && p0Min.Y <= p1Max.Y && p1Min.Y <= p0Max.Y && p0Min.Z <= p1Max.Z && p1Min.Z <= p0Max.Z;
	}

	private int AllocHandle()
	{
		{
		}

		int freeHandle = m_firstFreeHandle;
		m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree();
		m_numHandles++;
		if (freeHandle > m_LastHandleIndex)
		{
			m_LastHandleIndex = freeHandle;
		}

		return freeHandle;
	}

	private void FreeHandle(SimpleBroadphaseProxy proxy)
	{
		int handle = proxy.GetPosition();
		{
		}

		if (handle == m_LastHandleIndex)
		{
			m_LastHandleIndex--;
		}

		proxy.SetNextFree(m_firstFreeHandle);
		m_firstFreeHandle = handle;
		proxy.m_clientObject = null;
		m_numHandles--;
	}

	public virtual BroadphaseProxy CreateProxy(IndexedVector3 aabbMin, IndexedVector3 aabbMax, BroadphaseNativeTypes shapeType, Object userPtr, CollisionFilterGroups collisionFilterGroup, CollisionFilterGroups collisionFilterMask, IDispatcher dispatcher, Object multiSapProxy)
	{
		return CreateProxy(ref aabbMin, ref aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, dispatcher, multiSapProxy);
	}

	public virtual BroadphaseProxy CreateProxy(ref IndexedVector3 aabbMin, ref IndexedVector3 aabbMax, BroadphaseNativeTypes shapeType, Object userPtr, CollisionFilterGroups collisionFilterGroup, CollisionFilterGroups collisionFilterMask, IDispatcher dispatcher, Object multiSapProxy)
	{
		if (m_numHandles >= m_maxHandles)
		{
			{
			}

			return null; //should never happen, but don't let the game crash ;-)
		}

		int position = AllocHandle();
		m_pHandles[position] = new SimpleBroadphaseProxy(position, ref aabbMin, ref aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, multiSapProxy);
		;
		m_pHandles[position].m_uniqueId = ++m_proxyCounter;
		return m_pHandles[position];
	}

	public virtual void CalculateOverlappingPairs(IDispatcher dispatcher)
	{
		//first check for new overlapping pairs
		if (m_numHandles > 0)
		{
			int new_largest_index = -1;
			for (int i = 0; i <= m_LastHandleIndex; i++)
			{
				SimpleBroadphaseProxy proxy0 = m_pHandles[i];
				if (proxy0.GetClientObject() == null)
				{
					continue;
				}

				new_largest_index = i;
				for (int j = i + 1; j <= m_LastHandleIndex; j++)
				{
					SimpleBroadphaseProxy proxy1 = m_pHandles[j];
					//btAssert(proxy0 != proxy1);
					if (proxy1.GetClientObject() == null)
					{
						continue;
					}

					if (AabbOverlap(proxy0, proxy1))
					{
						if (m_pairCache.FindPair(proxy0, proxy1) == null)
						{
							m_pairCache.AddOverlappingPair(proxy0, proxy1);
						}
					}
					else
					{
						if (!m_pairCache.HasDeferredRemoval())
						{
							if (m_pairCache.FindPair(proxy0, proxy1) != null)
							{
								m_pairCache.RemoveOverlappingPair(proxy0, proxy1, dispatcher);
							}
						}
					}
				}
			}

			m_LastHandleIndex = new_largest_index;
			if (m_ownsPairCache && m_pairCache.HasDeferredRemoval())
			{
				IList<BroadphasePair> overlappingPairArray = m_pairCache.GetOverlappingPairArray();
				//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
				((List<BroadphasePair>)overlappingPairArray).Sort();
				//overlappingPairArray.Capacity = (overlappingPairArray.Count - m_invalidPair);
				m_invalidPair = 0;
				BroadphasePair previousPair = new BroadphasePair();
				for (int i = 0; i < overlappingPairArray.Count; i++)
				{
					BroadphasePair pair = overlappingPairArray[i];
					bool isDuplicate = (pair == previousPair);
					previousPair = pair;
					bool needsRemoval = false;
					if (!isDuplicate)
					{
						bool hasOverlap = TestAabbOverlap(pair.m_pProxy0, pair.m_pProxy1);
						if (hasOverlap)
						{
							needsRemoval = false; //callback->processOverlap(pair);
						}
						else
						{
							needsRemoval = true;
						}
					}
					else
					{
						//remove duplicate
						needsRemoval = true;
					//should have no algorithm
					//btAssert(!pair.m_algorithm);
					}

					if (needsRemoval)
					{
						m_pairCache.CleanOverlappingPair(pair, dispatcher);
						//		m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
						//		m_overlappingPairArray.pop_back();
						pair.m_pProxy0 = null;
						pair.m_pProxy1 = null;
						m_invalidPair++;
						BulletGlobals.gOverlappingPairs--;
					}
				}

				//perform a sort, to sort 'invalid' pairs to the end
				//overlappingPairArray.quickSort(new BroadphasePairSortPredicate());
				((List<BroadphasePair>)overlappingPairArray).Sort();
				//overlappingPairArray.Capacity = overlappingPairArray.Count - m_invalidPair;
				m_invalidPair = 0;
			}
		}
	}

	public virtual void DestroyProxy(BroadphaseProxy proxy, IDispatcher dispatcher)
	{
		SimpleBroadphaseProxy proxy0 = (SimpleBroadphaseProxy)(proxy);
		FreeHandle(proxy0);
		m_pairCache.RemoveOverlappingPairsContainingProxy(proxy, dispatcher);
	}

	public virtual void SetAabb(BroadphaseProxy proxy, ref IndexedVector3 aabbMin, ref IndexedVector3 aabbMax, IDispatcher dispatcher)
	{
		SimpleBroadphaseProxy sbp = GetSimpleProxyFromProxy(proxy);
		sbp.SetMinAABB(ref aabbMin);
		sbp.SetMaxAABB(ref aabbMax);
	}

	public virtual void GetAabb(BroadphaseProxy proxy, out IndexedVector3 aabbMin, out IndexedVector3 aabbMax)
	{
		SimpleBroadphaseProxy sbp = GetSimpleProxyFromProxy(proxy);
		aabbMin = sbp.GetMinAABB();
		aabbMax = sbp.GetMaxAABB();
	}

	public virtual void RayTest(ref IndexedVector3 rayFrom, ref IndexedVector3 rayTo, BroadphaseRayCallback rayCallback)
	{
		IndexedVector3 min = MathUtil.MIN_VECTOR;
		IndexedVector3 max = MathUtil.MAX_VECTOR;
		RayTest(ref rayFrom, ref rayTo, rayCallback, ref min, ref max);
	}

	public virtual void RayTest(ref IndexedVector3 rayFrom, ref IndexedVector3 rayTo, BroadphaseRayCallback rayCallback, ref IndexedVector3 aabbMin, ref IndexedVector3 aabbMax)
	{
		for (int i = 0; i <= m_LastHandleIndex; i++)
		{
			SimpleBroadphaseProxy proxy = m_pHandles[i];
			if (proxy.m_clientObject == null)
			{
				continue;
			}

			rayCallback.Process(proxy);
		}
	}

	public virtual void AabbTest(ref IndexedVector3 aabbMin, ref IndexedVector3 aabbMax, IBroadphaseAabbCallback callback)
	{
		for (int i = 0; i <= m_LastHandleIndex; i++)
		{
			SimpleBroadphaseProxy proxy = m_pHandles[i];
			if (proxy.m_clientObject == null)
			{
				continue;
			}

			if (AabbUtil2.TestAabbAgainstAabb2(ref aabbMin, ref aabbMax, ref proxy.m_aabbMin, ref proxy.m_aabbMax))
			{
				callback.Process(proxy);
			}
		}
	}

	public IOverlappingPairCache GetOverlappingPairCache()
	{
		return m_pairCache;
	}

	public bool TestAabbOverlap(BroadphaseProxy proxy0, BroadphaseProxy proxy1)
	{
		return AabbOverlap((SimpleBroadphaseProxy)proxy0, (SimpleBroadphaseProxy)proxy1);
	}

	public virtual void GetBroadphaseAabb(out IndexedVector3 aabbMin, out IndexedVector3 aabbMax)
	{
		aabbMin = MathUtil.MIN_VECTOR;
		aabbMax = MathUtil.MAX_VECTOR;
	}

	public virtual void PrintStats()
	{
	//		printf("btSimpleBroadphase.h\n");
	//		printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles);
	}

	protected SimpleBroadphaseProxy GetSimpleProxyFromProxy(BroadphaseProxy proxy)
	{
		return proxy as SimpleBroadphaseProxy;
	}

	public virtual void ResetPool(IDispatcher dispatcher)
	{
	// not yet
	}

	protected void Validate()
	{
		for (int i = 0; i < m_numHandles; i++)
		{
			for (int j = i + 1; j < m_numHandles; j++)
			{
				{
				}
			}
		}
	}

	private int m_proxyCounter = 2;
	private IOverlappingPairCache m_pairCache;
	private bool m_ownsPairCache;
	int m_invalidPair;
	protected int m_numHandles; // number of active handles
	protected int m_maxHandles; // max number of handles
	protected int m_LastHandleIndex;
	protected SimpleBroadphaseProxy[] m_pHandles; // handles pool
	protected Object m_pHandlesRawPtr;
	protected int m_firstFreeHandle; // free handles list
}