SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | - | * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org |
2 | + | * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org |
3 | * | |
4 | * This software is provided 'as-is', without any express or implied | |
5 | * warranty. In no event will the authors be held liable for any damages | |
6 | * arising from the use of this software. | |
7 | * Permission is granted to anyone to use this software for any purpose, | |
8 | * including commercial applications, and to alter it and redistribute it | |
9 | * freely, subject to the following restrictions: | |
10 | * 1. The origin of this software must not be misrepresented; you must not | |
11 | * claim that you wrote the original software. If you use this software | |
12 | * in a product, an acknowledgment in the product documentation would be | |
13 | * appreciated but is not required. | |
14 | * 2. Altered source versions must be plainly marked as such, and must not be | |
15 | * misrepresented as being the original software. | |
16 | * 3. This notice may not be removed or altered from any source distribution. | |
17 | */ | |
18 | ||
19 | - | #include <Box2D/Dynamics/b2World.h> |
19 | + | #ifndef B2_BROAD_PHASE_H |
20 | - | #include <Box2D/Dynamics/b2Body.h> |
20 | + | #define B2_BROAD_PHASE_H |
21 | - | #include <Box2D/Dynamics/b2Fixture.h> |
21 | + | |
22 | - | #include <Box2D/Dynamics/b2Island.h> |
22 | + | #include <Box2D/Common/b2Settings.h> |
23 | - | #include <Box2D/Dynamics/Joints/b2PulleyJoint.h> |
23 | + | |
24 | - | #include <Box2D/Dynamics/Contacts/b2Contact.h> |
24 | + | #include <Box2D/Collision/b2DynamicTree.h> |
25 | - | #include <Box2D/Dynamics/Contacts/b2ContactSolver.h> |
25 | + | //#include <algorithm> |
26 | #include <stdlib.h> | |
27 | - | #include <Box2D/Collision/b2BroadPhase.h> |
27 | + | |
28 | - | #include <Box2D/Collision/Shapes/b2CircleShape.h> |
28 | + | |
29 | - | #include <Box2D/Collision/Shapes/b2EdgeShape.h> |
29 | + | |
30 | - | #include <Box2D/Collision/Shapes/b2ChainShape.h> |
30 | + | |
31 | - | #include <Box2D/Collision/Shapes/b2PolygonShape.h> |
31 | + | struct b2Pair |
32 | - | #include <Box2D/Collision/b2TimeOfImpact.h> |
32 | + | |
33 | - | #include <Box2D/Common/b2Draw.h> |
33 | + | int32 proxyIdA; |
34 | - | #include <Box2D/Common/b2Timer.h> |
34 | + | int32 proxyIdB; |
35 | - | #include <new> |
35 | + | |
36 | ||
37 | /// The broad-phase is used for computing pairs and performing volume queries and ray casts. | |
38 | /// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. | |
39 | /// It is up to the client to consume the new pairs and to track subsequent overlap. | |
40 | - | b2World::b2World(const b2Vec2& gravity) |
40 | + | class b2BroadPhase |
41 | { | |
42 | - | m_destructionListener = NULL; |
42 | + | public: |
43 | - | g_debugDraw = NULL; |
43 | + | |
44 | enum | |
45 | - | m_bodyList = NULL; |
45 | + | |
46 | - | m_jointList = NULL; |
46 | + | e_nullProxy = -1 |
47 | }; | |
48 | - | m_bodyCount = 0; |
48 | + | |
49 | - | m_jointCount = 0; |
49 | + | b2BroadPhase(); |
50 | ~b2BroadPhase(); | |
51 | - | m_warmStarting = true; |
51 | + | |
52 | - | m_continuousPhysics = true; |
52 | + | /// Create a proxy with an initial AABB. Pairs are not reported until |
53 | - | m_subStepping = false; |
53 | + | /// UpdatePairs is called. |
54 | int32 CreateProxy(const b2AABB& aabb, void* userData); | |
55 | - | m_stepComplete = true; |
55 | + | |
56 | /// Destroy a proxy. It is up to the client to remove any pairs. | |
57 | - | m_allowSleep = true; |
57 | + | void DestroyProxy(int32 proxyId); |
58 | - | m_gravity = gravity; |
58 | + | |
59 | /// Call MoveProxy as many times as you like, then when you are done | |
60 | - | m_flags = e_clearForces; |
60 | + | /// call UpdatePairs to finalized the proxy pairs (for your time step). |
61 | void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); | |
62 | - | m_inv_dt0 = 0.0f; |
62 | + | |
63 | /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. | |
64 | - | m_contactManager.m_allocator = &m_blockAllocator; |
64 | + | void TouchProxy(int32 proxyId); |
65 | ||
66 | - | memset(&m_profile, 0, sizeof(b2Profile)); |
66 | + | /// Get the fat AABB for a proxy. |
67 | const b2AABB& GetFatAABB(int32 proxyId) const; | |
68 | ||
69 | - | b2World::~b2World() |
69 | + | /// Get user data from a proxy. Returns NULL if the id is invalid. |
70 | void* GetUserData(int32 proxyId) const; | |
71 | - | // Some shapes allocate using b2Alloc. |
71 | + | |
72 | - | b2Body* b = m_bodyList; |
72 | + | /// Test overlap of fat AABBs. |
73 | - | while (b) |
73 | + | bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; |
74 | ||
75 | - | b2Body* bNext = b->m_next; |
75 | + | /// Get the number of proxies. |
76 | int32 GetProxyCount() const; | |
77 | - | b2Fixture* f = b->m_fixtureList; |
77 | + | |
78 | - | while (f) |
78 | + | /// Update the pairs. This results in pair callbacks. This can only add pairs. |
79 | template <typename T> | |
80 | - | b2Fixture* fNext = f->m_next; |
80 | + | void UpdatePairs(T* callback); |
81 | - | f->m_proxyCount = 0; |
81 | + | |
82 | - | f->Destroy(&m_blockAllocator); |
82 | + | /// Query an AABB for overlapping proxies. The callback class |
83 | - | f = fNext; |
83 | + | /// is called for each proxy that overlaps the supplied AABB. |
84 | template <typename T> | |
85 | void Query(T* callback, const b2AABB& aabb) const; | |
86 | - | b = bNext; |
86 | + | |
87 | /// Ray-cast against the proxies in the tree. This relies on the callback | |
88 | /// to perform a exact ray-cast in the case were the proxy contains a shape. | |
89 | /// The callback also performs the any collision filtering. This has performance | |
90 | - | void b2World::SetDestructionListener(b2DestructionListener* listener) |
90 | + | /// roughly equal to k * log(n), where k is the number of collisions and n is the |
91 | /// number of proxies in the tree. | |
92 | - | m_destructionListener = listener; |
92 | + | /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). |
93 | /// @param callback a callback class that is called for each proxy that is hit by the ray. | |
94 | template <typename T> | |
95 | - | void b2World::SetContactFilter(b2ContactFilter* filter) |
95 | + | void RayCast(T* callback, const b2RayCastInput& input) const; |
96 | ||
97 | - | m_contactManager.m_contactFilter = filter; |
97 | + | /// Get the height of the embedded tree. |
98 | int32 GetTreeHeight() const; | |
99 | ||
100 | - | void b2World::SetContactListener(b2ContactListener* listener) |
100 | + | /// Get the balance of the embedded tree. |
101 | int32 GetTreeBalance() const; | |
102 | - | m_contactManager.m_contactListener = listener; |
102 | + | |
103 | /// Get the quality metric of the embedded tree. | |
104 | float32 GetTreeQuality() const; | |
105 | - | void b2World::SetDebugDraw(b2Draw* debugDraw) |
105 | + | |
106 | /// Shift the world origin. Useful for large worlds. | |
107 | - | g_debugDraw = debugDraw; |
107 | + | /// The shift formula is: position -= newOrigin |
108 | /// @param newOrigin the new origin with respect to the old origin | |
109 | void ShiftOrigin(const b2Vec2& newOrigin); | |
110 | - | b2Body* b2World::CreateBody(const b2BodyDef* def) |
110 | + | |
111 | private: | |
112 | - | b2Assert(IsLocked() == false); |
112 | + | |
113 | - | if (IsLocked()) |
113 | + | friend class b2DynamicTree; |
114 | ||
115 | - | return NULL; |
115 | + | void BufferMove(int32 proxyId); |
116 | void UnBufferMove(int32 proxyId); | |
117 | ||
118 | - | void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); |
118 | + | bool QueryCallback(int32 proxyId); |
119 | - | b2Body* b = new (mem) b2Body(def, this); |
119 | + | |
120 | b2DynamicTree m_tree; | |
121 | - | // Add to world doubly linked list. |
121 | + | |
122 | - | b->m_prev = NULL; |
122 | + | int32 m_proxyCount; |
123 | - | b->m_next = m_bodyList; |
123 | + | |
124 | - | if (m_bodyList) |
124 | + | int32* m_moveBuffer; |
125 | int32 m_moveCapacity; | |
126 | - | m_bodyList->m_prev = b; |
126 | + | int32 m_moveCount; |
127 | ||
128 | - | m_bodyList = b; |
128 | + | b2Pair* m_pairBuffer; |
129 | - | ++m_bodyCount; |
129 | + | int32 m_pairCapacity; |
130 | int32 m_pairCount; | |
131 | - | return b; |
131 | + | |
132 | int32 m_queryProxyId; | |
133 | }; | |
134 | - | void b2World::DestroyBody(b2Body* b) |
134 | + | |
135 | //The return value of this function should represent whether elem1 is considered less than, | |
136 | - | b2Assert(m_bodyCount > 0); |
136 | + | //equal to, or greater than elem2 by returning, respectively, a negative value, zero or a positive value. |
137 | - | b2Assert(IsLocked() == false); |
137 | + | inline int b2PairCompareQSort(const void * elem1, const void * elem2) |
138 | - | if (IsLocked()) |
138 | + | |
139 | b2Pair* pair1 = (b2Pair*) elem1; | |
140 | - | return; |
140 | + | b2Pair* pair2 = (b2Pair*) elem2; |
141 | ||
142 | if (pair1->proxyIdA < pair2->proxyIdA) | |
143 | - | // Delete the attached joints. |
143 | + | { |
144 | - | b2JointEdge* je = b->m_jointList; |
144 | + | return -1; |
145 | - | while (je) |
145 | + | } |
146 | ||
147 | - | b2JointEdge* je0 = je; |
147 | + | if (pair1->proxyIdA == pair2->proxyIdA) |
148 | - | je = je->next; |
148 | + | { |
149 | if( pair1->proxyIdB < pair2->proxyIdB ) { | |
150 | - | if (m_destructionListener) |
150 | + | return -1; |
151 | } | |
152 | - | m_destructionListener->SayGoodbye(je0->joint); |
152 | + | else if(pair1->proxyIdB > pair2->proxyIdB) { |
153 | return 1; | |
154 | } | |
155 | - | DestroyJoint(je0->joint); |
155 | + | else { |
156 | return 0; | |
157 | - | b->m_jointList = je; |
157 | + | } |
158 | } | |
159 | - | b->m_jointList = NULL; |
159 | + | else { |
160 | return 1; | |
161 | - | // Delete the attached contacts. |
161 | + | } |
162 | - | b2ContactEdge* ce = b->m_contactList; |
162 | + | |
163 | - | while (ce) |
163 | + | |
164 | ||
165 | - | b2ContactEdge* ce0 = ce; |
165 | + | /// This is used to sort pairs. |
166 | - | ce = ce->next; |
166 | + | inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) |
167 | - | m_contactManager.Destroy(ce0->contact); |
167 | + | |
168 | if (pair1.proxyIdA < pair2.proxyIdA) | |
169 | - | b->m_contactList = NULL; |
169 | + | |
170 | return true; | |
171 | - | // Delete the attached fixtures. This destroys broad-phase proxies. |
171 | + | |
172 | - | b2Fixture* f = b->m_fixtureList; |
172 | + | |
173 | - | while (f) |
173 | + | if (pair1.proxyIdA == pair2.proxyIdA) |
174 | { | |
175 | - | b2Fixture* f0 = f; |
175 | + | return pair1.proxyIdB < pair2.proxyIdB; |
176 | - | f = f->m_next; |
176 | + | |
177 | ||
178 | - | if (m_destructionListener) |
178 | + | return false; |
179 | } | |
180 | - | m_destructionListener->SayGoodbye(f0); |
180 | + | |
181 | inline void* b2BroadPhase::GetUserData(int32 proxyId) const | |
182 | { | |
183 | - | f0->DestroyProxies(&m_contactManager.m_broadPhase); |
183 | + | return m_tree.GetUserData(proxyId); |
184 | - | f0->Destroy(&m_blockAllocator); |
184 | + | |
185 | - | f0->~b2Fixture(); |
185 | + | |
186 | - | m_blockAllocator.Free(f0, sizeof(b2Fixture)); |
186 | + | inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const |
187 | { | |
188 | - | b->m_fixtureList = f; |
188 | + | const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); |
189 | - | b->m_fixtureCount -= 1; |
189 | + | const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); |
190 | return b2TestOverlap(aabbA, aabbB); | |
191 | - | b->m_fixtureList = NULL; |
191 | + | |
192 | - | b->m_fixtureCount = 0; |
192 | + | |
193 | inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const | |
194 | - | // Remove world body list. |
194 | + | |
195 | - | if (b->m_prev) |
195 | + | return m_tree.GetFatAABB(proxyId); |
196 | } | |
197 | - | b->m_prev->m_next = b->m_next; |
197 | + | |
198 | inline int32 b2BroadPhase::GetProxyCount() const | |
199 | { | |
200 | - | if (b->m_next) |
200 | + | return m_proxyCount; |
201 | } | |
202 | - | b->m_next->m_prev = b->m_prev; |
202 | + | |
203 | inline int32 b2BroadPhase::GetTreeHeight() const | |
204 | { | |
205 | - | if (b == m_bodyList) |
205 | + | return m_tree.GetHeight(); |
206 | } | |
207 | - | m_bodyList = b->m_next; |
207 | + | |
208 | inline int32 b2BroadPhase::GetTreeBalance() const | |
209 | { | |
210 | - | --m_bodyCount; |
210 | + | return m_tree.GetMaxBalance(); |
211 | - | b->~b2Body(); |
211 | + | |
212 | - | m_blockAllocator.Free(b, sizeof(b2Body)); |
212 | + | |
213 | inline float32 b2BroadPhase::GetTreeQuality() const | |
214 | { | |
215 | - | b2Joint* b2World::CreateJoint(const b2JointDef* def) |
215 | + | return m_tree.GetAreaRatio(); |
216 | } | |
217 | - | b2Assert(IsLocked() == false); |
217 | + | |
218 | - | if (IsLocked()) |
218 | + | template <typename T> |
219 | void b2BroadPhase::UpdatePairs(T* callback) | |
220 | - | return NULL; |
220 | + | |
221 | ||
222 | printf("\n"); | |
223 | - | b2Joint* j = b2Joint::Create(def, &m_blockAllocator); |
223 | + | printf("{"); |
224 | printf("%d",m_moveCount); | |
225 | - | // Connect to the world list. |
225 | + | |
226 | - | j->m_prev = NULL; |
226 | + | |
227 | - | j->m_next = m_jointList; |
227 | + | |
228 | - | if (m_jointList) |
228 | + | // Reset pair buffer |
229 | m_pairCount = 0; | |
230 | - | m_jointList->m_prev = j; |
230 | + | |
231 | // Perform tree queries for all moving proxies. | |
232 | - | m_jointList = j; |
232 | + | for (int32 i = 0; i < m_moveCount; ++i) |
233 | - | ++m_jointCount; |
233 | + | |
234 | m_queryProxyId = m_moveBuffer[i]; | |
235 | - | // Connect to the bodies' doubly linked lists. |
235 | + | if (m_queryProxyId == e_nullProxy) |
236 | - | j->m_edgeA.joint = j; |
236 | + | |
237 | - | j->m_edgeA.other = j->m_bodyB; |
237 | + | |
238 | - | j->m_edgeA.prev = NULL; |
238 | + | |
239 | - | j->m_edgeA.next = j->m_bodyA->m_jointList; |
239 | + | |
240 | - | if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; |
240 | + | // We have to query the tree with the fat AABB so that |
241 | - | j->m_bodyA->m_jointList = &j->m_edgeA; |
241 | + | // we don't fail to create a pair that may touch later. |
242 | const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); | |
243 | - | j->m_edgeB.joint = j; |
243 | + | |
244 | - | j->m_edgeB.other = j->m_bodyA; |
244 | + | // Query tree, create pairs and add them pair buffer. |
245 | - | j->m_edgeB.prev = NULL; |
245 | + | m_tree.Query(this, fatAABB); |
246 | - | j->m_edgeB.next = j->m_bodyB->m_jointList; |
246 | + | |
247 | - | if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; |
247 | + | |
248 | - | j->m_bodyB->m_jointList = &j->m_edgeB; |
248 | + | // Reset move buffer |
249 | m_moveCount = 0; | |
250 | - | b2Body* bodyA = def->bodyA; |
250 | + | |
251 | - | b2Body* bodyB = def->bodyB; |
251 | + | // Sort the pair buffer to expose duplicates. |
252 | //std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); | |
253 | - | // If the joint prevents collisions, then flag any contacts for filtering. |
253 | + | |
254 | - | if (def->collideConnected == false) |
254 | + | // FIX from http://www.box2d.org/forum/viewtopic.php?f=7&t=4756&start=0 to get rid of stl dependency |
255 | qsort(m_pairBuffer, sizeof(m_pairBuffer) / sizeof(struct b2Pair) , sizeof(struct b2Pair), b2PairCompareQSort); | |
256 | - | b2ContactEdge* edge = bodyB->GetContactList(); |
256 | + | // Send the pairs back to the client. |
257 | - | while (edge) |
257 | + | |
258 | int32 i = 0; | |
259 | - | if (edge->other == bodyA) |
259 | + | |
260 | printf("|"); | |
261 | - | // Flag the contact for filtering at the next time step (where either |
261 | + | printf("%d",m_pairCount); |
262 | - | // body is awake). |
262 | + | |
263 | - | edge->contact->FlagForFiltering(); |
263 | + | |
264 | ||
265 | while (i < m_pairCount) | |
266 | - | edge = edge->next; |
266 | + | |
267 | b2Pair* primaryPair = m_pairBuffer + i; | |
268 | void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); | |
269 | void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); | |
270 | - | // Note: creating a joint doesn't wake the bodies. |
270 | + | |
271 | callback->AddPair(userDataA, userDataB); | |
272 | - | return j; |
272 | + | |
273 | ||
274 | // Skip any duplicate pairs. | |
275 | - | void b2World::DestroyJoint(b2Joint* j) |
275 | + | while (i < m_pairCount) |
276 | { | |
277 | - | b2Assert(IsLocked() == false); |
277 | + | b2Pair* pair = m_pairBuffer + i; |
278 | - | if (IsLocked()) |
278 | + | if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) |
279 | { | |
280 | - | return; |
280 | + | break; |
281 | } | |
282 | ++i; | |
283 | - | bool collideConnected = j->m_collideConnected; |
283 | + | |
284 | } | |
285 | - | // Remove from the doubly linked list. |
285 | + | |
286 | - | if (j->m_prev) |
286 | + | printf("{*}"); |
287 | fflush(stdout); | |
288 | - | j->m_prev->m_next = j->m_next; |
288 | + | |
289 | // Try to keep the tree balanced. | |
290 | //m_tree.Rebalance(4); | |
291 | - | if (j->m_next) |
291 | + | |
292 | ||
293 | - | j->m_next->m_prev = j->m_prev; |
293 | + | template <typename T> |
294 | inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const | |
295 | { | |
296 | - | if (j == m_jointList) |
296 | + | m_tree.Query(callback, aabb); |
297 | } | |
298 | - | m_jointList = j->m_next; |
298 | + | |
299 | template <typename T> | |
300 | inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const | |
301 | - | // Disconnect from island graph. |
301 | + | |
302 | - | b2Body* bodyA = j->m_bodyA; |
302 | + | m_tree.RayCast(callback, input); |
303 | - | b2Body* bodyB = j->m_bodyB; |
303 | + | |
304 | ||
305 | - | // Wake up connected bodies. |
305 | + | inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin) |
306 | - | bodyA->SetAwake(true); |
306 | + | |
307 | - | bodyB->SetAwake(true); |
307 | + | m_tree.ShiftOrigin(newOrigin); |
308 | } | |
309 | - | // Remove from body 1. |
309 | + | |
310 | - | if (j->m_edgeA.prev) |
310 | + | #endif |