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