first commit
[blok] / Box2D / Source / Dynamics / Contacts / b2Contact.cpp
1 /*
2 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
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 "b2Contact.h"
20 #include "b2CircleContact.h"
21 #include "b2PolyAndCircleContact.h"
22 #include "b2PolyContact.h"
23 #include "b2ContactSolver.h"
24 #include "../../Collision/b2Collision.h"
25 #include "../../Collision/Shapes/b2Shape.h"
26 #include "../../Common/b2BlockAllocator.h"
27 #include "../../Dynamics/b2World.h"
28 #include "../../Dynamics/b2Body.h"
29
30 b2ContactRegister b2Contact::s_registers[e_shapeTypeCount][e_shapeTypeCount];
31 bool b2Contact::s_initialized = false;
32
33 void b2Contact::InitializeRegisters()
34 {
35         AddType(b2CircleContact::Create, b2CircleContact::Destroy, e_circleShape, e_circleShape);
36         AddType(b2PolyAndCircleContact::Create, b2PolyAndCircleContact::Destroy, e_polygonShape, e_circleShape);
37         AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, e_polygonShape, e_polygonShape);
38 }
39
40 void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,
41                                           b2ShapeType type1, b2ShapeType type2)
42 {
43         b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount);
44         b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount);
45         
46         s_registers[type1][type2].createFcn = createFcn;
47         s_registers[type1][type2].destroyFcn = destoryFcn;
48         s_registers[type1][type2].primary = true;
49
50         if (type1 != type2)
51         {
52                 s_registers[type2][type1].createFcn = createFcn;
53                 s_registers[type2][type1].destroyFcn = destoryFcn;
54                 s_registers[type2][type1].primary = false;
55         }
56 }
57
58 b2Contact* b2Contact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator)
59 {
60         if (s_initialized == false)
61         {
62                 InitializeRegisters();
63                 s_initialized = true;
64         }
65
66         b2ShapeType type1 = shape1->GetType();
67         b2ShapeType type2 = shape2->GetType();
68
69         b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount);
70         b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount);
71         
72         b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
73         if (createFcn)
74         {
75                 if (s_registers[type1][type2].primary)
76                 {
77                         return createFcn(shape1, shape2, allocator);
78                 }
79                 else
80                 {
81                         b2Contact* c = createFcn(shape2, shape1, allocator);
82                         for (int32 i = 0; i < c->GetManifoldCount(); ++i)
83                         {
84                                 b2Manifold* m = c->GetManifolds() + i;
85                                 m->normal = -m->normal;
86                         }
87                         return c;
88                 }
89         }
90         else
91         {
92                 return NULL;
93         }
94 }
95
96 void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
97 {
98         b2Assert(s_initialized == true);
99
100         if (contact->GetManifoldCount() > 0)
101         {
102                 contact->GetShape1()->GetBody()->WakeUp();
103                 contact->GetShape2()->GetBody()->WakeUp();
104         }
105
106         b2ShapeType type1 = contact->GetShape1()->GetType();
107         b2ShapeType type2 = contact->GetShape2()->GetType();
108
109         b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount);
110         b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount);
111
112         b2ContactDestroyFcn* destroyFcn = s_registers[type1][type2].destroyFcn;
113         destroyFcn(contact, allocator);
114 }
115
116 b2Contact::b2Contact(b2Shape* s1, b2Shape* s2)
117 {
118         m_flags = 0;
119
120         if (s1->IsSensor() || s2->IsSensor())
121         {
122                 m_flags |= e_nonSolidFlag;
123         }
124
125         m_shape1 = s1;
126         m_shape2 = s2;
127
128         m_manifoldCount = 0;
129
130         m_friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction());
131         m_restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution());
132         m_prev = NULL;
133         m_next = NULL;
134
135         m_node1.contact = NULL;
136         m_node1.prev = NULL;
137         m_node1.next = NULL;
138         m_node1.other = NULL;
139
140         m_node2.contact = NULL;
141         m_node2.prev = NULL;
142         m_node2.next = NULL;
143         m_node2.other = NULL;
144 }
145
146 void b2Contact::Update(b2ContactListener* listener)
147 {
148         int32 oldCount = GetManifoldCount();
149
150         Evaluate(listener);
151
152         int32 newCount = GetManifoldCount();
153
154         b2Body* body1 = m_shape1->GetBody();
155         b2Body* body2 = m_shape2->GetBody();
156
157         if (newCount == 0 && oldCount > 0)
158         {
159                 body1->WakeUp();
160                 body2->WakeUp();
161         }
162
163         // Slow contacts don't generate TOI events.
164         if (body1->IsStatic() || body1->IsBullet() || body2->IsStatic() || body2->IsBullet())
165         {
166                 m_flags &= ~e_slowFlag;
167         }
168         else
169         {
170                 m_flags |= e_slowFlag;
171         }
172 }