1 #include <CtrlLib/CtrlLib.h>
2 #include <Painter/Painter.h>
3 #include <plugin/box2d/Box2D.h>
4 
5 using namespace Upp;
6 
7 struct QueryCallback : b2QueryCallback
8 {
QueryCallbackQueryCallback9 	QueryCallback(const b2Vec2& point)
10 	{
11 		this->point = point;
12 		fixture = NULL;
13 	}
14 
ReportFixtureQueryCallback15 	bool ReportFixture(b2Fixture* fixture)
16 	{
17 		b2Body* body = fixture->GetBody();
18 		if (body->GetType() == b2_dynamicBody)
19 		{
20 			bool inside = fixture->TestPoint(point);
21 			if (inside)
22 			{
23 				this->fixture = fixture;
24 				return false;
25 			}
26 		}
27 
28 		return true;
29 	}
30 
31 	b2Vec2 point;
32 	b2Fixture* fixture;
33 };
34 
35 struct DebugDraw : b2DebugDraw
36 {
37 	Draw* w;
38 	Sizef sz;
39 	float cx, cy;
40 	float aspect;
41 	float zoom;
42 
DebugDrawDebugDraw43 	DebugDraw()
44 	{}
45 
InitDebugDraw46 	void Init(Draw& d, Size s)
47 	{
48 		w = &d;
49 		sz = s;
50 		zoom = 15.0f;
51 		cx = float(sz.cx / 2.0f);
52 		cy = float(sz.cy / 2.0f + 150.0f);
53 		aspect = float(sz.cx / sz.cy);
54 		aspect *= zoom;
55 	}
56 
convDebugDraw57 	Point conv(const b2Vec2& v)
58 	{
59 		return Point(int(v.x * aspect + cx), int(cy - v.y * aspect));
60 	}
61 
convDebugDraw62 	b2Vec2 conv(const Point& p)
63 	{
64 		b2Vec2 v;
65 
66 		v.x = (p.x - cx) / aspect;
67 		v.y = (cy - p.y) / aspect;
68 
69 		return v;
70 	}
71 
convDebugDraw72 	Color conv(const b2Color& c, double f = 255.0)
73 	{
74 		return Color(int(c.r * f), int(c.g * f), int(c.b * f));
75 	}
76 
DrawPolygonDebugDraw77 	void DrawPolygon(const b2Vec2* v, int vertexCount, const b2Color& color)
78 	{
79 		Vector<Point> p;
80 		p.SetCount(vertexCount + 1);
81 		for(int i = 0; i < vertexCount; ++i)
82 			p[i] = conv(v[i]);
83 		p[vertexCount] = p[0];
84 
85 		w->DrawPolyline(p, 1, conv(color, 150.0));
86 	}
87 
DrawSolidPolygonDebugDraw88 	void DrawSolidPolygon(const b2Vec2* v, int vertexCount, const b2Color& color)
89 	{
90 		Vector<Point> p;
91 		p.SetCount(vertexCount);
92 		for(int i = 0; i < vertexCount; ++i)
93 			p[i] = conv(v[i]);
94 
95 		w->DrawPolygon(p, conv(color, 255.0), 1, conv(color, 150));
96 	}
97 
DrawCircleDebugDraw98 	void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
99 	{
100 		int r = int(aspect * radius * 2.0f);
101 		Point p = conv(b2Vec2(center.x - radius, center.y + radius));
102 		w->DrawEllipse(p.x, p.y, r, r, conv(color, 150.0));
103 	}
104 
DrawSolidCircleDebugDraw105 	void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
106 	{
107 		int r = int(aspect * radius * 2.0f);
108 		Point p = conv(b2Vec2(center.x - radius, center.y + radius));
109 		w->DrawEllipse(p.x, p.y, r, r, conv(color, 255.0), PEN_SOLID, conv(color, 150.0));
110 	}
111 
DrawSegmentDebugDraw112 	void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
113 	{
114 		w->DrawLine(conv(p1), conv(p2), 1, conv(color, 150.0));
115 	}
116 
DrawTransformDebugDraw117 	void DrawTransform(const b2Transform& xf)
118 	{
119 	}
120 
DrawPointDebugDraw121 	void DrawPoint(const b2Vec2& p0, float32 size, const b2Color& color)
122 	{
123 		Point p = conv(p0);
124 		int s = int(size * aspect);
125 		w->DrawRect(p.x, p.y, s, s, conv(color, 255.0));
126 	}
127 
DrawStringDebugDraw128 	void DrawString(int x, int y, const char* string, ...)
129 	{
130 		char buffer[256];
131 
132 		va_list arg;
133 		va_start(arg, string);
134 		vsprintf(buffer, string, arg);
135 		va_end(arg);
136 
137 		w->DrawText(x, y, buffer);
138 	}
139 
DrawAABBDebugDraw140 	void DrawAABB(b2AABB* aabb, const b2Color& color)
141 	{
142 		Point lb = conv(aabb->lowerBound);
143 		Point ub = conv(aabb->upperBound);
144 		Color fg = conv(color, 150.0);
145 
146 		w->DrawRect(lb.x, lb.y, ub.x, ub.y, fg);
147 	}
148 };
149 
150 struct App : TopWindow
151 {
152 	b2World world;
153 	b2MouseJoint* mouseJoint;
154 	b2Vec2 mouseWorld;
155 	b2Body* groundBody;
156 	Option showBoxes;
157 	DropList drawMode;
158 	DebugDraw debugDraw;
159 
160 	typedef App CLASSNAME;
161 
AppApp162 	App() : world(b2Vec2(0.0, -10.0), true)
163 	{
164 		Title("Box2D Example");
165 		SetRectX(0, 640);
166 		SetRectY(0, 480);
167 		Sizeable().Zoomable();
168 		BackPaint();
169 		SetTimeCallback(-1, THISBACK(Render));
170 		mouseJoint = NULL;
171 		b2Vec2 gravity;
172 		gravity.Set(0.0f, -10.0f);
173 		world.SetGravity(gravity);
174 		world.SetDebugDraw(&debugDraw);
175 		b2BodyDef bodyDef;
176 		groundBody = world.CreateBody(&bodyDef);
177 		showBoxes.SetLabel("AABBs");
178 
179 		drawMode
180 			.Add(0, "Draw")
181 			.Add(1, "Painter - No aa")
182 			.Add(2, "Painter - Antialiased")
183 			.Add(3, "Painter - Subpixel");
184 
185 		drawMode <<= 2;
186 
187 		Add(showBoxes.LeftPosZ(5, 55).TopPosZ(5, 19));
188 		Add(drawMode.LeftPosZ(5, 130).TopPosZ(28, 19));
189 		Bridge();
190 	}
191 
BridgeApp192 	void Bridge()
193 	{
194 		const int ecount = 30;
195 
196 		b2BodyDef bd;
197 		b2Body* ground = world.CreateBody(&bd);
198 
199 		b2PolygonShape shape;
200 		shape.SetAsEdge(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
201 		ground->CreateFixture(&shape, 0.0f);
202 
203 		shape.SetAsBox(0.5f, 0.125f);
204 
205 		b2FixtureDef fd;
206 		fd.shape = &shape;
207 		fd.density = 20.0f;
208 		fd.friction = 0.2f;
209 
210 		b2RevoluteJointDef jd;
211 
212 		b2Body* prevBody = ground;
213 		for(int i = 0; i < ecount; ++i)
214 		{
215 			b2BodyDef bd;
216 			bd.type = b2_dynamicBody;
217 			bd.position.Set(-14.5f + 1.0f * i, 5.0f);
218 			b2Body* body = world.CreateBody(&bd);
219 			body->CreateFixture(&fd);
220 
221 			b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
222 			jd.Initialize(prevBody, body, anchor);
223 			world.CreateJoint(&jd);
224 
225 			prevBody = body;
226 		}
227 
228 		b2Vec2 anchor(-15.0f + 1.0f * ecount, 5.0f);
229 		jd.Initialize(prevBody, ground, anchor);
230 		world.CreateJoint(&jd);
231 
232 		for(int i = 0; i < 2; ++i)
233 		{
234 			b2Vec2 vertices[3];
235 			vertices[0].Set(-0.5f, 0.0f);
236 			vertices[1].Set(0.5f, 0.0f);
237 			vertices[2].Set(0.0f, 1.5f);
238 
239 			b2PolygonShape shape;
240 			shape.Set(vertices, 3);
241 
242 			b2FixtureDef fd;
243 			fd.shape = &shape;
244 			fd.density = 1.0f;
245 
246 			b2BodyDef bd;
247 			bd.type = b2_dynamicBody;
248 			bd.position.Set(-8.0f + 8.0f * i, 12.0f);
249 			b2Body* body = world.CreateBody(&bd);
250 			body->CreateFixture(&fd);
251 		}
252 
253 		for(int i = 0; i < 3; ++i)
254 		{
255 			b2CircleShape shape;
256 			shape.m_radius = 0.5f;
257 
258 			b2FixtureDef fd;
259 			fd.shape = &shape;
260 			fd.density = 1.0f;
261 
262 			b2BodyDef bd;
263 			bd.type = b2_dynamicBody;
264 			bd.position.Set(-6.0f + 6.0f * i, 10.0f);
265 			b2Body* body = world.CreateBody(&bd);
266 			body->CreateFixture(&fd);
267 		}
268 	}
269 
RenderApp270 	void Render() { Refresh(); }
271 
PaintApp272 	virtual void Paint(Draw& w)
273 	{
274 		int m = ~drawMode;
275 
276 		float hz = 60;
277 		int velocityIterations = 8;
278 		int positionIterations = 10;
279 
280 		float32 timeStep = 1.0f / hz;
281 
282 		int flags = b2DebugDraw::e_shapeBit | b2DebugDraw::e_jointBit;
283 		if(showBoxes)
284 			flags |= b2DebugDraw::e_aabbBit;
285 
286 		debugDraw.SetFlags(flags);
287 
288 		world.SetWarmStarting(1);
289 		world.SetContinuousPhysics(1);
290 		world.Step(timeStep, velocityIterations, positionIterations);
291 
292 		Point p1, p2;
293 		if(mouseJoint)
294 		{
295 			p1 = debugDraw.conv(mouseJoint->GetAnchorB());
296 			p2 = debugDraw.conv(mouseJoint->GetTarget());
297 		}
298 
299 		Size sz = GetSize();
300 
301 		if(m > 0)
302 		{
303 			ImageBuffer ib(sz);
304 			BufferPainter bp(ib, m == 1 ? MODE_NOAA : m == 2 ? MODE_ANTIALIASED : MODE_SUBPIXEL);
305 			RGBA bg;
306 			bg.r = bg.g = bg.b = bg.a = 255;
307 			bp.Clear(bg);
308 			debugDraw.Init(bp, sz);
309 
310 			world.DrawDebugData();
311 			if(mouseJoint)
312 			{
313 				bp.DrawLine(p1, p2, 2, LtGreen);
314 				bp.DrawEllipse(p2.x - 3, p2.y - 3, 6, 6, Green, PEN_SOLID, Black);
315 			}
316 
317 			w.DrawImage(0, 0, ib);
318 		}
319 		else
320 		{
321 			w.DrawRect(sz, White);
322 			debugDraw.Init(w, sz);
323 			world.DrawDebugData();
324 			if(mouseJoint)
325 			{
326 				w.DrawLine(p1, p2, 2, LtGreen);
327 				w.DrawEllipse(p2.x - 3, p2.y - 3, 6, 6, Green, PEN_SOLID, Black);
328 			}
329 		}
330 	}
331 
LeftDownApp332 	virtual void LeftDown(Point p0, dword keyflags)
333 	{
334 		b2Vec2 p = debugDraw.conv(p0);
335 		mouseWorld = p;
336 
337 		if(mouseJoint != NULL)
338 			return;
339 
340 		b2AABB aabb;
341 		b2Vec2 d;
342 		d.Set(0.001f, 0.001f);
343 		aabb.lowerBound = p - d;
344 		aabb.upperBound = p + d;
345 
346 		QueryCallback callback(p);
347 		world.QueryAABB(&callback, aabb);
348 
349 		if (callback.fixture)
350 		{
351 			b2Body* body = callback.fixture->GetBody();
352 			b2MouseJointDef md;
353 			md.bodyA = groundBody;
354 			md.bodyB = body;
355 			md.target = p;
356 			md.maxForce = 1000.0f * body->GetMass();
357 			mouseJoint = (b2MouseJoint*) world.CreateJoint(&md);
358 			body->SetAwake(true);
359 		}
360 	}
361 
LeftUpApp362 	virtual void LeftUp(Point p0, dword keyflags)
363 	{
364 		if (mouseJoint)
365 		{
366 			world.DestroyJoint(mouseJoint);
367 			mouseJoint = NULL;
368 		}
369 	}
370 
MouseMoveApp371 	virtual void MouseMove(Point p, dword keyflags)
372 	{
373 		mouseWorld = debugDraw.conv(p);
374 
375 		if(mouseJoint)
376 			mouseJoint->SetTarget(mouseWorld);
377 	}
378 
MouseWheelApp379 	virtual void MouseWheel(Point p, int zdelta, dword keyflags)
380 	{
381 		debugDraw.zoom += zdelta / 80.0f;
382 	}
383 };
384 
385 GUI_APP_MAIN
386 {
387 	App().Run();
388 }
389 
390