1 /*
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 #ifndef POLY_SHAPES_H
20 #define POLY_SHAPES_H
21 
22 /// This tests stacking. It also shows how to use b2World::Query
23 /// and b2TestOverlap.
24 
25 const int32 k_maxBodies = 256;
26 
27 /// This callback is called by b2World::QueryAABB. We find all the fixtures
28 /// that overlap an AABB. Of those, we use b2TestOverlap to determine which fixtures
29 /// overlap a circle. Up to 4 overlapped fixtures will be highlighted with a yellow border.
30 class PolyShapesCallback : public b2QueryCallback
31 {
32 public:
33 
34     enum
35     {
36         e_maxCount = 4
37     };
38 
PolyShapesCallback()39     PolyShapesCallback()
40     {
41         m_count = 0;
42     }
43 
DrawFixture(b2Fixture * fixture)44     void DrawFixture(b2Fixture* fixture)
45     {
46         b2Color color(0.95f, 0.95f, 0.6f);
47         const b2Transform& xf = fixture->GetBody()->GetTransform();
48 
49         switch (fixture->GetType())
50         {
51         case b2Shape::e_circle:
52             {
53                 b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
54 
55                 b2Vec2 center = b2Mul(xf, circle->m_p);
56                 float32 radius = circle->m_radius;
57 
58                 m_debugDraw->DrawCircle(center, radius, color);
59             }
60             break;
61 
62         case b2Shape::e_polygon:
63             {
64                 b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
65                 int32 vertexCount = poly->m_vertexCount;
66                 b2Assert(vertexCount <= b2_maxPolygonVertices);
67                 b2Vec2 vertices[b2_maxPolygonVertices];
68 
69                 for (int32 i = 0; i < vertexCount; ++i)
70                 {
71                     vertices[i] = b2Mul(xf, poly->m_vertices[i]);
72                 }
73 
74                 m_debugDraw->DrawPolygon(vertices, vertexCount, color);
75             }
76             break;
77 
78         default:
79             break;
80         }
81     }
82 
83     /// Called for each fixture found in the query AABB.
84     /// @return false to terminate the query.
ReportFixture(b2Fixture * fixture)85     bool ReportFixture(b2Fixture* fixture)
86     {
87         if (m_count == e_maxCount)
88         {
89             return false;
90         }
91 
92         b2Body* body = fixture->GetBody();
93         b2Shape* shape = fixture->GetShape();
94 
95         bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform);
96 
97         if (overlap)
98         {
99             DrawFixture(fixture);
100             ++m_count;
101         }
102 
103         return true;
104     }
105 
106     b2CircleShape m_circle;
107     b2Transform m_transform;
108     b2Draw* m_debugDraw;
109     int32 m_count;
110 };
111 
112 class PolyShapes : public Test
113 {
114 public:
PolyShapes()115     PolyShapes()
116     {
117         // Ground body
118         {
119             b2BodyDef bd;
120             b2Body* ground = m_world->CreateBody(&bd);
121 
122             b2EdgeShape shape;
123             shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
124             ground->CreateFixture(&shape, 0.0f);
125         }
126 
127         {
128             b2Vec2 vertices[3];
129             vertices[0].Set(-0.5f, 0.0f);
130             vertices[1].Set(0.5f, 0.0f);
131             vertices[2].Set(0.0f, 1.5f);
132             m_polygons[0].Set(vertices, 3);
133         }
134 
135         {
136             b2Vec2 vertices[3];
137             vertices[0].Set(-0.1f, 0.0f);
138             vertices[1].Set(0.1f, 0.0f);
139             vertices[2].Set(0.0f, 1.5f);
140             m_polygons[1].Set(vertices, 3);
141         }
142 
143         {
144             float32 w = 1.0f;
145             float32 b = w / (2.0f + b2Sqrt(2.0f));
146             float32 s = b2Sqrt(2.0f) * b;
147 
148             b2Vec2 vertices[8];
149             vertices[0].Set(0.5f * s, 0.0f);
150             vertices[1].Set(0.5f * w, b);
151             vertices[2].Set(0.5f * w, b + s);
152             vertices[3].Set(0.5f * s, w);
153             vertices[4].Set(-0.5f * s, w);
154             vertices[5].Set(-0.5f * w, b + s);
155             vertices[6].Set(-0.5f * w, b);
156             vertices[7].Set(-0.5f * s, 0.0f);
157 
158             m_polygons[2].Set(vertices, 8);
159         }
160 
161         {
162             m_polygons[3].SetAsBox(0.5f, 0.5f);
163         }
164 
165         {
166             m_circle.m_radius = 0.5f;
167         }
168 
169         m_bodyIndex = 0;
170         memset(m_bodies, 0, sizeof(m_bodies));
171     }
172 
Create(int32 index)173     void Create(int32 index)
174     {
175         if (m_bodies[m_bodyIndex] != NULL)
176         {
177             m_world->DestroyBody(m_bodies[m_bodyIndex]);
178             m_bodies[m_bodyIndex] = NULL;
179         }
180 
181         b2BodyDef bd;
182         bd.type = b2_dynamicBody;
183 
184         float32 x = RandomFloat(-2.0f, 2.0f);
185         bd.position.Set(x, 10.0f);
186         bd.angle = RandomFloat(-b2_pi, b2_pi);
187 
188         if (index == 4)
189         {
190             bd.angularDamping = 0.02f;
191         }
192 
193         m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
194 
195         if (index < 4)
196         {
197             b2FixtureDef fd;
198             fd.shape = m_polygons + index;
199             fd.density = 1.0f;
200             fd.friction = 0.3f;
201             m_bodies[m_bodyIndex]->CreateFixture(&fd);
202         }
203         else
204         {
205             b2FixtureDef fd;
206             fd.shape = &m_circle;
207             fd.density = 1.0f;
208             fd.friction = 0.3f;
209 
210             m_bodies[m_bodyIndex]->CreateFixture(&fd);
211         }
212 
213         m_bodyIndex = (m_bodyIndex + 1) % k_maxBodies;
214     }
215 
DestroyBody()216     void DestroyBody()
217     {
218         for (int32 i = 0; i < k_maxBodies; ++i)
219         {
220             if (m_bodies[i] != NULL)
221             {
222                 m_world->DestroyBody(m_bodies[i]);
223                 m_bodies[i] = NULL;
224                 return;
225             }
226         }
227     }
228 
Keyboard(unsigned char key)229     void Keyboard(unsigned char key)
230     {
231         switch (key)
232         {
233         case '1':
234         case '2':
235         case '3':
236         case '4':
237         case '5':
238             Create(key - '1');
239             break;
240 
241         case 'a':
242             for (int32 i = 0; i < k_maxBodies; i += 2)
243             {
244                 if (m_bodies[i])
245                 {
246                     bool active = m_bodies[i]->IsActive();
247                     m_bodies[i]->SetActive(!active);
248                 }
249             }
250             break;
251 
252         case 'd':
253             DestroyBody();
254             break;
255         }
256     }
257 
Step(Settings * settings)258     void Step(Settings* settings)
259     {
260         Test::Step(settings);
261 
262         PolyShapesCallback callback;
263         callback.m_circle.m_radius = 2.0f;
264         callback.m_circle.m_p.Set(0.0f, 1.1f);
265         callback.m_transform.SetIdentity();
266         callback.m_debugDraw = &m_debugDraw;
267 
268         b2AABB aabb;
269         callback.m_circle.ComputeAABB(&aabb, callback.m_transform, 0);
270 
271         m_world->QueryAABB(&callback, aabb);
272 
273         b2Color color(0.4f, 0.7f, 0.8f);
274         m_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color);
275 
276         m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");
277         m_textLine += 15;
278         m_debugDraw.DrawString(5, m_textLine, "Press 'a' to (de)activate some bodies");
279         m_textLine += 15;
280         m_debugDraw.DrawString(5, m_textLine, "Press 'd' to destroy a body");
281         m_textLine += 15;
282     }
283 
Create()284     static Test* Create()
285     {
286         return new PolyShapes;
287     }
288 
289     int32 m_bodyIndex;
290     b2Body* m_bodies[k_maxBodies];
291     b2PolygonShape m_polygons[4];
292     b2CircleShape m_circle;
293 };
294 
295 #endif
296