Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Box2D/Collision/b2BroadPhase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions Box2D/Collision/b2BroadPhase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 <typename T>
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;
Expand Down Expand Up @@ -220,9 +220,9 @@ inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const
}

template <typename T>
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)
Expand Down
29 changes: 25 additions & 4 deletions Box2D/Collision/b2DynamicTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();

Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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
{
Expand All @@ -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;
Expand Down Expand Up @@ -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
{
Expand All @@ -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;
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 9 additions & 5 deletions Box2D/Collision/b2DynamicTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include <Box2D/Common/b2GrowableStack.h>

#define b2_nullNode (-1)

/// A node in the dynamic tree. The client does not interact with this directly.
struct b2TreeNode
{
Expand All @@ -37,6 +36,9 @@ struct b2TreeNode

void* userData;

// Category bits for collision filtering
uint16 categoryBits;

union
{
int32 parent;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 <typename T>
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;
Expand All @@ -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();

Expand Down Expand Up @@ -218,7 +222,7 @@ inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
}

template <typename T>
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;
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion Box2D/Dynamics/b2Fixture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions Box2D/Dynamics/b2World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion Box2D/Dynamics/b2World.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down