diff --git a/Box2D/Collision/b2BroadPhase.cpp b/Box2D/Collision/b2BroadPhase.cpp index 0af21cd..52c8979 100755 --- a/Box2D/Collision/b2BroadPhase.cpp +++ b/Box2D/Collision/b2BroadPhase.cpp @@ -37,9 +37,9 @@ b2BroadPhase::~b2BroadPhase() b2Free(m_pairBuffer); } -int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) +int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData, uint16 categoryBits) { - int32 proxyId = m_tree.CreateProxy(aabb, userData); + int32 proxyId = m_tree.CreateProxy(aabb, userData, categoryBits); ++m_proxyCount; BufferMove(proxyId); return proxyId; diff --git a/Box2D/Collision/b2BroadPhase.h b/Box2D/Collision/b2BroadPhase.h index 54ee9c4..65cad89 100755 --- a/Box2D/Collision/b2BroadPhase.h +++ b/Box2D/Collision/b2BroadPhase.h @@ -46,7 +46,7 @@ class b2BroadPhase /// Create a proxy with an initial AABB. Pairs are not reported until /// UpdatePairs is called. - int32 CreateProxy(const b2AABB& aabb, void* userData); + int32 CreateProxy(const b2AABB& aabb, void* userData, uint16 categoryBits); /// Destroy a proxy. It is up to the client to remove any pairs. void DestroyProxy(int32 proxyId); @@ -87,7 +87,7 @@ class b2BroadPhase /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. template - void RayCast(T* callback, const b2RayCastInput& input) const; + void RayCast(T* callback, const b2RayCastInput& input, uint16 maskBits) const; /// Get the height of the embedded tree. int32 GetTreeHeight() const; @@ -220,9 +220,9 @@ inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const } template -inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const +inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input, uint16 maskBits) const { - m_tree.RayCast(callback, input); + m_tree.RayCast(callback, input, maskBits); } inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin) diff --git a/Box2D/Collision/b2DynamicTree.cpp b/Box2D/Collision/b2DynamicTree.cpp index 5e9a8fa..800d963 100755 --- a/Box2D/Collision/b2DynamicTree.cpp +++ b/Box2D/Collision/b2DynamicTree.cpp @@ -85,6 +85,7 @@ int32 b2DynamicTree::AllocateNode() m_nodes[nodeId].child1 = b2_nullNode; m_nodes[nodeId].child2 = b2_nullNode; m_nodes[nodeId].height = 0; + m_nodes[nodeId].categoryBits = _I16_MAX; m_nodes[nodeId].userData = NULL; m_nodes[nodeId].moved = false; ++m_nodeCount; @@ -105,7 +106,7 @@ void b2DynamicTree::FreeNode(int32 nodeId) // Create a proxy in the tree as a leaf node. We return the index // of the node instead of a pointer so that we can grow // the node pool. -int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) +int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData, uint16 categoryBits) { int32 proxyId = AllocateNode(); @@ -115,8 +116,8 @@ int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; m_nodes[proxyId].userData = userData; m_nodes[proxyId].height = 0; + m_nodes[proxyId].categoryBits = categoryBits; m_nodes[proxyId].moved = true; - InsertLeaf(proxyId); return proxyId; @@ -286,6 +287,7 @@ void b2DynamicTree::InsertLeaf(int32 leaf) m_nodes[newParent].userData = NULL; m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); m_nodes[newParent].height = m_nodes[sibling].height + 1; + m_nodes[newParent].categoryBits = m_nodes[leaf].categoryBits | m_nodes[sibling].categoryBits; if (oldParent != b2_nullNode) { @@ -328,7 +330,7 @@ void b2DynamicTree::InsertLeaf(int32 leaf) m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - + m_nodes[newParent].categoryBits = m_nodes[child1].categoryBits | m_nodes[child2].categoryBits; index = m_nodes[index].parent; } @@ -380,7 +382,7 @@ void b2DynamicTree::RemoveLeaf(int32 leaf) m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); - + m_nodes[index].categoryBits = m_nodes[child1].categoryBits | m_nodes[child2].categoryBits; index = m_nodes[index].parent; } } @@ -460,6 +462,8 @@ int32 b2DynamicTree::Balance(int32 iA) A->height = 1 + b2Max(B->height, G->height); C->height = 1 + b2Max(A->height, F->height); + A->categoryBits = B->categoryBits | G->categoryBits; + C->categoryBits = A->categoryBits | F->categoryBits; } else { @@ -471,6 +475,9 @@ int32 b2DynamicTree::Balance(int32 iA) A->height = 1 + b2Max(B->height, F->height); C->height = 1 + b2Max(A->height, G->height); + + A->categoryBits = B->categoryBits | F->categoryBits; + C->categoryBits = A->categoryBits | G->categoryBits; } return iC; @@ -520,6 +527,9 @@ int32 b2DynamicTree::Balance(int32 iA) A->height = 1 + b2Max(C->height, E->height); B->height = 1 + b2Max(A->height, D->height); + + A->categoryBits = C->categoryBits | E->categoryBits; + B->categoryBits = A->categoryBits | D->categoryBits; } else { @@ -531,6 +541,9 @@ int32 b2DynamicTree::Balance(int32 iA) A->height = 1 + b2Max(C->height, D->height); B->height = 1 + b2Max(A->height, E->height); + + A->categoryBits = C->categoryBits | D->categoryBits; + B->categoryBits = A->categoryBits | E->categoryBits; } return iB; @@ -576,6 +589,10 @@ float32 b2DynamicTree::GetAreaRatio() const return totalArea / rootArea; } +void b2DynamicTree::SetCategoryBits(uint16 categoryBits) +{ +} + // Compute the height of a sub-tree. int32 b2DynamicTree::ComputeHeight(int32 nodeId) const { @@ -672,6 +689,9 @@ void b2DynamicTree::ValidateMetrics(int32 index) const b2Assert(aabb.lowerBound == node->aabb.lowerBound); b2Assert(aabb.upperBound == node->aabb.upperBound); + uint16 categoryBits = m_nodes[child1].categoryBits | m_nodes[child2].categoryBits; + b2Assert(node->categoryBits == categoryBits); + ValidateMetrics(child1); ValidateMetrics(child2); } @@ -777,6 +797,7 @@ void b2DynamicTree::RebuildBottomUp() parent->child2 = index2; parent->height = 1 + b2Max(child1->height, child2->height); parent->aabb.Combine(child1->aabb, child2->aabb); + parent->categoryBits = child1->categoryBits | child2->categoryBits; parent->parent = b2_nullNode; child1->parent = parentIndex; diff --git a/Box2D/Collision/b2DynamicTree.h b/Box2D/Collision/b2DynamicTree.h index 28a56e8..ff95190 100755 --- a/Box2D/Collision/b2DynamicTree.h +++ b/Box2D/Collision/b2DynamicTree.h @@ -23,7 +23,6 @@ #include #define b2_nullNode (-1) - /// A node in the dynamic tree. The client does not interact with this directly. struct b2TreeNode { @@ -37,6 +36,9 @@ struct b2TreeNode void* userData; + // Category bits for collision filtering + uint16 categoryBits; + union { int32 parent; @@ -70,7 +72,7 @@ class b2DynamicTree ~b2DynamicTree(); /// Create a proxy. Provide a tight fitting AABB and a userData pointer. - int32 CreateProxy(const b2AABB& aabb, void* userData); + int32 CreateProxy(const b2AABB& aabb, void* userData, uint16 categoryBits); /// Destroy a proxy. This asserts if the id is invalid. void DestroyProxy(int32 proxyId); @@ -104,7 +106,7 @@ class b2DynamicTree /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. template - void RayCast(T* callback, const b2RayCastInput& input) const; + void RayCast(T* callback, const b2RayCastInput& input, uint16 maskBits) const; /// Validate this tree. For testing. void Validate() const; @@ -120,6 +122,8 @@ class b2DynamicTree /// Get the ratio of the sum of the node areas to the root area. float32 GetAreaRatio() const; + void SetCategoryBits(uint16 categoryBits); + /// Build an optimal tree. Very expensive. For testing. void RebuildBottomUp(); @@ -218,7 +222,7 @@ inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const } template -inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const +inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input, uint16 maskBits) const { b2Vec2 p1 = input.p1; b2Vec2 p2 = input.p2; @@ -256,7 +260,7 @@ inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) con const b2TreeNode* node = m_nodes + nodeId; - if (b2TestOverlap(node->aabb, segmentAABB) == false) + if ((node->categoryBits & maskBits) == 0 || (b2TestOverlap(node->aabb, segmentAABB) == false)) { continue; } diff --git a/Box2D/Dynamics/b2Fixture.cpp b/Box2D/Dynamics/b2Fixture.cpp index ff75b10..1e08025 100755 --- a/Box2D/Dynamics/b2Fixture.cpp +++ b/Box2D/Dynamics/b2Fixture.cpp @@ -130,7 +130,7 @@ void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) { b2FixtureProxy* proxy = m_proxies + i; m_shape->ComputeAABB(&proxy->aabb, xf, i); - proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); + proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy, m_filter.categoryBits); proxy->fixture = this; proxy->childIndex = i; } diff --git a/Box2D/Dynamics/b2World.cpp b/Box2D/Dynamics/b2World.cpp index d3a0518..f0bf8e7 100755 --- a/Box2D/Dynamics/b2World.cpp +++ b/Box2D/Dynamics/b2World.cpp @@ -1119,7 +1119,7 @@ struct b2WorldRayCastWrapper b2RayCastCallback* callback; }; -void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const +void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2, uint16 maskBits) const { b2WorldRayCastWrapper wrapper; wrapper.broadPhase = &m_contactManager.m_broadPhase; @@ -1128,7 +1128,7 @@ void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b input.maxFraction = 1.0f; input.p1 = point1; input.p2 = point2; - m_contactManager.m_broadPhase.RayCast(&wrapper, input); + m_contactManager.m_broadPhase.RayCast(&wrapper, input, maskBits); for (b2ParticleSystem* p = m_particleSystemList; p; p = p->GetNext()) { if (callback->ShouldQueryParticleSystem(p)) diff --git a/Box2D/Dynamics/b2World.h b/Box2D/Dynamics/b2World.h index ce0b8c1..af68817 100755 --- a/Box2D/Dynamics/b2World.h +++ b/Box2D/Dynamics/b2World.h @@ -166,7 +166,7 @@ class b2World /// @param callback a user implemented callback class. /// @param point1 the ray starting point /// @param point2 the ray ending point - void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; + void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2, uint16 maskBits) const; /// Get the world body list. With the returned body, use b2Body::GetNext to get /// the next body in the world list. A NULL body indicates the end of the list.