#include #include #include using namespace Upp; struct QueryCallback : b2QueryCallback { QueryCallback(const b2Vec2& point) { this->point = point; fixture = NULL; } bool ReportFixture(b2Fixture* fixture) { b2Body* body = fixture->GetBody(); if (body->GetType() == b2_dynamicBody) { bool inside = fixture->TestPoint(point); if (inside) { this->fixture = fixture; return false; } } return true; } b2Vec2 point; b2Fixture* fixture; }; struct DebugDraw : b2DebugDraw { Draw* w; Sizef sz; float cx, cy; float aspect; float zoom; DebugDraw() {} void Init(Draw& d, Size s) { w = &d; sz = s; zoom = 15.0f; cx = float(sz.cx / 2.0f); cy = float(sz.cy / 2.0f + 150.0f); aspect = float(sz.cx / sz.cy); aspect *= zoom; } Point conv(const b2Vec2& v) { return Point(int(v.x * aspect + cx), int(cy - v.y * aspect)); } b2Vec2 conv(const Point& p) { b2Vec2 v; v.x = (p.x - cx) / aspect; v.y = (cy - p.y) / aspect; return v; } Color conv(const b2Color& c, double f = 255.0) { return Color(int(c.r * f), int(c.g * f), int(c.b * f)); } void DrawPolygon(const b2Vec2* v, int vertexCount, const b2Color& color) { Vector p; p.SetCount(vertexCount + 1); for(int i = 0; i < vertexCount; ++i) p[i] = conv(v[i]); p[vertexCount] = p[0]; w->DrawPolyline(p, vertexCount + 1, 1, conv(color, 150.0)); } void DrawSolidPolygon(const b2Vec2* v, int vertexCount, const b2Color& color) { Vector p; p.SetCount(vertexCount); for(int i = 0; i < vertexCount; ++i) p[i] = conv(v[i]); w->DrawPolygon(p, conv(color, 255.0), 1, conv(color, 150)); } void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) { int r = int(aspect * radius * 2.0f); Point p = conv(b2Vec2(center.x - radius, center.y + radius)); w->DrawEllipse(p.x, p.y, r, r, conv(color, 150.0)); } void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) { int r = int(aspect * radius * 2.0f); Point p = conv(b2Vec2(center.x - radius, center.y + radius)); w->DrawEllipse(p.x, p.y, r, r, conv(color, 255.0), PEN_SOLID, conv(color, 150.0)); } void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) { w->DrawLine(conv(p1), conv(p2), 1, conv(color, 150.0)); } void DrawTransform(const b2Transform& xf) { } void DrawPoint(const b2Vec2& p0, float32 size, const b2Color& color) { Point p = conv(p0); int s = int(size * aspect); w->DrawRect(p.x, p.y, s, s, conv(color, 255.0)); } void DrawString(int x, int y, const char* string, ...) { char buffer[256]; va_list arg; va_start(arg, string); vsprintf(buffer, string, arg); va_end(arg); w->DrawText(x, y, buffer); } void DrawAABB(b2AABB* aabb, const b2Color& color) { Point lb = conv(aabb->lowerBound); Point ub = conv(aabb->upperBound); Color fg = conv(color, 150.0); w->DrawRect(lb.x, lb.y, ub.x, ub.y, fg); } }; struct App : TopWindow { b2World world; b2MouseJoint* mouseJoint; b2Vec2 mouseWorld; b2Body* groundBody; Option showBoxes; DropList drawMode; DebugDraw debugDraw; typedef App CLASSNAME; App() : world(b2Vec2(0.0, -10.0), true) { Title("Box2D Example"); SetRectX(0, 640); SetRectY(0, 480); Sizeable().Zoomable(); BackPaint(); SetTimeCallback(-1, THISBACK(Render)); mouseJoint = NULL; b2Vec2 gravity; gravity.Set(0.0f, -10.0f); world.SetGravity(gravity); world.SetDebugDraw(&debugDraw); b2BodyDef bodyDef; groundBody = world.CreateBody(&bodyDef); showBoxes.SetLabel("AABBs"); drawMode .Add(0, "Draw") .Add(1, "Painter - No aa") .Add(2, "Painter - Antialiased") .Add(3, "Painter - Subpixel"); drawMode <<= 2; Add(showBoxes.LeftPosZ(5, 55).TopPosZ(5, 19)); Add(drawMode.LeftPosZ(5, 130).TopPosZ(28, 19)); Bridge(); } void Bridge() { const int ecount = 30; b2BodyDef bd; b2Body* ground = world.CreateBody(&bd); b2PolygonShape shape; shape.SetAsEdge(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); ground->CreateFixture(&shape, 0.0f); shape.SetAsBox(0.5f, 0.125f); b2FixtureDef fd; fd.shape = &shape; fd.density = 20.0f; fd.friction = 0.2f; b2RevoluteJointDef jd; b2Body* prevBody = ground; for(int i = 0; i < ecount; ++i) { b2BodyDef bd; bd.type = b2_dynamicBody; bd.position.Set(-14.5f + 1.0f * i, 5.0f); b2Body* body = world.CreateBody(&bd); body->CreateFixture(&fd); b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f); jd.Initialize(prevBody, body, anchor); world.CreateJoint(&jd); prevBody = body; } b2Vec2 anchor(-15.0f + 1.0f * ecount, 5.0f); jd.Initialize(prevBody, ground, anchor); world.CreateJoint(&jd); for(int i = 0; i < 2; ++i) { b2Vec2 vertices[3]; vertices[0].Set(-0.5f, 0.0f); vertices[1].Set(0.5f, 0.0f); vertices[2].Set(0.0f, 1.5f); b2PolygonShape shape; shape.Set(vertices, 3); b2FixtureDef fd; fd.shape = &shape; fd.density = 1.0f; b2BodyDef bd; bd.type = b2_dynamicBody; bd.position.Set(-8.0f + 8.0f * i, 12.0f); b2Body* body = world.CreateBody(&bd); body->CreateFixture(&fd); } for(int i = 0; i < 3; ++i) { b2CircleShape shape; shape.m_radius = 0.5f; b2FixtureDef fd; fd.shape = &shape; fd.density = 1.0f; b2BodyDef bd; bd.type = b2_dynamicBody; bd.position.Set(-6.0f + 6.0f * i, 10.0f); b2Body* body = world.CreateBody(&bd); body->CreateFixture(&fd); } } void Render() { Refresh(); } virtual void Paint(Draw& w) { int m = ~drawMode; float hz = 60; int velocityIterations = 8; int positionIterations = 10; float32 timeStep = 1.0f / hz; int flags = b2DebugDraw::e_shapeBit | b2DebugDraw::e_jointBit; if(showBoxes) flags |= b2DebugDraw::e_aabbBit; debugDraw.SetFlags(flags); world.SetWarmStarting(1); world.SetContinuousPhysics(1); world.Step(timeStep, velocityIterations, positionIterations); Point p1, p2; if(mouseJoint) { p1 = debugDraw.conv(mouseJoint->GetAnchorB()); p2 = debugDraw.conv(mouseJoint->GetTarget()); } Size sz = GetSize(); if(m > 0) { ImageBuffer ib(sz); BufferPainter bp(ib, m == 1 ? MODE_NOAA : m == 2 ? MODE_ANTIALIASED : MODE_SUBPIXEL); RGBA bg; bg.r = bg.g = bg.b = bg.a = 255; bp.Clear(bg); debugDraw.Init(bp, sz); world.DrawDebugData(); if(mouseJoint) { bp.DrawLine(p1, p2, 2, LtGreen); bp.DrawEllipse(p2.x - 3, p2.y - 3, 6, 6, Green, PEN_SOLID, Black); } w.DrawImage(0, 0, ib); } else { w.DrawRect(sz, White); debugDraw.Init(w, sz); world.DrawDebugData(); if(mouseJoint) { w.DrawLine(p1, p2, 2, LtGreen); w.DrawEllipse(p2.x - 3, p2.y - 3, 6, 6, Green, PEN_SOLID, Black); } } } virtual void LeftDown(Point p0, dword keyflags) { b2Vec2 p = debugDraw.conv(p0); mouseWorld = p; if(mouseJoint != NULL) return; b2AABB aabb; b2Vec2 d; d.Set(0.001f, 0.001f); aabb.lowerBound = p - d; aabb.upperBound = p + d; QueryCallback callback(p); world.QueryAABB(&callback, aabb); if (callback.fixture) { b2Body* body = callback.fixture->GetBody(); b2MouseJointDef md; md.bodyA = groundBody; md.bodyB = body; md.target = p; md.maxForce = 1000.0f * body->GetMass(); mouseJoint = (b2MouseJoint*) world.CreateJoint(&md); body->SetAwake(true); } } virtual void LeftUp(Point p0, dword keyflags) { if (mouseJoint) { world.DestroyJoint(mouseJoint); mouseJoint = NULL; } } virtual void MouseMove(Point p, dword keyflags) { mouseWorld = debugDraw.conv(p); if(mouseJoint) mouseJoint->SetTarget(mouseWorld); } virtual void MouseWheel(Point p, int zdelta, dword keyflags) { debugDraw.zoom += zdelta / 80.0f; } }; GUI_APP_MAIN { App().Run(); }