SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | * Copyright (c) 2006-2011 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> | |
20 | #include <Box2D/Dynamics/b2Body.h> | |
21 | #include <Box2D/Dynamics/b2Fixture.h> | |
22 | #include <Box2D/Dynamics/b2Island.h> | |
23 | #include <Box2D/Dynamics/Joints/b2PulleyJoint.h> | |
24 | #include <Box2D/Dynamics/Contacts/b2Contact.h> | |
25 | #include <Box2D/Dynamics/Contacts/b2ContactSolver.h> | |
26 | #include <Box2D/Collision/b2Collision.h> | |
27 | #include <Box2D/Collision/b2BroadPhase.h> | |
28 | #include <Box2D/Collision/Shapes/b2CircleShape.h> | |
29 | #include <Box2D/Collision/Shapes/b2EdgeShape.h> | |
30 | #include <Box2D/Collision/Shapes/b2ChainShape.h> | |
31 | #include <Box2D/Collision/Shapes/b2PolygonShape.h> | |
32 | #include <Box2D/Collision/b2TimeOfImpact.h> | |
33 | #include <Box2D/Common/b2Draw.h> | |
34 | #include <Box2D/Common/b2Timer.h> | |
35 | #include <new> | |
36 | ||
37 | #include <string> | |
38 | #include <stdio.h> | |
39 | ||
40 | b2World::b2World(const b2Vec2& gravity) | |
41 | { | |
42 | m_destructionListener = NULL; | |
43 | g_debugDraw = NULL; | |
44 | ||
45 | m_bodyList = NULL; | |
46 | m_jointList = NULL; | |
47 | ||
48 | m_bodyCount = 0; | |
49 | m_jointCount = 0; | |
50 | ||
51 | m_warmStarting = true; | |
52 | m_continuousPhysics = true; | |
53 | m_subStepping = false; | |
54 | ||
55 | m_stepComplete = true; | |
56 | ||
57 | m_allowSleep = true; | |
58 | m_gravity = gravity; | |
59 | ||
60 | m_flags = e_clearForces; | |
61 | ||
62 | m_inv_dt0 = 0.0f; | |
63 | ||
64 | m_contactManager.m_allocator = &m_blockAllocator; | |
65 | ||
66 | memset(&m_profile, 0, sizeof(b2Profile)); | |
67 | } | |
68 | ||
69 | b2World::~b2World() | |
70 | { | |
71 | // Some shapes allocate using b2Alloc. | |
72 | b2Body* b = m_bodyList; | |
73 | while (b) | |
74 | { | |
75 | b2Body* bNext = b->m_next; | |
76 | ||
77 | b2Fixture* f = b->m_fixtureList; | |
78 | while (f) | |
79 | { | |
80 | b2Fixture* fNext = f->m_next; | |
81 | f->m_proxyCount = 0; | |
82 | f->Destroy(&m_blockAllocator); | |
83 | f = fNext; | |
84 | } | |
85 | ||
86 | b = bNext; | |
87 | } | |
88 | } | |
89 | ||
90 | void b2World::SetDestructionListener(b2DestructionListener* listener) | |
91 | { | |
92 | m_destructionListener = listener; | |
93 | } | |
94 | ||
95 | void b2World::SetContactFilter(b2ContactFilter* filter) | |
96 | { | |
97 | m_contactManager.m_contactFilter = filter; | |
98 | } | |
99 | ||
100 | void b2World::SetContactListener(b2ContactListener* listener) | |
101 | { | |
102 | m_contactManager.m_contactListener = listener; | |
103 | } | |
104 | ||
105 | void b2World::SetDebugDraw(b2Draw* debugDraw) | |
106 | { | |
107 | g_debugDraw = debugDraw; | |
108 | } | |
109 | ||
110 | b2Body* b2World::CreateBody(const b2BodyDef* def) | |
111 | { | |
112 | b2Assert(IsLocked() == false); | |
113 | if (IsLocked()) | |
114 | { | |
115 | return NULL; | |
116 | } | |
117 | ||
118 | void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); | |
119 | b2Body* b = new (mem) b2Body(def, this); | |
120 | ||
121 | // Add to world doubly linked list. | |
122 | b->m_prev = NULL; | |
123 | b->m_next = m_bodyList; | |
124 | if (m_bodyList) | |
125 | { | |
126 | m_bodyList->m_prev = b; | |
127 | } | |
128 | m_bodyList = b; | |
129 | ++m_bodyCount; | |
130 | ||
131 | return b; | |
132 | } | |
133 | ||
134 | void b2World::DestroyBody(b2Body* b) | |
135 | { | |
136 | b2Assert(m_bodyCount > 0); | |
137 | b2Assert(IsLocked() == false); | |
138 | if (IsLocked()) | |
139 | { | |
140 | return; | |
141 | } | |
142 | ||
143 | // Delete the attached joints. | |
144 | b2JointEdge* je = b->m_jointList; | |
145 | while (je) | |
146 | { | |
147 | b2JointEdge* je0 = je; | |
148 | je = je->next; | |
149 | ||
150 | if (m_destructionListener) | |
151 | { | |
152 | m_destructionListener->SayGoodbye(je0->joint); | |
153 | } | |
154 | ||
155 | DestroyJoint(je0->joint); | |
156 | ||
157 | b->m_jointList = je; | |
158 | } | |
159 | b->m_jointList = NULL; | |
160 | ||
161 | // Delete the attached contacts. | |
162 | b2ContactEdge* ce = b->m_contactList; | |
163 | while (ce) | |
164 | { | |
165 | b2ContactEdge* ce0 = ce; | |
166 | ce = ce->next; | |
167 | m_contactManager.Destroy(ce0->contact); | |
168 | } | |
169 | b->m_contactList = NULL; | |
170 | ||
171 | // Delete the attached fixtures. This destroys broad-phase proxies. | |
172 | b2Fixture* f = b->m_fixtureList; | |
173 | while (f) | |
174 | { | |
175 | b2Fixture* f0 = f; | |
176 | f = f->m_next; | |
177 | ||
178 | if (m_destructionListener) | |
179 | { | |
180 | m_destructionListener->SayGoodbye(f0); | |
181 | } | |
182 | ||
183 | f0->DestroyProxies(&m_contactManager.m_broadPhase); | |
184 | f0->Destroy(&m_blockAllocator); | |
185 | f0->~b2Fixture(); | |
186 | m_blockAllocator.Free(f0, sizeof(b2Fixture)); | |
187 | ||
188 | b->m_fixtureList = f; | |
189 | b->m_fixtureCount -= 1; | |
190 | } | |
191 | b->m_fixtureList = NULL; | |
192 | b->m_fixtureCount = 0; | |
193 | ||
194 | // Remove world body list. | |
195 | if (b->m_prev) | |
196 | { | |
197 | b->m_prev->m_next = b->m_next; | |
198 | } | |
199 | ||
200 | if (b->m_next) | |
201 | { | |
202 | b->m_next->m_prev = b->m_prev; | |
203 | } | |
204 | ||
205 | if (b == m_bodyList) | |
206 | { | |
207 | m_bodyList = b->m_next; | |
208 | } | |
209 | ||
210 | --m_bodyCount; | |
211 | b->~b2Body(); | |
212 | m_blockAllocator.Free(b, sizeof(b2Body)); | |
213 | } | |
214 | ||
215 | b2Joint* b2World::CreateJoint(const b2JointDef* def) | |
216 | { | |
217 | b2Assert(IsLocked() == false); | |
218 | if (IsLocked()) | |
219 | { | |
220 | return NULL; | |
221 | } | |
222 | ||
223 | b2Joint* j = b2Joint::Create(def, &m_blockAllocator); | |
224 | ||
225 | // Connect to the world list. | |
226 | j->m_prev = NULL; | |
227 | j->m_next = m_jointList; | |
228 | if (m_jointList) | |
229 | { | |
230 | m_jointList->m_prev = j; | |
231 | } | |
232 | m_jointList = j; | |
233 | ++m_jointCount; | |
234 | ||
235 | // Connect to the bodies' doubly linked lists. | |
236 | j->m_edgeA.joint = j; | |
237 | j->m_edgeA.other = j->m_bodyB; | |
238 | j->m_edgeA.prev = NULL; | |
239 | j->m_edgeA.next = j->m_bodyA->m_jointList; | |
240 | if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; | |
241 | j->m_bodyA->m_jointList = &j->m_edgeA; | |
242 | ||
243 | j->m_edgeB.joint = j; | |
244 | j->m_edgeB.other = j->m_bodyA; | |
245 | j->m_edgeB.prev = NULL; | |
246 | j->m_edgeB.next = j->m_bodyB->m_jointList; | |
247 | if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; | |
248 | j->m_bodyB->m_jointList = &j->m_edgeB; | |
249 | ||
250 | b2Body* bodyA = def->bodyA; | |
251 | b2Body* bodyB = def->bodyB; | |
252 | ||
253 | // If the joint prevents collisions, then flag any contacts for filtering. | |
254 | if (def->collideConnected == false) | |
255 | { | |
256 | b2ContactEdge* edge = bodyB->GetContactList(); | |
257 | while (edge) | |
258 | { | |
259 | if (edge->other == bodyA) | |
260 | { | |
261 | // Flag the contact for filtering at the next time step (where either | |
262 | // body is awake). | |
263 | edge->contact->FlagForFiltering(); | |
264 | } | |
265 | ||
266 | edge = edge->next; | |
267 | } | |
268 | } | |
269 | ||
270 | // Note: creating a joint doesn't wake the bodies. | |
271 | ||
272 | return j; | |
273 | } | |
274 | ||
275 | void b2World::DestroyJoint(b2Joint* j) | |
276 | { | |
277 | b2Assert(IsLocked() == false); | |
278 | if (IsLocked()) | |
279 | { | |
280 | return; | |
281 | } | |
282 | ||
283 | bool collideConnected = j->m_collideConnected; | |
284 | ||
285 | // Remove from the doubly linked list. | |
286 | if (j->m_prev) | |
287 | { | |
288 | j->m_prev->m_next = j->m_next; | |
289 | } | |
290 | ||
291 | if (j->m_next) | |
292 | { | |
293 | j->m_next->m_prev = j->m_prev; | |
294 | } | |
295 | ||
296 | if (j == m_jointList) | |
297 | { | |
298 | m_jointList = j->m_next; | |
299 | } | |
300 | ||
301 | // Disconnect from island graph. | |
302 | b2Body* bodyA = j->m_bodyA; | |
303 | b2Body* bodyB = j->m_bodyB; | |
304 | ||
305 | // Wake up connected bodies. | |
306 | bodyA->SetAwake(true); | |
307 | bodyB->SetAwake(true); | |
308 | ||
309 | // Remove from body 1. | |
310 | if (j->m_edgeA.prev) | |
311 | { | |
312 | j->m_edgeA.prev->next = j->m_edgeA.next; | |
313 | } | |
314 | ||
315 | if (j->m_edgeA.next) | |
316 | { | |
317 | j->m_edgeA.next->prev = j->m_edgeA.prev; | |
318 | } | |
319 | ||
320 | if (&j->m_edgeA == bodyA->m_jointList) | |
321 | { | |
322 | bodyA->m_jointList = j->m_edgeA.next; | |
323 | } | |
324 | ||
325 | j->m_edgeA.prev = NULL; | |
326 | j->m_edgeA.next = NULL; | |
327 | ||
328 | // Remove from body 2 | |
329 | if (j->m_edgeB.prev) | |
330 | { | |
331 | j->m_edgeB.prev->next = j->m_edgeB.next; | |
332 | } | |
333 | ||
334 | if (j->m_edgeB.next) | |
335 | { | |
336 | j->m_edgeB.next->prev = j->m_edgeB.prev; | |
337 | } | |
338 | ||
339 | if (&j->m_edgeB == bodyB->m_jointList) | |
340 | { | |
341 | bodyB->m_jointList = j->m_edgeB.next; | |
342 | } | |
343 | ||
344 | j->m_edgeB.prev = NULL; | |
345 | j->m_edgeB.next = NULL; | |
346 | ||
347 | b2Joint::Destroy(j, &m_blockAllocator); | |
348 | ||
349 | b2Assert(m_jointCount > 0); | |
350 | --m_jointCount; | |
351 | ||
352 | // If the joint prevents collisions, then flag any contacts for filtering. | |
353 | if (collideConnected == false) | |
354 | { | |
355 | b2ContactEdge* edge = bodyB->GetContactList(); | |
356 | while (edge) | |
357 | { | |
358 | if (edge->other == bodyA) | |
359 | { | |
360 | // Flag the contact for filtering at the next time step (where either | |
361 | // body is awake). | |
362 | edge->contact->FlagForFiltering(); | |
363 | } | |
364 | ||
365 | edge = edge->next; | |
366 | } | |
367 | } | |
368 | } | |
369 | ||
370 | // | |
371 | void b2World::SetAllowSleeping(bool flag) | |
372 | { | |
373 | if (flag == m_allowSleep) | |
374 | { | |
375 | return; | |
376 | } | |
377 | ||
378 | m_allowSleep = flag; | |
379 | if (m_allowSleep == false) | |
380 | { | |
381 | for (b2Body* b = m_bodyList; b; b = b->m_next) | |
382 | { | |
383 | b->SetAwake(true); | |
384 | } | |
385 | } | |
386 | } | |
387 | ||
388 | // Find islands, integrate and solve constraints, solve position constraints | |
389 | void b2World::Solve(const b2TimeStep& step) | |
390 | { | |
391 | m_profile.solveInit = 0.0f; | |
392 | m_profile.solveVelocity = 0.0f; | |
393 | m_profile.solvePosition = 0.0f; | |
394 | ||
395 | // Size the island for the worst case. | |
396 | b2Island island(m_bodyCount, | |
397 | m_contactManager.m_contactCount, | |
398 | m_jointCount, | |
399 | &m_stackAllocator, | |
400 | m_contactManager.m_contactListener); | |
401 | ||
402 | // Clear all the island flags. | |
403 | for (b2Body* b = m_bodyList; b; b = b->m_next) | |
404 | { | |
405 | b->m_flags &= ~b2Body::e_islandFlag; | |
406 | } | |
407 | ||
408 | for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) | |
409 | { | |
410 | c->m_flags &= ~b2Contact::e_islandFlag; | |
411 | } | |
412 | ||
413 | for (b2Joint* j = m_jointList; j; j = j->m_next) | |
414 | { | |
415 | j->m_islandFlag = false; | |
416 | } | |
417 | ||
418 | // Build and simulate all awake islands. | |
419 | int32 stackSize = m_bodyCount; | |
420 | b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); | |
421 | for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) | |
422 | { | |
423 | if (seed->m_flags & b2Body::e_islandFlag) | |
424 | { | |
425 | continue; | |
426 | } | |
427 | ||
428 | if (seed->IsAwake() == false || seed->IsActive() == false) | |
429 | { | |
430 | continue; | |
431 | } | |
432 | ||
433 | // The seed can be dynamic or kinematic. | |
434 | if (seed->GetType() == b2_staticBody) | |
435 | { | |
436 | continue; | |
437 | } | |
438 | ||
439 | //printf("{N}"); | |
440 | //fflush(stdout); | |
441 | // Reset island and stack. | |
442 | island.Clear(); | |
443 | int32 stackCount = 0; | |
444 | stack[stackCount++] = seed; | |
445 | seed->m_flags |= b2Body::e_islandFlag; | |
446 | ||
447 | // Perform a depth first search (DFS) on the constraint graph. | |
448 | while (stackCount > 0) | |
449 | { | |
450 | // Grab the next body off the stack and add it to the island. | |
451 | b2Body* b = stack[--stackCount]; | |
452 | b2Assert(b->IsActive() == true); | |
453 | island.Add(b); | |
454 | ||
455 | // Make sure the body is awake. | |
456 | b->SetAwake(true); | |
457 | ||
458 | // To keep islands as small as possible, we don't | |
459 | // propagate islands across static bodies. | |
460 | if (b->GetType() == b2_staticBody) | |
461 | { | |
462 | continue; | |
463 | } | |
464 | ||
465 | // Search all contacts connected to this body. | |
466 | for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) | |
467 | { | |
468 | b2Contact* contact = ce->contact; | |
469 | ||
470 | // Has this contact already been added to an island? | |
471 | if (contact->m_flags & b2Contact::e_islandFlag) | |
472 | { | |
473 | continue; | |
474 | } | |
475 | ||
476 | // Is this contact solid and touching? | |
477 | if (contact->IsEnabled() == false || | |
478 | contact->IsTouching() == false) | |
479 | { | |
480 | continue; | |
481 | } | |
482 | ||
483 | // Skip sensors. | |
484 | bool sensorA = contact->m_fixtureA->m_isSensor; | |
485 | bool sensorB = contact->m_fixtureB->m_isSensor; | |
486 | if (sensorA || sensorB) | |
487 | { | |
488 | continue; | |
489 | } | |
490 | ||
491 | island.Add(contact); | |
492 | contact->m_flags |= b2Contact::e_islandFlag; | |
493 | ||
494 | b2Body* other = ce->other; | |
495 | ||
496 | // Was the other body already added to this island? | |
497 | if (other->m_flags & b2Body::e_islandFlag) | |
498 | { | |
499 | continue; | |
500 | } | |
501 | ||
502 | b2Assert(stackCount < stackSize); | |
503 | stack[stackCount++] = other; | |
504 | other->m_flags |= b2Body::e_islandFlag; | |
505 | } | |
506 | ||
507 | // Search all joints connect to this body. | |
508 | for (b2JointEdge* je = b->m_jointList; je; je = je->next) | |
509 | { | |
510 | if (je->joint->m_islandFlag == true) | |
511 | { | |
512 | continue; | |
513 | } | |
514 | ||
515 | b2Body* other = je->other; | |
516 | ||
517 | // Don't simulate joints connected to inactive bodies. | |
518 | if (other->IsActive() == false) | |
519 | { | |
520 | continue; | |
521 | } | |
522 | ||
523 | island.Add(je->joint); | |
524 | je->joint->m_islandFlag = true; | |
525 | ||
526 | if (other->m_flags & b2Body::e_islandFlag) | |
527 | { | |
528 | continue; | |
529 | } | |
530 | ||
531 | b2Assert(stackCount < stackSize); | |
532 | stack[stackCount++] = other; | |
533 | other->m_flags |= b2Body::e_islandFlag; | |
534 | } | |
535 | } | |
536 | ||
537 | //printf("{M}"); | |
538 | //fflush(stdout); | |
539 | b2Profile profile; | |
540 | island.Solve(&profile, step, m_gravity, m_allowSleep); | |
541 | m_profile.solveInit += profile.solveInit; | |
542 | m_profile.solveVelocity += profile.solveVelocity; | |
543 | m_profile.solvePosition += profile.solvePosition; | |
544 | ||
545 | //printf("{;}"); | |
546 | //fflush(stdout); | |
547 | // Post solve cleanup. | |
548 | for (int32 i = 0; i < island.m_bodyCount; ++i) | |
549 | { | |
550 | // Allow static bodies to participate in other islands. | |
551 | b2Body* b = island.m_bodies[i]; | |
552 | if (b->GetType() == b2_staticBody) | |
553 | { | |
554 | b->m_flags &= ~b2Body::e_islandFlag; | |
555 | } | |
556 | } | |
557 | } | |
558 | ||
559 | m_stackAllocator.Free(stack); | |
560 | ||
561 | { | |
562 | b2Timer timer; | |
563 | // Synchronize fixtures, check for out of range bodies. | |
564 | for (b2Body* b = m_bodyList; b; b = b->GetNext()) | |
565 | { | |
566 | // If a body was not in an island then it did not move. | |
567 | if ((b->m_flags & b2Body::e_islandFlag) == 0) | |
568 | { | |
569 | continue; | |
570 | } | |
571 | ||
572 | if (b->GetType() == b2_staticBody) | |
573 | { | |
574 | continue; | |
575 | } | |
576 | ||
577 | // Update fixtures (for broad-phase). | |
578 | b->SynchronizeFixtures(); | |
579 | } | |
580 | ||
581 | // Look for new contacts. | |
582 | m_contactManager.FindNewContacts(); | |
583 | m_profile.broadphase = timer.GetMilliseconds(); | |
584 | } | |
585 | } | |
586 | ||
587 | // Find TOI contacts and solve them. | |
588 | void b2World::SolveTOI(const b2TimeStep& step) | |
589 | { | |
590 | ||
591 | printf("\n"); | |
592 | printf("{A}"); | |
593 | fflush(stdout); | |
594 | ||
595 | b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); | |
596 | printf("{B}"); | |
597 | fflush(stdout); | |
598 | ||
599 | if (m_stepComplete) | |
600 | { | |
601 | for (b2Body* b = m_bodyList; b; b = b->m_next) | |
602 | { | |
603 | b->m_flags &= ~b2Body::e_islandFlag; | |
604 | b->m_sweep.alpha0 = 0.0f; | |
605 | } | |
606 | printf("{C}"); | |
607 | fflush(stdout); | |
608 | ||
609 | for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) | |
610 | { | |
611 | // Invalidate TOI | |
612 | c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); | |
613 | c->m_toiCount = 0; | |
614 | c->m_toi = 1.0f; | |
615 | } | |
616 | } | |
617 | printf("{D}"); | |
618 | fflush(stdout); | |
619 | ||
620 | // Find TOI events and solve them. | |
621 | for (;;) | |
622 | { | |
623 | // Find the first TOI. | |
624 | b2Contact* minContact = NULL; | |
625 | float32 minAlpha = 1.0f; | |
626 | - | int32 contactCount = 0; |
626 | + | |
627 | - | int32 contactProcessedCount = 0; |
627 | + | |
628 | { | |
629 | // Is this contact disabled? | |
630 | if (c->IsEnabled() == false) | |
631 | - | contactCount++; |
631 | + | |
632 | continue; | |
633 | } | |
634 | ||
635 | // Prevent excessive sub-stepping. | |
636 | if (c->m_toiCount > b2_maxSubSteps) | |
637 | { | |
638 | continue; | |
639 | } | |
640 | ||
641 | float32 alpha = 1.0f; | |
642 | if (c->m_flags & b2Contact::e_toiFlag) | |
643 | { | |
644 | // This contact has a valid cached TOI. | |
645 | alpha = c->m_toi; | |
646 | } | |
647 | else | |
648 | { | |
649 | b2Fixture* fA = c->GetFixtureA(); | |
650 | b2Fixture* fB = c->GetFixtureB(); | |
651 | ||
652 | // Is there a sensor? | |
653 | if (fA->IsSensor() || fB->IsSensor()) | |
654 | { | |
655 | continue; | |
656 | } | |
657 | ||
658 | b2Body* bA = fA->GetBody(); | |
659 | b2Body* bB = fB->GetBody(); | |
660 | ||
661 | b2BodyType typeA = bA->m_type; | |
662 | b2BodyType typeB = bB->m_type; | |
663 | b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); | |
664 | ||
665 | bool activeA = bA->IsAwake() && typeA != b2_staticBody; | |
666 | bool activeB = bB->IsAwake() && typeB != b2_staticBody; | |
667 | ||
668 | // Is at least one body active (awake and dynamic or kinematic)? | |
669 | if (activeA == false && activeB == false) | |
670 | { | |
671 | continue; | |
672 | } | |
673 | ||
674 | bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; | |
675 | bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; | |
676 | ||
677 | // Are these two non-bullet dynamic bodies? | |
678 | if (collideA == false && collideB == false) | |
679 | { | |
680 | continue; | |
681 | } | |
682 | ||
683 | // Compute the TOI for this contact. | |
684 | // Put the sweeps onto the same time interval. | |
685 | float32 alpha0 = bA->m_sweep.alpha0; | |
686 | ||
687 | if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) | |
688 | { | |
689 | alpha0 = bB->m_sweep.alpha0; | |
690 | bA->m_sweep.Advance(alpha0); | |
691 | } | |
692 | else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) | |
693 | { | |
694 | alpha0 = bA->m_sweep.alpha0; | |
695 | bB->m_sweep.Advance(alpha0); | |
696 | } | |
697 | ||
698 | b2Assert(alpha0 < 1.0f); | |
699 | ||
700 | int32 indexA = c->GetChildIndexA(); | |
701 | int32 indexB = c->GetChildIndexB(); | |
702 | ||
703 | // Compute the time of impact in interval [0, minTOI] | |
704 | b2TOIInput input; | |
705 | input.proxyA.Set(fA->GetShape(), indexA); | |
706 | input.proxyB.Set(fB->GetShape(), indexB); | |
707 | input.sweepA = bA->m_sweep; | |
708 | input.sweepB = bB->m_sweep; | |
709 | input.tMax = 1.0f; | |
710 | ||
711 | b2TOIOutput output; | |
712 | b2TimeOfImpact(&output, &input); | |
713 | ||
714 | // Beta is the fraction of the remaining portion of the . | |
715 | float32 beta = output.t; | |
716 | if (output.state == b2TOIOutput::e_touching) | |
717 | { | |
718 | alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); | |
719 | } | |
720 | else | |
721 | { | |
722 | alpha = 1.0f; | |
723 | } | |
724 | ||
725 | c->m_toi = alpha; | |
726 | c->m_flags |= b2Contact::e_toiFlag; | |
727 | } | |
728 | ||
729 | if (alpha < minAlpha) | |
730 | - | contactProcessedCount++; |
730 | + | |
731 | // This is the minimum TOI found so far. | |
732 | minContact = c; | |
733 | minAlpha = alpha; | |
734 | } | |
735 | } | |
736 | ||
737 | if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) | |
738 | { | |
739 | printf("{E2}"); | |
740 | - | printf("{c"); |
740 | + | |
741 | - | printf("%d",contactProcessedCount); |
741 | + | |
742 | - | printf("/"); |
742 | + | |
743 | - | printf("%d",contactCount); |
743 | + | |
744 | - | printf("}"); |
744 | + | |
745 | printf("{E1}"); | |
746 | fflush(stdout); | |
747 | } | |
748 | ||
749 | // Advance the bodies to the TOI. | |
750 | b2Fixture* fA = minContact->GetFixtureA(); | |
751 | b2Fixture* fB = minContact->GetFixtureB(); | |
752 | b2Body* bA = fA->GetBody(); | |
753 | b2Body* bB = fB->GetBody(); | |
754 | ||
755 | b2Sweep backup1 = bA->m_sweep; | |
756 | b2Sweep backup2 = bB->m_sweep; | |
757 | ||
758 | bA->Advance(minAlpha); | |
759 | bB->Advance(minAlpha); | |
760 | printf("{F}"); | |
761 | fflush(stdout); | |
762 | ||
763 | // The TOI contact likely has some new contact points. | |
764 | minContact->Update(m_contactManager.m_contactListener); | |
765 | minContact->m_flags &= ~b2Contact::e_toiFlag; | |
766 | ++minContact->m_toiCount; | |
767 | ||
768 | printf("{G}"); | |
769 | fflush(stdout); | |
770 | // Is the contact solid? | |
771 | if (minContact->IsEnabled() == false || minContact->IsTouching() == false) | |
772 | { | |
773 | // Restore the sweeps. | |
774 | minContact->SetEnabled(false); | |
775 | bA->m_sweep = backup1; | |
776 | bB->m_sweep = backup2; | |
777 | bA->SynchronizeTransform(); | |
778 | bB->SynchronizeTransform(); | |
779 | continue; | |
780 | } | |
781 | ||
782 | bA->SetAwake(true); | |
783 | bB->SetAwake(true); | |
784 | ||
785 | // Build the island | |
786 | island.Clear(); | |
787 | island.Add(bA); | |
788 | island.Add(bB); | |
789 | island.Add(minContact); | |
790 | ||
791 | bA->m_flags |= b2Body::e_islandFlag; | |
792 | bB->m_flags |= b2Body::e_islandFlag; | |
793 | minContact->m_flags |= b2Contact::e_islandFlag; | |
794 | ||
795 | // Get contacts on bodyA and bodyB. | |
796 | b2Body* bodies[2] = {bA, bB}; | |
797 | for (int32 i = 0; i < 2; ++i) | |
798 | { | |
799 | b2Body* body = bodies[i]; | |
800 | if (body->m_type == b2_dynamicBody) | |
801 | { | |
802 | for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) | |
803 | { | |
804 | if (island.m_bodyCount == island.m_bodyCapacity) | |
805 | { | |
806 | break; | |
807 | } | |
808 | ||
809 | if (island.m_contactCount == island.m_contactCapacity) | |
810 | { | |
811 | break; | |
812 | } | |
813 | ||
814 | b2Contact* contact = ce->contact; | |
815 | ||
816 | // Has this contact already been added to the island? | |
817 | if (contact->m_flags & b2Contact::e_islandFlag) | |
818 | { | |
819 | continue; | |
820 | } | |
821 | ||
822 | // Only add static, kinematic, or bullet bodies. | |
823 | b2Body* other = ce->other; | |
824 | if (other->m_type == b2_dynamicBody && | |
825 | body->IsBullet() == false && other->IsBullet() == false) | |
826 | { | |
827 | continue; | |
828 | } | |
829 | ||
830 | // Skip sensors. | |
831 | bool sensorA = contact->m_fixtureA->m_isSensor; | |
832 | bool sensorB = contact->m_fixtureB->m_isSensor; | |
833 | if (sensorA || sensorB) | |
834 | { | |
835 | continue; | |
836 | } | |
837 | ||
838 | // Tentatively advance the body to the TOI. | |
839 | b2Sweep backup = other->m_sweep; | |
840 | if ((other->m_flags & b2Body::e_islandFlag) == 0) | |
841 | { | |
842 | other->Advance(minAlpha); | |
843 | } | |
844 | ||
845 | // Update the contact points | |
846 | contact->Update(m_contactManager.m_contactListener); | |
847 | ||
848 | // Was the contact disabled by the user? | |
849 | if (contact->IsEnabled() == false) | |
850 | { | |
851 | other->m_sweep = backup; | |
852 | other->SynchronizeTransform(); | |
853 | continue; | |
854 | } | |
855 | ||
856 | // Are there contact points? | |
857 | if (contact->IsTouching() == false) | |
858 | { | |
859 | other->m_sweep = backup; | |
860 | other->SynchronizeTransform(); | |
861 | continue; | |
862 | } | |
863 | ||
864 | // Add the contact to the island | |
865 | contact->m_flags |= b2Contact::e_islandFlag; | |
866 | island.Add(contact); | |
867 | ||
868 | // Has the other body already been added to the island? | |
869 | if (other->m_flags & b2Body::e_islandFlag) | |
870 | { | |
871 | continue; | |
872 | } | |
873 | ||
874 | // Add the other body to the island. | |
875 | other->m_flags |= b2Body::e_islandFlag; | |
876 | ||
877 | if (other->m_type != b2_staticBody) | |
878 | { | |
879 | other->SetAwake(true); | |
880 | } | |
881 | ||
882 | island.Add(other); | |
883 | } | |
884 | } | |
885 | } | |
886 | printf("{H}"); | |
887 | fflush(stdout); | |
888 | ||
889 | b2TimeStep subStep; | |
890 | subStep.dt = (1.0f - minAlpha) * step.dt; | |
891 | subStep.inv_dt = 1.0f / subStep.dt; | |
892 | subStep.dtRatio = 1.0f; | |
893 | subStep.positionIterations = 20; | |
894 | subStep.velocityIterations = step.velocityIterations; | |
895 | subStep.warmStarting = false; | |
896 | island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); | |
897 | printf("{I}"); | |
898 | fflush(stdout); | |
899 | ||
900 | // Reset island flags and synchronize broad-phase proxies. | |
901 | for (int32 i = 0; i < island.m_bodyCount; ++i) | |
902 | { | |
903 | b2Body* body = island.m_bodies[i]; | |
904 | body->m_flags &= ~b2Body::e_islandFlag; | |
905 | ||
906 | if (body->m_type != b2_dynamicBody) | |
907 | { | |
908 | continue; | |
909 | } | |
910 | ||
911 | body->SynchronizeFixtures(); | |
912 | ||
913 | // Invalidate all contact TOIs on this displaced body. | |
914 | for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) | |
915 | { | |
916 | ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); | |
917 | } | |
918 | } | |
919 | printf("{J}"); | |
920 | fflush(stdout); | |
921 | ||
922 | // Commit fixture proxy movements to the broad-phase so that new contacts are created. | |
923 | // Also, some contacts can be destroyed. | |
924 | m_contactManager.FindNewContacts(); | |
925 | printf("{K}"); | |
926 | fflush(stdout); | |
927 | ||
928 | if (m_subStepping) | |
929 | { | |
930 | m_stepComplete = false; | |
931 | break; | |
932 | } | |
933 | } | |
934 | } | |
935 | ||
936 | void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) | |
937 | { | |
938 | b2Timer stepTimer; | |
939 | ||
940 | // If new fixtures were added, we need to find the new contacts. | |
941 | if (m_flags & e_newFixture) | |
942 | { | |
943 | m_contactManager.FindNewContacts(); | |
944 | m_flags &= ~e_newFixture; | |
945 | } | |
946 | ||
947 | m_flags |= e_locked; | |
948 | ||
949 | b2TimeStep step; | |
950 | step.dt = dt; | |
951 | step.velocityIterations = velocityIterations; | |
952 | step.positionIterations = positionIterations; | |
953 | if (dt > 0.0f) | |
954 | { | |
955 | step.inv_dt = 1.0f / dt; | |
956 | } | |
957 | else | |
958 | { | |
959 | step.inv_dt = 0.0f; | |
960 | } | |
961 | ||
962 | step.dtRatio = m_inv_dt0 * dt; | |
963 | ||
964 | step.warmStarting = m_warmStarting; | |
965 | ||
966 | // Update contacts. This is where some contacts are destroyed. | |
967 | { | |
968 | b2Timer timer; | |
969 | m_contactManager.Collide(); | |
970 | m_profile.collide = timer.GetMilliseconds(); | |
971 | } | |
972 | ||
973 | // Integrate velocities, solve velocity constraints, and integrate positions. | |
974 | if (m_stepComplete && step.dt > 0.0f) | |
975 | { | |
976 | b2Timer timer; | |
977 | Solve(step); | |
978 | m_profile.solve = timer.GetMilliseconds(); | |
979 | } | |
980 | ||
981 | // Handle TOI events. | |
982 | if (m_continuousPhysics && step.dt > 0.0f) | |
983 | { | |
984 | b2Timer timer; | |
985 | SolveTOI(step); | |
986 | m_profile.solveTOI = timer.GetMilliseconds(); | |
987 | } | |
988 | ||
989 | if (step.dt > 0.0f) | |
990 | { | |
991 | m_inv_dt0 = step.inv_dt; | |
992 | } | |
993 | ||
994 | if (m_flags & e_clearForces) | |
995 | { | |
996 | ClearForces(); | |
997 | } | |
998 | ||
999 | m_flags &= ~e_locked; | |
1000 | ||
1001 | m_profile.step = stepTimer.GetMilliseconds(); | |
1002 | ||
1003 | printf("\n"); | |
1004 | printf("{PR|"); | |
1005 | printf("%.2f", m_profile.step); | |
1006 | printf("|"); | |
1007 | printf("%.2f", m_profile.collide); | |
1008 | printf("|"); | |
1009 | printf("%.2f", m_profile.solve); | |
1010 | printf("|"); | |
1011 | printf("%.2f", m_profile.solveInit); | |
1012 | printf("|"); | |
1013 | printf("%.2f", m_profile.solveVelocity); | |
1014 | printf("|"); | |
1015 | printf("%.2f", m_profile.solvePosition); | |
1016 | printf("|"); | |
1017 | printf("%.2f", m_profile.solveTOI); | |
1018 | printf("|"); | |
1019 | printf("%.2f", m_profile.broadphase); | |
1020 | printf("}"); | |
1021 | fflush(stdout); | |
1022 | ||
1023 | } | |
1024 | ||
1025 | void b2World::ClearForces() | |
1026 | { | |
1027 | for (b2Body* body = m_bodyList; body; body = body->GetNext()) | |
1028 | { | |
1029 | body->m_force.SetZero(); | |
1030 | body->m_torque = 0.0f; | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | struct b2WorldQueryWrapper | |
1035 | { | |
1036 | bool QueryCallback(int32 proxyId) | |
1037 | { | |
1038 | b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); | |
1039 | return callback->ReportFixture(proxy->fixture); | |
1040 | } | |
1041 | ||
1042 | const b2BroadPhase* broadPhase; | |
1043 | b2QueryCallback* callback; | |
1044 | }; | |
1045 | ||
1046 | void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const | |
1047 | { | |
1048 | b2WorldQueryWrapper wrapper; | |
1049 | wrapper.broadPhase = &m_contactManager.m_broadPhase; | |
1050 | wrapper.callback = callback; | |
1051 | m_contactManager.m_broadPhase.Query(&wrapper, aabb); | |
1052 | } | |
1053 | ||
1054 | struct b2WorldRayCastWrapper | |
1055 | { | |
1056 | float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) | |
1057 | { | |
1058 | void* userData = broadPhase->GetUserData(proxyId); | |
1059 | b2FixtureProxy* proxy = (b2FixtureProxy*)userData; | |
1060 | b2Fixture* fixture = proxy->fixture; | |
1061 | int32 index = proxy->childIndex; | |
1062 | b2RayCastOutput output; | |
1063 | bool hit = fixture->RayCast(&output, input, index); | |
1064 | ||
1065 | if (hit) | |
1066 | { | |
1067 | float32 fraction = output.fraction; | |
1068 | b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; | |
1069 | return callback->ReportFixture(fixture, point, output.normal, fraction); | |
1070 | } | |
1071 | ||
1072 | return input.maxFraction; | |
1073 | } | |
1074 | ||
1075 | const b2BroadPhase* broadPhase; | |
1076 | b2RayCastCallback* callback; | |
1077 | }; | |
1078 | ||
1079 | void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const | |
1080 | { | |
1081 | b2WorldRayCastWrapper wrapper; | |
1082 | wrapper.broadPhase = &m_contactManager.m_broadPhase; | |
1083 | wrapper.callback = callback; | |
1084 | b2RayCastInput input; | |
1085 | input.maxFraction = 1.0f; | |
1086 | input.p1 = point1; | |
1087 | input.p2 = point2; | |
1088 | m_contactManager.m_broadPhase.RayCast(&wrapper, input); | |
1089 | } | |
1090 | ||
1091 | void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) | |
1092 | { | |
1093 | switch (fixture->GetType()) | |
1094 | { | |
1095 | case b2Shape::e_circle: | |
1096 | { | |
1097 | b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); | |
1098 | ||
1099 | b2Vec2 center = b2Mul(xf, circle->m_p); | |
1100 | float32 radius = circle->m_radius; | |
1101 | b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); | |
1102 | ||
1103 | g_debugDraw->DrawSolidCircle(center, radius, axis, color); | |
1104 | } | |
1105 | break; | |
1106 | ||
1107 | case b2Shape::e_edge: | |
1108 | { | |
1109 | b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); | |
1110 | b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); | |
1111 | b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); | |
1112 | g_debugDraw->DrawSegment(v1, v2, color); | |
1113 | } | |
1114 | break; | |
1115 | ||
1116 | case b2Shape::e_chain: | |
1117 | { | |
1118 | b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); | |
1119 | int32 count = chain->m_count; | |
1120 | const b2Vec2* vertices = chain->m_vertices; | |
1121 | ||
1122 | b2Vec2 v1 = b2Mul(xf, vertices[0]); | |
1123 | for (int32 i = 1; i < count; ++i) | |
1124 | { | |
1125 | b2Vec2 v2 = b2Mul(xf, vertices[i]); | |
1126 | g_debugDraw->DrawSegment(v1, v2, color); | |
1127 | g_debugDraw->DrawCircle(v1, 0.05f, color); | |
1128 | v1 = v2; | |
1129 | } | |
1130 | } | |
1131 | break; | |
1132 | ||
1133 | case b2Shape::e_polygon: | |
1134 | { | |
1135 | b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); | |
1136 | int32 vertexCount = poly->m_count; | |
1137 | b2Assert(vertexCount <= b2_maxPolygonVertices); | |
1138 | b2Vec2 vertices[b2_maxPolygonVertices]; | |
1139 | ||
1140 | for (int32 i = 0; i < vertexCount; ++i) | |
1141 | { | |
1142 | vertices[i] = b2Mul(xf, poly->m_vertices[i]); | |
1143 | } | |
1144 | ||
1145 | g_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); | |
1146 | } | |
1147 | break; | |
1148 | ||
1149 | default: | |
1150 | break; | |
1151 | } | |
1152 | } | |
1153 | ||
1154 | void b2World::DrawJoint(b2Joint* joint) | |
1155 | { | |
1156 | b2Body* bodyA = joint->GetBodyA(); | |
1157 | b2Body* bodyB = joint->GetBodyB(); | |
1158 | const b2Transform& xf1 = bodyA->GetTransform(); | |
1159 | const b2Transform& xf2 = bodyB->GetTransform(); | |
1160 | b2Vec2 x1 = xf1.p; | |
1161 | b2Vec2 x2 = xf2.p; | |
1162 | b2Vec2 p1 = joint->GetAnchorA(); | |
1163 | b2Vec2 p2 = joint->GetAnchorB(); | |
1164 | ||
1165 | b2Color color(0.5f, 0.8f, 0.8f); | |
1166 | ||
1167 | switch (joint->GetType()) | |
1168 | { | |
1169 | case e_distanceJoint: | |
1170 | g_debugDraw->DrawSegment(p1, p2, color); | |
1171 | break; | |
1172 | ||
1173 | case e_pulleyJoint: | |
1174 | { | |
1175 | b2PulleyJoint* pulley = (b2PulleyJoint*)joint; | |
1176 | b2Vec2 s1 = pulley->GetGroundAnchorA(); | |
1177 | b2Vec2 s2 = pulley->GetGroundAnchorB(); | |
1178 | g_debugDraw->DrawSegment(s1, p1, color); | |
1179 | g_debugDraw->DrawSegment(s2, p2, color); | |
1180 | g_debugDraw->DrawSegment(s1, s2, color); | |
1181 | } | |
1182 | break; | |
1183 | ||
1184 | case e_mouseJoint: | |
1185 | // don't draw this | |
1186 | break; | |
1187 | ||
1188 | default: | |
1189 | g_debugDraw->DrawSegment(x1, p1, color); | |
1190 | g_debugDraw->DrawSegment(p1, p2, color); | |
1191 | g_debugDraw->DrawSegment(x2, p2, color); | |
1192 | } | |
1193 | } | |
1194 | ||
1195 | void b2World::DrawDebugData() | |
1196 | { | |
1197 | if (g_debugDraw == NULL) | |
1198 | { | |
1199 | return; | |
1200 | } | |
1201 | ||
1202 | uint32 flags = g_debugDraw->GetFlags(); | |
1203 | ||
1204 | if (flags & b2Draw::e_shapeBit) | |
1205 | { | |
1206 | for (b2Body* b = m_bodyList; b; b = b->GetNext()) | |
1207 | { | |
1208 | const b2Transform& xf = b->GetTransform(); | |
1209 | for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) | |
1210 | { | |
1211 | if (b->IsActive() == false) | |
1212 | { | |
1213 | DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); | |
1214 | } | |
1215 | else if (b->GetType() == b2_staticBody) | |
1216 | { | |
1217 | DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); | |
1218 | } | |
1219 | else if (b->GetType() == b2_kinematicBody) | |
1220 | { | |
1221 | DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); | |
1222 | } | |
1223 | else if (b->IsAwake() == false) | |
1224 | { | |
1225 | DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); | |
1226 | } | |
1227 | else | |
1228 | { | |
1229 | DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); | |
1230 | } | |
1231 | } | |
1232 | } | |
1233 | } | |
1234 | ||
1235 | if (flags & b2Draw::e_jointBit) | |
1236 | { | |
1237 | for (b2Joint* j = m_jointList; j; j = j->GetNext()) | |
1238 | { | |
1239 | DrawJoint(j); | |
1240 | } | |
1241 | } | |
1242 | ||
1243 | if (flags & b2Draw::e_pairBit) | |
1244 | { | |
1245 | b2Color color(0.3f, 0.9f, 0.9f); | |
1246 | for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) | |
1247 | { | |
1248 | //b2Fixture* fixtureA = c->GetFixtureA(); | |
1249 | //b2Fixture* fixtureB = c->GetFixtureB(); | |
1250 | ||
1251 | //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); | |
1252 | //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); | |
1253 | ||
1254 | //g_debugDraw->DrawSegment(cA, cB, color); | |
1255 | } | |
1256 | } | |
1257 | ||
1258 | if (flags & b2Draw::e_aabbBit) | |
1259 | { | |
1260 | b2Color color(0.9f, 0.3f, 0.9f); | |
1261 | b2BroadPhase* bp = &m_contactManager.m_broadPhase; | |
1262 | ||
1263 | for (b2Body* b = m_bodyList; b; b = b->GetNext()) | |
1264 | { | |
1265 | if (b->IsActive() == false) | |
1266 | { | |
1267 | continue; | |
1268 | } | |
1269 | ||
1270 | for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) | |
1271 | { | |
1272 | for (int32 i = 0; i < f->m_proxyCount; ++i) | |
1273 | { | |
1274 | b2FixtureProxy* proxy = f->m_proxies + i; | |
1275 | b2AABB aabb = bp->GetFatAABB(proxy->proxyId); | |
1276 | b2Vec2 vs[4]; | |
1277 | vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); | |
1278 | vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); | |
1279 | vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); | |
1280 | vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); | |
1281 | ||
1282 | g_debugDraw->DrawPolygon(vs, 4, color); | |
1283 | } | |
1284 | } | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | if (flags & b2Draw::e_centerOfMassBit) | |
1289 | { | |
1290 | for (b2Body* b = m_bodyList; b; b = b->GetNext()) | |
1291 | { | |
1292 | b2Transform xf = b->GetTransform(); | |
1293 | xf.p = b->GetWorldCenter(); | |
1294 | g_debugDraw->DrawTransform(xf); | |
1295 | } | |
1296 | } | |
1297 | } | |
1298 | ||
1299 | int32 b2World::GetProxyCount() const | |
1300 | { | |
1301 | return m_contactManager.m_broadPhase.GetProxyCount(); | |
1302 | } | |
1303 | ||
1304 | int32 b2World::GetTreeHeight() const | |
1305 | { | |
1306 | return m_contactManager.m_broadPhase.GetTreeHeight(); | |
1307 | } | |
1308 | ||
1309 | int32 b2World::GetTreeBalance() const | |
1310 | { | |
1311 | return m_contactManager.m_broadPhase.GetTreeBalance(); | |
1312 | } | |
1313 | ||
1314 | float32 b2World::GetTreeQuality() const | |
1315 | { | |
1316 | return m_contactManager.m_broadPhase.GetTreeQuality(); | |
1317 | } | |
1318 | ||
1319 | void b2World::ShiftOrigin(const b2Vec2& newOrigin) | |
1320 | { | |
1321 | b2Assert((m_flags & e_locked) == 0); | |
1322 | if ((m_flags & e_locked) == e_locked) | |
1323 | { | |
1324 | return; | |
1325 | } | |
1326 | ||
1327 | for (b2Body* b = m_bodyList; b; b = b->m_next) | |
1328 | { | |
1329 | b->m_xf.p -= newOrigin; | |
1330 | b->m_sweep.c0 -= newOrigin; | |
1331 | b->m_sweep.c -= newOrigin; | |
1332 | } | |
1333 | ||
1334 | for (b2Joint* j = m_jointList; j; j = j->m_next) | |
1335 | { | |
1336 | j->ShiftOrigin(newOrigin); | |
1337 | } | |
1338 | ||
1339 | m_contactManager.m_broadPhase.ShiftOrigin(newOrigin); | |
1340 | } | |
1341 | ||
1342 | void b2World::Dump() | |
1343 | { | |
1344 | if ((m_flags & e_locked) == e_locked) | |
1345 | { | |
1346 | return; | |
1347 | } | |
1348 | ||
1349 | b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); | |
1350 | b2Log("m_world->SetGravity(g);\n"); | |
1351 | ||
1352 | b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); | |
1353 | b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); | |
1354 | int32 i = 0; | |
1355 | for (b2Body* b = m_bodyList; b; b = b->m_next) | |
1356 | { | |
1357 | b->m_islandIndex = i; | |
1358 | b->Dump(); | |
1359 | ++i; | |
1360 | } | |
1361 | ||
1362 | i = 0; | |
1363 | for (b2Joint* j = m_jointList; j; j = j->m_next) | |
1364 | { | |
1365 | j->m_index = i; | |
1366 | ++i; | |
1367 | } | |
1368 | ||
1369 | // First pass on joints, skip gear joints. | |
1370 | for (b2Joint* j = m_jointList; j; j = j->m_next) | |
1371 | { | |
1372 | if (j->m_type == e_gearJoint) | |
1373 | { | |
1374 | continue; | |
1375 | } | |
1376 | ||
1377 | b2Log("{\n"); | |
1378 | j->Dump(); | |
1379 | b2Log("}\n"); | |
1380 | } | |
1381 | ||
1382 | // Second pass on joints, only gear joints. | |
1383 | for (b2Joint* j = m_jointList; j; j = j->m_next) | |
1384 | { | |
1385 | if (j->m_type != e_gearJoint) | |
1386 | { | |
1387 | continue; | |
1388 | } | |
1389 | ||
1390 | b2Log("{\n"); | |
1391 | j->Dump(); | |
1392 | b2Log("}\n"); | |
1393 | } | |
1394 | ||
1395 | b2Log("b2Free(joints);\n"); | |
1396 | b2Log("b2Free(bodies);\n"); | |
1397 | b2Log("joints = NULL;\n"); | |
1398 | b2Log("bodies = NULL;\n"); | |
1399 | } |