--- /dev/null
+Box2D/
+Contributions/
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 491330C81372616300DFB46D /* Box2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913307B1372616300DFB46D /* Box2D.h */; };
+ 491330C91372616300DFB46D /* b2BroadPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913307D1372616300DFB46D /* b2BroadPhase.cpp */; };
+ 491330CA1372616300DFB46D /* b2BroadPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913307E1372616300DFB46D /* b2BroadPhase.h */; };
+ 491330CB1372616300DFB46D /* b2CollideCircle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913307F1372616300DFB46D /* b2CollideCircle.cpp */; };
+ 491330CC1372616300DFB46D /* b2CollidePolygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330801372616300DFB46D /* b2CollidePolygon.cpp */; };
+ 491330CD1372616300DFB46D /* b2Collision.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330811372616300DFB46D /* b2Collision.cpp */; };
+ 491330CE1372616300DFB46D /* b2Collision.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330821372616300DFB46D /* b2Collision.h */; };
+ 491330CF1372616300DFB46D /* b2Distance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330831372616300DFB46D /* b2Distance.cpp */; };
+ 491330D01372616300DFB46D /* b2Distance.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330841372616300DFB46D /* b2Distance.h */; };
+ 491330D11372616300DFB46D /* b2DynamicTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330851372616300DFB46D /* b2DynamicTree.cpp */; };
+ 491330D21372616300DFB46D /* b2DynamicTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330861372616300DFB46D /* b2DynamicTree.h */; };
+ 491330D31372616300DFB46D /* b2TimeOfImpact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330871372616300DFB46D /* b2TimeOfImpact.cpp */; };
+ 491330D41372616300DFB46D /* b2TimeOfImpact.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330881372616300DFB46D /* b2TimeOfImpact.h */; };
+ 491330D51372616300DFB46D /* b2CircleShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913308A1372616300DFB46D /* b2CircleShape.cpp */; };
+ 491330D61372616300DFB46D /* b2CircleShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913308B1372616300DFB46D /* b2CircleShape.h */; };
+ 491330D71372616300DFB46D /* b2PolygonShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913308C1372616300DFB46D /* b2PolygonShape.cpp */; };
+ 491330D81372616300DFB46D /* b2PolygonShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913308D1372616300DFB46D /* b2PolygonShape.h */; };
+ 491330D91372616300DFB46D /* b2Shape.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913308E1372616300DFB46D /* b2Shape.h */; };
+ 491330DA1372616300DFB46D /* b2BlockAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330901372616300DFB46D /* b2BlockAllocator.cpp */; };
+ 491330DB1372616300DFB46D /* b2BlockAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330911372616300DFB46D /* b2BlockAllocator.h */; };
+ 491330DC1372616300DFB46D /* b2Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330921372616300DFB46D /* b2Math.cpp */; };
+ 491330DD1372616300DFB46D /* b2Math.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330931372616300DFB46D /* b2Math.h */; };
+ 491330DE1372616300DFB46D /* b2Settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330941372616300DFB46D /* b2Settings.cpp */; };
+ 491330DF1372616300DFB46D /* b2Settings.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330951372616300DFB46D /* b2Settings.h */; };
+ 491330E01372616300DFB46D /* b2StackAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330961372616300DFB46D /* b2StackAllocator.cpp */; };
+ 491330E11372616300DFB46D /* b2StackAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330971372616300DFB46D /* b2StackAllocator.h */; };
+ 491330E21372616300DFB46D /* b2Body.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330991372616300DFB46D /* b2Body.cpp */; };
+ 491330E31372616300DFB46D /* b2Body.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913309A1372616300DFB46D /* b2Body.h */; };
+ 491330E41372616300DFB46D /* b2ContactManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913309B1372616300DFB46D /* b2ContactManager.cpp */; };
+ 491330E51372616300DFB46D /* b2ContactManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913309C1372616300DFB46D /* b2ContactManager.h */; };
+ 491330E61372616300DFB46D /* b2Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913309D1372616300DFB46D /* b2Fixture.cpp */; };
+ 491330E71372616300DFB46D /* b2Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913309E1372616300DFB46D /* b2Fixture.h */; };
+ 491330E81372616300DFB46D /* b2Island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4913309F1372616300DFB46D /* b2Island.cpp */; };
+ 491330E91372616300DFB46D /* b2Island.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330A01372616300DFB46D /* b2Island.h */; };
+ 491330EA1372616300DFB46D /* b2TimeStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330A11372616300DFB46D /* b2TimeStep.h */; };
+ 491330EB1372616300DFB46D /* b2World.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330A21372616300DFB46D /* b2World.cpp */; };
+ 491330EC1372616300DFB46D /* b2World.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330A31372616300DFB46D /* b2World.h */; };
+ 491330ED1372616300DFB46D /* b2WorldCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330A41372616300DFB46D /* b2WorldCallbacks.cpp */; };
+ 491330EE1372616300DFB46D /* b2WorldCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330A51372616300DFB46D /* b2WorldCallbacks.h */; };
+ 491330EF1372616300DFB46D /* b2CircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330A71372616300DFB46D /* b2CircleContact.cpp */; };
+ 491330F01372616300DFB46D /* b2CircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330A81372616300DFB46D /* b2CircleContact.h */; };
+ 491330F11372616300DFB46D /* b2Contact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330A91372616300DFB46D /* b2Contact.cpp */; };
+ 491330F21372616300DFB46D /* b2Contact.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330AA1372616300DFB46D /* b2Contact.h */; };
+ 491330F31372616300DFB46D /* b2ContactSolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330AB1372616300DFB46D /* b2ContactSolver.cpp */; };
+ 491330F41372616300DFB46D /* b2ContactSolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330AC1372616300DFB46D /* b2ContactSolver.h */; };
+ 491330F51372616300DFB46D /* b2PolygonAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330AD1372616300DFB46D /* b2PolygonAndCircleContact.cpp */; };
+ 491330F61372616300DFB46D /* b2PolygonAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330AE1372616300DFB46D /* b2PolygonAndCircleContact.h */; };
+ 491330F71372616300DFB46D /* b2PolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330AF1372616300DFB46D /* b2PolygonContact.cpp */; };
+ 491330F81372616300DFB46D /* b2PolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330B01372616300DFB46D /* b2PolygonContact.h */; };
+ 491330F91372616300DFB46D /* b2TOISolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330B11372616300DFB46D /* b2TOISolver.cpp */; };
+ 491330FA1372616300DFB46D /* b2TOISolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330B21372616300DFB46D /* b2TOISolver.h */; };
+ 491330FB1372616300DFB46D /* b2DistanceJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330B41372616300DFB46D /* b2DistanceJoint.cpp */; };
+ 491330FC1372616300DFB46D /* b2DistanceJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330B51372616300DFB46D /* b2DistanceJoint.h */; };
+ 491330FD1372616300DFB46D /* b2FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330B61372616300DFB46D /* b2FrictionJoint.cpp */; };
+ 491330FE1372616300DFB46D /* b2FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330B71372616300DFB46D /* b2FrictionJoint.h */; };
+ 491330FF1372616300DFB46D /* b2GearJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330B81372616300DFB46D /* b2GearJoint.cpp */; };
+ 491331001372616300DFB46D /* b2GearJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330B91372616300DFB46D /* b2GearJoint.h */; };
+ 491331011372616300DFB46D /* b2Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330BA1372616300DFB46D /* b2Joint.cpp */; };
+ 491331021372616300DFB46D /* b2Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330BB1372616300DFB46D /* b2Joint.h */; };
+ 491331031372616300DFB46D /* b2LineJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330BC1372616300DFB46D /* b2LineJoint.cpp */; };
+ 491331041372616300DFB46D /* b2LineJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330BD1372616300DFB46D /* b2LineJoint.h */; };
+ 491331051372616300DFB46D /* b2MouseJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330BE1372616300DFB46D /* b2MouseJoint.cpp */; };
+ 491331061372616300DFB46D /* b2MouseJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330BF1372616300DFB46D /* b2MouseJoint.h */; };
+ 491331071372616300DFB46D /* b2PrismaticJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330C01372616300DFB46D /* b2PrismaticJoint.cpp */; };
+ 491331081372616300DFB46D /* b2PrismaticJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330C11372616300DFB46D /* b2PrismaticJoint.h */; };
+ 491331091372616300DFB46D /* b2PulleyJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330C21372616300DFB46D /* b2PulleyJoint.cpp */; };
+ 4913310A1372616300DFB46D /* b2PulleyJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330C31372616300DFB46D /* b2PulleyJoint.h */; };
+ 4913310B1372616300DFB46D /* b2RevoluteJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330C41372616300DFB46D /* b2RevoluteJoint.cpp */; };
+ 4913310C1372616300DFB46D /* b2RevoluteJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330C51372616300DFB46D /* b2RevoluteJoint.h */; };
+ 4913310D1372616300DFB46D /* b2WeldJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491330C61372616300DFB46D /* b2WeldJoint.cpp */; };
+ 4913310E1372616300DFB46D /* b2WeldJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 491330C71372616300DFB46D /* b2WeldJoint.h */; };
+ 49133123137262F200DFB46D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49133122137262F200DFB46D /* Foundation.framework */; };
+ 491331281372630700DFB46D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 491331271372630700DFB46D /* UIKit.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 4913305F1372610400DFB46D /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBox2D.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4913307B1372616300DFB46D /* Box2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2D.h; sourceTree = "<group>"; };
+ 4913307D1372616300DFB46D /* b2BroadPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BroadPhase.cpp; sourceTree = "<group>"; };
+ 4913307E1372616300DFB46D /* b2BroadPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BroadPhase.h; sourceTree = "<group>"; };
+ 4913307F1372616300DFB46D /* b2CollideCircle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideCircle.cpp; sourceTree = "<group>"; };
+ 491330801372616300DFB46D /* b2CollidePolygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollidePolygon.cpp; sourceTree = "<group>"; };
+ 491330811372616300DFB46D /* b2Collision.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Collision.cpp; sourceTree = "<group>"; };
+ 491330821372616300DFB46D /* b2Collision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Collision.h; sourceTree = "<group>"; };
+ 491330831372616300DFB46D /* b2Distance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Distance.cpp; sourceTree = "<group>"; };
+ 491330841372616300DFB46D /* b2Distance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Distance.h; sourceTree = "<group>"; };
+ 491330851372616300DFB46D /* b2DynamicTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DynamicTree.cpp; sourceTree = "<group>"; };
+ 491330861372616300DFB46D /* b2DynamicTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DynamicTree.h; sourceTree = "<group>"; };
+ 491330871372616300DFB46D /* b2TimeOfImpact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2TimeOfImpact.cpp; sourceTree = "<group>"; };
+ 491330881372616300DFB46D /* b2TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeOfImpact.h; sourceTree = "<group>"; };
+ 4913308A1372616300DFB46D /* b2CircleShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleShape.cpp; sourceTree = "<group>"; };
+ 4913308B1372616300DFB46D /* b2CircleShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleShape.h; sourceTree = "<group>"; };
+ 4913308C1372616300DFB46D /* b2PolygonShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonShape.cpp; sourceTree = "<group>"; };
+ 4913308D1372616300DFB46D /* b2PolygonShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonShape.h; sourceTree = "<group>"; };
+ 4913308E1372616300DFB46D /* b2Shape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Shape.h; sourceTree = "<group>"; };
+ 491330901372616300DFB46D /* b2BlockAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BlockAllocator.cpp; sourceTree = "<group>"; };
+ 491330911372616300DFB46D /* b2BlockAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BlockAllocator.h; sourceTree = "<group>"; };
+ 491330921372616300DFB46D /* b2Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Math.cpp; sourceTree = "<group>"; };
+ 491330931372616300DFB46D /* b2Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Math.h; sourceTree = "<group>"; };
+ 491330941372616300DFB46D /* b2Settings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Settings.cpp; sourceTree = "<group>"; };
+ 491330951372616300DFB46D /* b2Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Settings.h; sourceTree = "<group>"; };
+ 491330961372616300DFB46D /* b2StackAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2StackAllocator.cpp; sourceTree = "<group>"; };
+ 491330971372616300DFB46D /* b2StackAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2StackAllocator.h; sourceTree = "<group>"; };
+ 491330991372616300DFB46D /* b2Body.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Body.cpp; sourceTree = "<group>"; };
+ 4913309A1372616300DFB46D /* b2Body.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Body.h; sourceTree = "<group>"; };
+ 4913309B1372616300DFB46D /* b2ContactManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactManager.cpp; sourceTree = "<group>"; };
+ 4913309C1372616300DFB46D /* b2ContactManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactManager.h; sourceTree = "<group>"; };
+ 4913309D1372616300DFB46D /* b2Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Fixture.cpp; sourceTree = "<group>"; };
+ 4913309E1372616300DFB46D /* b2Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Fixture.h; sourceTree = "<group>"; };
+ 4913309F1372616300DFB46D /* b2Island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Island.cpp; sourceTree = "<group>"; };
+ 491330A01372616300DFB46D /* b2Island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Island.h; sourceTree = "<group>"; };
+ 491330A11372616300DFB46D /* b2TimeStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeStep.h; sourceTree = "<group>"; };
+ 491330A21372616300DFB46D /* b2World.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2World.cpp; sourceTree = "<group>"; };
+ 491330A31372616300DFB46D /* b2World.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2World.h; sourceTree = "<group>"; };
+ 491330A41372616300DFB46D /* b2WorldCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WorldCallbacks.cpp; sourceTree = "<group>"; };
+ 491330A51372616300DFB46D /* b2WorldCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WorldCallbacks.h; sourceTree = "<group>"; };
+ 491330A71372616300DFB46D /* b2CircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleContact.cpp; sourceTree = "<group>"; };
+ 491330A81372616300DFB46D /* b2CircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleContact.h; sourceTree = "<group>"; };
+ 491330A91372616300DFB46D /* b2Contact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Contact.cpp; sourceTree = "<group>"; };
+ 491330AA1372616300DFB46D /* b2Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Contact.h; sourceTree = "<group>"; };
+ 491330AB1372616300DFB46D /* b2ContactSolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactSolver.cpp; sourceTree = "<group>"; };
+ 491330AC1372616300DFB46D /* b2ContactSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactSolver.h; sourceTree = "<group>"; };
+ 491330AD1372616300DFB46D /* b2PolygonAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonAndCircleContact.cpp; sourceTree = "<group>"; };
+ 491330AE1372616300DFB46D /* b2PolygonAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonAndCircleContact.h; sourceTree = "<group>"; };
+ 491330AF1372616300DFB46D /* b2PolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonContact.cpp; sourceTree = "<group>"; };
+ 491330B01372616300DFB46D /* b2PolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonContact.h; sourceTree = "<group>"; };
+ 491330B11372616300DFB46D /* b2TOISolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2TOISolver.cpp; sourceTree = "<group>"; };
+ 491330B21372616300DFB46D /* b2TOISolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TOISolver.h; sourceTree = "<group>"; };
+ 491330B41372616300DFB46D /* b2DistanceJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DistanceJoint.cpp; sourceTree = "<group>"; };
+ 491330B51372616300DFB46D /* b2DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DistanceJoint.h; sourceTree = "<group>"; };
+ 491330B61372616300DFB46D /* b2FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2FrictionJoint.cpp; sourceTree = "<group>"; };
+ 491330B71372616300DFB46D /* b2FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2FrictionJoint.h; sourceTree = "<group>"; };
+ 491330B81372616300DFB46D /* b2GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2GearJoint.cpp; sourceTree = "<group>"; };
+ 491330B91372616300DFB46D /* b2GearJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2GearJoint.h; sourceTree = "<group>"; };
+ 491330BA1372616300DFB46D /* b2Joint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Joint.cpp; sourceTree = "<group>"; };
+ 491330BB1372616300DFB46D /* b2Joint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Joint.h; sourceTree = "<group>"; };
+ 491330BC1372616300DFB46D /* b2LineJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2LineJoint.cpp; sourceTree = "<group>"; };
+ 491330BD1372616300DFB46D /* b2LineJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2LineJoint.h; sourceTree = "<group>"; };
+ 491330BE1372616300DFB46D /* b2MouseJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2MouseJoint.cpp; sourceTree = "<group>"; };
+ 491330BF1372616300DFB46D /* b2MouseJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2MouseJoint.h; sourceTree = "<group>"; };
+ 491330C01372616300DFB46D /* b2PrismaticJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PrismaticJoint.cpp; sourceTree = "<group>"; };
+ 491330C11372616300DFB46D /* b2PrismaticJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PrismaticJoint.h; sourceTree = "<group>"; };
+ 491330C21372616300DFB46D /* b2PulleyJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PulleyJoint.cpp; sourceTree = "<group>"; };
+ 491330C31372616300DFB46D /* b2PulleyJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PulleyJoint.h; sourceTree = "<group>"; };
+ 491330C41372616300DFB46D /* b2RevoluteJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2RevoluteJoint.cpp; sourceTree = "<group>"; };
+ 491330C51372616300DFB46D /* b2RevoluteJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2RevoluteJoint.h; sourceTree = "<group>"; };
+ 491330C61372616300DFB46D /* b2WeldJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WeldJoint.cpp; sourceTree = "<group>"; };
+ 491330C71372616300DFB46D /* b2WeldJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WeldJoint.h; sourceTree = "<group>"; };
+ 49133122137262F200DFB46D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 491331271372630700DFB46D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 4913305C1372610400DFB46D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 491331281372630700DFB46D /* UIKit.framework in Frameworks */,
+ 49133123137262F200DFB46D /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 491330541372610400DFB46D = {
+ isa = PBXGroup;
+ children = (
+ 4913307A1372616300DFB46D /* Box2D */,
+ 491331291372630F00DFB46D /* Frameworks */,
+ 491330601372610400DFB46D /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 491330601372610400DFB46D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 4913305F1372610400DFB46D /* libBox2D.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 4913307A1372616300DFB46D /* Box2D */ = {
+ isa = PBXGroup;
+ children = (
+ 4913307B1372616300DFB46D /* Box2D.h */,
+ 4913307C1372616300DFB46D /* Collision */,
+ 4913308F1372616300DFB46D /* Common */,
+ 491330981372616300DFB46D /* Dynamics */,
+ );
+ name = Box2D;
+ path = src/Box2D;
+ sourceTree = "<group>";
+ };
+ 4913307C1372616300DFB46D /* Collision */ = {
+ isa = PBXGroup;
+ children = (
+ 4913307D1372616300DFB46D /* b2BroadPhase.cpp */,
+ 4913307E1372616300DFB46D /* b2BroadPhase.h */,
+ 4913307F1372616300DFB46D /* b2CollideCircle.cpp */,
+ 491330801372616300DFB46D /* b2CollidePolygon.cpp */,
+ 491330811372616300DFB46D /* b2Collision.cpp */,
+ 491330821372616300DFB46D /* b2Collision.h */,
+ 491330831372616300DFB46D /* b2Distance.cpp */,
+ 491330841372616300DFB46D /* b2Distance.h */,
+ 491330851372616300DFB46D /* b2DynamicTree.cpp */,
+ 491330861372616300DFB46D /* b2DynamicTree.h */,
+ 491330871372616300DFB46D /* b2TimeOfImpact.cpp */,
+ 491330881372616300DFB46D /* b2TimeOfImpact.h */,
+ 491330891372616300DFB46D /* Shapes */,
+ );
+ path = Collision;
+ sourceTree = "<group>";
+ };
+ 491330891372616300DFB46D /* Shapes */ = {
+ isa = PBXGroup;
+ children = (
+ 4913308A1372616300DFB46D /* b2CircleShape.cpp */,
+ 4913308B1372616300DFB46D /* b2CircleShape.h */,
+ 4913308C1372616300DFB46D /* b2PolygonShape.cpp */,
+ 4913308D1372616300DFB46D /* b2PolygonShape.h */,
+ 4913308E1372616300DFB46D /* b2Shape.h */,
+ );
+ path = Shapes;
+ sourceTree = "<group>";
+ };
+ 4913308F1372616300DFB46D /* Common */ = {
+ isa = PBXGroup;
+ children = (
+ 491330901372616300DFB46D /* b2BlockAllocator.cpp */,
+ 491330911372616300DFB46D /* b2BlockAllocator.h */,
+ 491330921372616300DFB46D /* b2Math.cpp */,
+ 491330931372616300DFB46D /* b2Math.h */,
+ 491330941372616300DFB46D /* b2Settings.cpp */,
+ 491330951372616300DFB46D /* b2Settings.h */,
+ 491330961372616300DFB46D /* b2StackAllocator.cpp */,
+ 491330971372616300DFB46D /* b2StackAllocator.h */,
+ );
+ path = Common;
+ sourceTree = "<group>";
+ };
+ 491330981372616300DFB46D /* Dynamics */ = {
+ isa = PBXGroup;
+ children = (
+ 491330991372616300DFB46D /* b2Body.cpp */,
+ 4913309A1372616300DFB46D /* b2Body.h */,
+ 4913309B1372616300DFB46D /* b2ContactManager.cpp */,
+ 4913309C1372616300DFB46D /* b2ContactManager.h */,
+ 4913309D1372616300DFB46D /* b2Fixture.cpp */,
+ 4913309E1372616300DFB46D /* b2Fixture.h */,
+ 4913309F1372616300DFB46D /* b2Island.cpp */,
+ 491330A01372616300DFB46D /* b2Island.h */,
+ 491330A11372616300DFB46D /* b2TimeStep.h */,
+ 491330A21372616300DFB46D /* b2World.cpp */,
+ 491330A31372616300DFB46D /* b2World.h */,
+ 491330A41372616300DFB46D /* b2WorldCallbacks.cpp */,
+ 491330A51372616300DFB46D /* b2WorldCallbacks.h */,
+ 491330A61372616300DFB46D /* Contacts */,
+ 491330B31372616300DFB46D /* Joints */,
+ );
+ path = Dynamics;
+ sourceTree = "<group>";
+ };
+ 491330A61372616300DFB46D /* Contacts */ = {
+ isa = PBXGroup;
+ children = (
+ 491330A71372616300DFB46D /* b2CircleContact.cpp */,
+ 491330A81372616300DFB46D /* b2CircleContact.h */,
+ 491330A91372616300DFB46D /* b2Contact.cpp */,
+ 491330AA1372616300DFB46D /* b2Contact.h */,
+ 491330AB1372616300DFB46D /* b2ContactSolver.cpp */,
+ 491330AC1372616300DFB46D /* b2ContactSolver.h */,
+ 491330AD1372616300DFB46D /* b2PolygonAndCircleContact.cpp */,
+ 491330AE1372616300DFB46D /* b2PolygonAndCircleContact.h */,
+ 491330AF1372616300DFB46D /* b2PolygonContact.cpp */,
+ 491330B01372616300DFB46D /* b2PolygonContact.h */,
+ 491330B11372616300DFB46D /* b2TOISolver.cpp */,
+ 491330B21372616300DFB46D /* b2TOISolver.h */,
+ );
+ path = Contacts;
+ sourceTree = "<group>";
+ };
+ 491330B31372616300DFB46D /* Joints */ = {
+ isa = PBXGroup;
+ children = (
+ 491330B41372616300DFB46D /* b2DistanceJoint.cpp */,
+ 491330B51372616300DFB46D /* b2DistanceJoint.h */,
+ 491330B61372616300DFB46D /* b2FrictionJoint.cpp */,
+ 491330B71372616300DFB46D /* b2FrictionJoint.h */,
+ 491330B81372616300DFB46D /* b2GearJoint.cpp */,
+ 491330B91372616300DFB46D /* b2GearJoint.h */,
+ 491330BA1372616300DFB46D /* b2Joint.cpp */,
+ 491330BB1372616300DFB46D /* b2Joint.h */,
+ 491330BC1372616300DFB46D /* b2LineJoint.cpp */,
+ 491330BD1372616300DFB46D /* b2LineJoint.h */,
+ 491330BE1372616300DFB46D /* b2MouseJoint.cpp */,
+ 491330BF1372616300DFB46D /* b2MouseJoint.h */,
+ 491330C01372616300DFB46D /* b2PrismaticJoint.cpp */,
+ 491330C11372616300DFB46D /* b2PrismaticJoint.h */,
+ 491330C21372616300DFB46D /* b2PulleyJoint.cpp */,
+ 491330C31372616300DFB46D /* b2PulleyJoint.h */,
+ 491330C41372616300DFB46D /* b2RevoluteJoint.cpp */,
+ 491330C51372616300DFB46D /* b2RevoluteJoint.h */,
+ 491330C61372616300DFB46D /* b2WeldJoint.cpp */,
+ 491330C71372616300DFB46D /* b2WeldJoint.h */,
+ );
+ path = Joints;
+ sourceTree = "<group>";
+ };
+ 491331291372630F00DFB46D /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 491331271372630700DFB46D /* UIKit.framework */,
+ 49133122137262F200DFB46D /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 4913305D1372610400DFB46D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 491330C81372616300DFB46D /* Box2D.h in Headers */,
+ 491330CA1372616300DFB46D /* b2BroadPhase.h in Headers */,
+ 491330CE1372616300DFB46D /* b2Collision.h in Headers */,
+ 491330D01372616300DFB46D /* b2Distance.h in Headers */,
+ 491330D21372616300DFB46D /* b2DynamicTree.h in Headers */,
+ 491330D41372616300DFB46D /* b2TimeOfImpact.h in Headers */,
+ 491330D61372616300DFB46D /* b2CircleShape.h in Headers */,
+ 491330D81372616300DFB46D /* b2PolygonShape.h in Headers */,
+ 491330D91372616300DFB46D /* b2Shape.h in Headers */,
+ 491330DB1372616300DFB46D /* b2BlockAllocator.h in Headers */,
+ 491330DD1372616300DFB46D /* b2Math.h in Headers */,
+ 491330DF1372616300DFB46D /* b2Settings.h in Headers */,
+ 491330E11372616300DFB46D /* b2StackAllocator.h in Headers */,
+ 491330E31372616300DFB46D /* b2Body.h in Headers */,
+ 491330E51372616300DFB46D /* b2ContactManager.h in Headers */,
+ 491330E71372616300DFB46D /* b2Fixture.h in Headers */,
+ 491330E91372616300DFB46D /* b2Island.h in Headers */,
+ 491330EA1372616300DFB46D /* b2TimeStep.h in Headers */,
+ 491330EC1372616300DFB46D /* b2World.h in Headers */,
+ 491330EE1372616300DFB46D /* b2WorldCallbacks.h in Headers */,
+ 491330F01372616300DFB46D /* b2CircleContact.h in Headers */,
+ 491330F21372616300DFB46D /* b2Contact.h in Headers */,
+ 491330F41372616300DFB46D /* b2ContactSolver.h in Headers */,
+ 491330F61372616300DFB46D /* b2PolygonAndCircleContact.h in Headers */,
+ 491330F81372616300DFB46D /* b2PolygonContact.h in Headers */,
+ 491330FA1372616300DFB46D /* b2TOISolver.h in Headers */,
+ 491330FC1372616300DFB46D /* b2DistanceJoint.h in Headers */,
+ 491330FE1372616300DFB46D /* b2FrictionJoint.h in Headers */,
+ 491331001372616300DFB46D /* b2GearJoint.h in Headers */,
+ 491331021372616300DFB46D /* b2Joint.h in Headers */,
+ 491331041372616300DFB46D /* b2LineJoint.h in Headers */,
+ 491331061372616300DFB46D /* b2MouseJoint.h in Headers */,
+ 491331081372616300DFB46D /* b2PrismaticJoint.h in Headers */,
+ 4913310A1372616300DFB46D /* b2PulleyJoint.h in Headers */,
+ 4913310C1372616300DFB46D /* b2RevoluteJoint.h in Headers */,
+ 4913310E1372616300DFB46D /* b2WeldJoint.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 4913305E1372610400DFB46D /* Box2D */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 491330691372610400DFB46D /* Build configuration list for PBXNativeTarget "Box2D" */;
+ buildPhases = (
+ 4913305B1372610400DFB46D /* Sources */,
+ 4913305C1372610400DFB46D /* Frameworks */,
+ 4913305D1372610400DFB46D /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Box2D;
+ productName = Box2D;
+ productReference = 4913305F1372610400DFB46D /* libBox2D.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 491330561372610400DFB46D /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 491330591372610400DFB46D /* Build configuration list for PBXProject "box2d-ios" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 491330541372610400DFB46D;
+ productRefGroup = 491330601372610400DFB46D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 4913305E1372610400DFB46D /* Box2D */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 4913305B1372610400DFB46D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 491330C91372616300DFB46D /* b2BroadPhase.cpp in Sources */,
+ 491330CB1372616300DFB46D /* b2CollideCircle.cpp in Sources */,
+ 491330CC1372616300DFB46D /* b2CollidePolygon.cpp in Sources */,
+ 491330CD1372616300DFB46D /* b2Collision.cpp in Sources */,
+ 491330CF1372616300DFB46D /* b2Distance.cpp in Sources */,
+ 491330D11372616300DFB46D /* b2DynamicTree.cpp in Sources */,
+ 491330D31372616300DFB46D /* b2TimeOfImpact.cpp in Sources */,
+ 491330D51372616300DFB46D /* b2CircleShape.cpp in Sources */,
+ 491330D71372616300DFB46D /* b2PolygonShape.cpp in Sources */,
+ 491330DA1372616300DFB46D /* b2BlockAllocator.cpp in Sources */,
+ 491330DC1372616300DFB46D /* b2Math.cpp in Sources */,
+ 491330DE1372616300DFB46D /* b2Settings.cpp in Sources */,
+ 491330E01372616300DFB46D /* b2StackAllocator.cpp in Sources */,
+ 491330E21372616300DFB46D /* b2Body.cpp in Sources */,
+ 491330E41372616300DFB46D /* b2ContactManager.cpp in Sources */,
+ 491330E61372616300DFB46D /* b2Fixture.cpp in Sources */,
+ 491330E81372616300DFB46D /* b2Island.cpp in Sources */,
+ 491330EB1372616300DFB46D /* b2World.cpp in Sources */,
+ 491330ED1372616300DFB46D /* b2WorldCallbacks.cpp in Sources */,
+ 491330EF1372616300DFB46D /* b2CircleContact.cpp in Sources */,
+ 491330F11372616300DFB46D /* b2Contact.cpp in Sources */,
+ 491330F31372616300DFB46D /* b2ContactSolver.cpp in Sources */,
+ 491330F51372616300DFB46D /* b2PolygonAndCircleContact.cpp in Sources */,
+ 491330F71372616300DFB46D /* b2PolygonContact.cpp in Sources */,
+ 491330F91372616300DFB46D /* b2TOISolver.cpp in Sources */,
+ 491330FB1372616300DFB46D /* b2DistanceJoint.cpp in Sources */,
+ 491330FD1372616300DFB46D /* b2FrictionJoint.cpp in Sources */,
+ 491330FF1372616300DFB46D /* b2GearJoint.cpp in Sources */,
+ 491331011372616300DFB46D /* b2Joint.cpp in Sources */,
+ 491331031372616300DFB46D /* b2LineJoint.cpp in Sources */,
+ 491331051372616300DFB46D /* b2MouseJoint.cpp in Sources */,
+ 491331071372616300DFB46D /* b2PrismaticJoint.cpp in Sources */,
+ 491331091372616300DFB46D /* b2PulleyJoint.cpp in Sources */,
+ 4913310B1372616300DFB46D /* b2RevoluteJoint.cpp in Sources */,
+ 4913310D1372616300DFB46D /* b2WeldJoint.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 491330671372610400DFB46D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 491330681372610400DFB46D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = 4.2;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+ 4913306A1372610400DFB46D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ DSTROOT = /tmp/Box2D.dst;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "Box2D/Box2D-Prefix.pch";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ USER_HEADER_SEARCH_PATHS = "./src/**";
+ };
+ name = Debug;
+ };
+ 4913306B1372610400DFB46D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ DSTROOT = /tmp/Box2D.dst;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "Box2D/Box2D-Prefix.pch";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ USER_HEADER_SEARCH_PATHS = "./src/**";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 491330591372610400DFB46D /* Build configuration list for PBXProject "box2d-ios" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 491330671372610400DFB46D /* Debug */,
+ 491330681372610400DFB46D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 491330691372610400DFB46D /* Build configuration list for PBXNativeTarget "Box2D" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4913306A1372610400DFB46D /* Debug */,
+ 4913306B1372610400DFB46D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 491330561372610400DFB46D /* Project object */;
+}
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 4913316E1372645C00DFB46D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4913316D1372645C00DFB46D /* UIKit.framework */; };
+ 491331701372645C00DFB46D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4913316F1372645C00DFB46D /* Foundation.framework */; };
+ 491331721372645C00DFB46D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 491331711372645C00DFB46D /* CoreGraphics.framework */; };
+ 491331A91372653600DFB46D /* Box2DAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4913319A1372653600DFB46D /* Box2DAppDelegate.mm */; };
+ 491331AA1372653600DFB46D /* Box2DView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4913319C1372653600DFB46D /* Box2DView.mm */; };
+ 491331AB1372653600DFB46D /* GLES-Render.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4913319F1372653600DFB46D /* GLES-Render.mm */; };
+ 491331AC1372653600DFB46D /* iPhoneTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 491331A11372653600DFB46D /* iPhoneTest.mm */; };
+ 491331AD1372653600DFB46D /* iPhoneTestEntries.mm in Sources */ = {isa = PBXBuildFile; fileRef = 491331A21372653600DFB46D /* iPhoneTestEntries.mm */; };
+ 491331AE1372653600DFB46D /* TestEntriesViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 491331A41372653600DFB46D /* TestEntriesViewController.mm */; };
+ 491331AF1372653600DFB46D /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 491331A51372653600DFB46D /* Icon.png */; };
+ 491331B01372653600DFB46D /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 491331A61372653600DFB46D /* Info.plist */; };
+ 491331B11372653600DFB46D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 491331A71372653600DFB46D /* main.m */; };
+ 491331B21372653600DFB46D /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 491331A81372653600DFB46D /* MainWindow.xib */; };
+ 491331C11372663200DFB46D /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 491331C01372663200DFB46D /* libBox2D.a */; };
+ 4913323813726B1F00DFB46D /* ApplyForce.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913320D13726B1F00DFB46D /* ApplyForce.h */; };
+ 4913323913726B1F00DFB46D /* BodyTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913320E13726B1F00DFB46D /* BodyTypes.h */; };
+ 4913323A13726B1F00DFB46D /* Breakable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913320F13726B1F00DFB46D /* Breakable.h */; };
+ 4913323B13726B1F00DFB46D /* Bridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321013726B1F00DFB46D /* Bridge.h */; };
+ 4913323C13726B1F00DFB46D /* BulletTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321113726B1F00DFB46D /* BulletTest.h */; };
+ 4913323D13726B1F00DFB46D /* Cantilever.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321213726B1F00DFB46D /* Cantilever.h */; };
+ 4913323E13726B1F00DFB46D /* Car.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321313726B1F00DFB46D /* Car.h */; };
+ 4913323F13726B1F00DFB46D /* Chain.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321413726B1F00DFB46D /* Chain.h */; };
+ 4913324013726B1F00DFB46D /* CharacterCollision.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321513726B1F00DFB46D /* CharacterCollision.h */; };
+ 4913324113726B1F00DFB46D /* CollisionFiltering.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321613726B1F00DFB46D /* CollisionFiltering.h */; };
+ 4913324213726B1F00DFB46D /* CollisionProcessing.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321713726B1F00DFB46D /* CollisionProcessing.h */; };
+ 4913324313726B1F00DFB46D /* CompoundShapes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321813726B1F00DFB46D /* CompoundShapes.h */; };
+ 4913324413726B1F00DFB46D /* Confined.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321913726B1F00DFB46D /* Confined.h */; };
+ 4913324513726B1F00DFB46D /* ContinuousTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321A13726B1F00DFB46D /* ContinuousTest.h */; };
+ 4913324613726B1F00DFB46D /* DistanceTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321B13726B1F00DFB46D /* DistanceTest.h */; };
+ 4913324713726B1F00DFB46D /* Dominos.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321C13726B1F00DFB46D /* Dominos.h */; };
+ 4913324813726B1F00DFB46D /* DynamicTreeTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321D13726B1F00DFB46D /* DynamicTreeTest.h */; };
+ 4913324913726B1F00DFB46D /* EdgeShapes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321E13726B1F00DFB46D /* EdgeShapes.h */; };
+ 4913324A13726B1F00DFB46D /* EdgeTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913321F13726B1F00DFB46D /* EdgeTest.h */; };
+ 4913324B13726B1F00DFB46D /* Gears.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322013726B1F00DFB46D /* Gears.h */; };
+ 4913324C13726B1F00DFB46D /* LineJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322113726B1F00DFB46D /* LineJoint.h */; };
+ 4913324D13726B1F00DFB46D /* OneSidedPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322213726B1F00DFB46D /* OneSidedPlatform.h */; };
+ 4913324E13726B1F00DFB46D /* Pinball.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322313726B1F00DFB46D /* Pinball.h */; };
+ 4913324F13726B1F00DFB46D /* PolyCollision.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322413726B1F00DFB46D /* PolyCollision.h */; };
+ 4913325013726B1F00DFB46D /* PolyShapes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322513726B1F00DFB46D /* PolyShapes.h */; };
+ 4913325113726B1F00DFB46D /* Prismatic.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322613726B1F00DFB46D /* Prismatic.h */; };
+ 4913325213726B1F00DFB46D /* Pulleys.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322713726B1F00DFB46D /* Pulleys.h */; };
+ 4913325313726B1F00DFB46D /* Pyramid.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322813726B1F00DFB46D /* Pyramid.h */; };
+ 4913325413726B1F00DFB46D /* RayCast.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322913726B1F00DFB46D /* RayCast.h */; };
+ 4913325513726B1F00DFB46D /* Revolute.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322A13726B1F00DFB46D /* Revolute.h */; };
+ 4913325613726B1F00DFB46D /* Rope.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322B13726B1F00DFB46D /* Rope.h */; };
+ 4913325713726B1F00DFB46D /* RopeJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322C13726B1F00DFB46D /* RopeJoint.h */; };
+ 4913325813726B1F00DFB46D /* SensorTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322D13726B1F00DFB46D /* SensorTest.h */; };
+ 4913325913726B1F00DFB46D /* ShapeEditing.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322E13726B1F00DFB46D /* ShapeEditing.h */; };
+ 4913325A13726B1F00DFB46D /* SliderCrank.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913322F13726B1F00DFB46D /* SliderCrank.h */; };
+ 4913325B13726B1F00DFB46D /* SphereStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323013726B1F00DFB46D /* SphereStack.h */; };
+ 4913325C13726B1F00DFB46D /* TheoJansen.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323113726B1F00DFB46D /* TheoJansen.h */; };
+ 4913325D13726B1F00DFB46D /* Tiles.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323213726B1F00DFB46D /* Tiles.h */; };
+ 4913325E13726B1F00DFB46D /* TimeOfImpact.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323313726B1F00DFB46D /* TimeOfImpact.h */; };
+ 4913325F13726B1F00DFB46D /* VaryingFriction.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323413726B1F00DFB46D /* VaryingFriction.h */; };
+ 4913326013726B1F00DFB46D /* VaryingRestitution.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323513726B1F00DFB46D /* VaryingRestitution.h */; };
+ 4913326113726B1F00DFB46D /* VerticalStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323613726B1F00DFB46D /* VerticalStack.h */; };
+ 4913326213726B1F00DFB46D /* Web.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913323713726B1F00DFB46D /* Web.h */; };
+ 4913326413726B5D00DFB46D /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4913326313726B5D00DFB46D /* OpenGLES.framework */; };
+ 4913326E13726BC800DFB46D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4913326D13726BC800DFB46D /* QuartzCore.framework */; };
+ 4913326F13726D2F00DFB46D /* Box2DAppDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 491331991372653600DFB46D /* Box2DAppDelegate.h */; };
+ 4913327013726D2F00DFB46D /* Box2DView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913319B1372653600DFB46D /* Box2DView.h */; };
+ 4913327113726D2F00DFB46D /* Delegates.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913319D1372653600DFB46D /* Delegates.h */; };
+ 4913327213726D2F00DFB46D /* GLES-Render.h in Headers */ = {isa = PBXBuildFile; fileRef = 4913319E1372653600DFB46D /* GLES-Render.h */; };
+ 4913327313726D2F00DFB46D /* iPhoneTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 491331A01372653600DFB46D /* iPhoneTest.h */; };
+ 4913327413726D2F00DFB46D /* TestEntriesViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 491331A31372653600DFB46D /* TestEntriesViewController.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 491331BB1372661700DFB46D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 491331B41372661600DFB46D /* box2d-ios.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 4913305F1372610400DFB46D;
+ remoteInfo = Box2D;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 491331691372645C00DFB46D /* box2d-iphone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "box2d-iphone.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4913316D1372645C00DFB46D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 4913316F1372645C00DFB46D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 491331711372645C00DFB46D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 491331971372653600DFB46D /* Box2D_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2D_Prefix.pch; sourceTree = "<group>"; };
+ 491331991372653600DFB46D /* Box2DAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2DAppDelegate.h; sourceTree = "<group>"; };
+ 4913319A1372653600DFB46D /* Box2DAppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Box2DAppDelegate.mm; sourceTree = "<group>"; };
+ 4913319B1372653600DFB46D /* Box2DView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2DView.h; sourceTree = "<group>"; };
+ 4913319C1372653600DFB46D /* Box2DView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Box2DView.mm; sourceTree = "<group>"; };
+ 4913319D1372653600DFB46D /* Delegates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Delegates.h; sourceTree = "<group>"; };
+ 4913319E1372653600DFB46D /* GLES-Render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GLES-Render.h"; sourceTree = "<group>"; };
+ 4913319F1372653600DFB46D /* GLES-Render.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "GLES-Render.mm"; sourceTree = "<group>"; };
+ 491331A01372653600DFB46D /* iPhoneTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iPhoneTest.h; sourceTree = "<group>"; };
+ 491331A11372653600DFB46D /* iPhoneTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iPhoneTest.mm; sourceTree = "<group>"; };
+ 491331A21372653600DFB46D /* iPhoneTestEntries.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iPhoneTestEntries.mm; sourceTree = "<group>"; };
+ 491331A31372653600DFB46D /* TestEntriesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestEntriesViewController.h; sourceTree = "<group>"; };
+ 491331A41372653600DFB46D /* TestEntriesViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestEntriesViewController.mm; sourceTree = "<group>"; };
+ 491331A51372653600DFB46D /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = "<group>"; };
+ 491331A61372653600DFB46D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 491331A71372653600DFB46D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 491331A81372653600DFB46D /* MainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = "<group>"; };
+ 491331B41372661600DFB46D /* box2d-ios.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = "box2d-ios.xcodeproj"; sourceTree = SOURCE_ROOT; };
+ 491331C01372663200DFB46D /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libBox2D.a; sourceTree = SOURCE_ROOT; };
+ 4913320D13726B1F00DFB46D /* ApplyForce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyForce.h; sourceTree = "<group>"; };
+ 4913320E13726B1F00DFB46D /* BodyTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BodyTypes.h; sourceTree = "<group>"; };
+ 4913320F13726B1F00DFB46D /* Breakable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakable.h; sourceTree = "<group>"; };
+ 4913321013726B1F00DFB46D /* Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bridge.h; sourceTree = "<group>"; };
+ 4913321113726B1F00DFB46D /* BulletTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BulletTest.h; sourceTree = "<group>"; };
+ 4913321213726B1F00DFB46D /* Cantilever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cantilever.h; sourceTree = "<group>"; };
+ 4913321313726B1F00DFB46D /* Car.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Car.h; sourceTree = "<group>"; };
+ 4913321413726B1F00DFB46D /* Chain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Chain.h; sourceTree = "<group>"; };
+ 4913321513726B1F00DFB46D /* CharacterCollision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CharacterCollision.h; sourceTree = "<group>"; };
+ 4913321613726B1F00DFB46D /* CollisionFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollisionFiltering.h; sourceTree = "<group>"; };
+ 4913321713726B1F00DFB46D /* CollisionProcessing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollisionProcessing.h; sourceTree = "<group>"; };
+ 4913321813726B1F00DFB46D /* CompoundShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompoundShapes.h; sourceTree = "<group>"; };
+ 4913321913726B1F00DFB46D /* Confined.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Confined.h; sourceTree = "<group>"; };
+ 4913321A13726B1F00DFB46D /* ContinuousTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContinuousTest.h; sourceTree = "<group>"; };
+ 4913321B13726B1F00DFB46D /* DistanceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DistanceTest.h; sourceTree = "<group>"; };
+ 4913321C13726B1F00DFB46D /* Dominos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dominos.h; sourceTree = "<group>"; };
+ 4913321D13726B1F00DFB46D /* DynamicTreeTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicTreeTest.h; sourceTree = "<group>"; };
+ 4913321E13726B1F00DFB46D /* EdgeShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeShapes.h; sourceTree = "<group>"; };
+ 4913321F13726B1F00DFB46D /* EdgeTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeTest.h; sourceTree = "<group>"; };
+ 4913322013726B1F00DFB46D /* Gears.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gears.h; sourceTree = "<group>"; };
+ 4913322113726B1F00DFB46D /* LineJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineJoint.h; sourceTree = "<group>"; };
+ 4913322213726B1F00DFB46D /* OneSidedPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneSidedPlatform.h; sourceTree = "<group>"; };
+ 4913322313726B1F00DFB46D /* Pinball.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pinball.h; sourceTree = "<group>"; };
+ 4913322413726B1F00DFB46D /* PolyCollision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolyCollision.h; sourceTree = "<group>"; };
+ 4913322513726B1F00DFB46D /* PolyShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolyShapes.h; sourceTree = "<group>"; };
+ 4913322613726B1F00DFB46D /* Prismatic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prismatic.h; sourceTree = "<group>"; };
+ 4913322713726B1F00DFB46D /* Pulleys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pulleys.h; sourceTree = "<group>"; };
+ 4913322813726B1F00DFB46D /* Pyramid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pyramid.h; sourceTree = "<group>"; };
+ 4913322913726B1F00DFB46D /* RayCast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RayCast.h; sourceTree = "<group>"; };
+ 4913322A13726B1F00DFB46D /* Revolute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Revolute.h; sourceTree = "<group>"; };
+ 4913322B13726B1F00DFB46D /* Rope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rope.h; sourceTree = "<group>"; };
+ 4913322C13726B1F00DFB46D /* RopeJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RopeJoint.h; sourceTree = "<group>"; };
+ 4913322D13726B1F00DFB46D /* SensorTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SensorTest.h; sourceTree = "<group>"; };
+ 4913322E13726B1F00DFB46D /* ShapeEditing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShapeEditing.h; sourceTree = "<group>"; };
+ 4913322F13726B1F00DFB46D /* SliderCrank.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SliderCrank.h; sourceTree = "<group>"; };
+ 4913323013726B1F00DFB46D /* SphereStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SphereStack.h; sourceTree = "<group>"; };
+ 4913323113726B1F00DFB46D /* TheoJansen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TheoJansen.h; sourceTree = "<group>"; };
+ 4913323213726B1F00DFB46D /* Tiles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tiles.h; sourceTree = "<group>"; };
+ 4913323313726B1F00DFB46D /* TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeOfImpact.h; sourceTree = "<group>"; };
+ 4913323413726B1F00DFB46D /* VaryingFriction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VaryingFriction.h; sourceTree = "<group>"; };
+ 4913323513726B1F00DFB46D /* VaryingRestitution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VaryingRestitution.h; sourceTree = "<group>"; };
+ 4913323613726B1F00DFB46D /* VerticalStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VerticalStack.h; sourceTree = "<group>"; };
+ 4913323713726B1F00DFB46D /* Web.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Web.h; sourceTree = "<group>"; };
+ 4913326313726B5D00DFB46D /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
+ 4913326D13726BC800DFB46D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 491331661372645C00DFB46D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4913326E13726BC800DFB46D /* QuartzCore.framework in Frameworks */,
+ 4913326413726B5D00DFB46D /* OpenGLES.framework in Frameworks */,
+ 4913316E1372645C00DFB46D /* UIKit.framework in Frameworks */,
+ 491331701372645C00DFB46D /* Foundation.framework in Frameworks */,
+ 491331721372645C00DFB46D /* CoreGraphics.framework in Frameworks */,
+ 491331C11372663200DFB46D /* libBox2D.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 4913315E1372645C00DFB46D = {
+ isa = PBXGroup;
+ children = (
+ 491331B41372661600DFB46D /* box2d-ios.xcodeproj */,
+ 491331961372653600DFB46D /* iPhone */,
+ 4913320C13726B1F00DFB46D /* Tests */,
+ 491331B31372654900DFB46D /* Resources */,
+ 4913316C1372645C00DFB46D /* Frameworks */,
+ 4913316A1372645C00DFB46D /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 4913316A1372645C00DFB46D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 491331691372645C00DFB46D /* box2d-iphone.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 4913316C1372645C00DFB46D /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 4913326D13726BC800DFB46D /* QuartzCore.framework */,
+ 4913326313726B5D00DFB46D /* OpenGLES.framework */,
+ 491331C01372663200DFB46D /* libBox2D.a */,
+ 4913316D1372645C00DFB46D /* UIKit.framework */,
+ 4913316F1372645C00DFB46D /* Foundation.framework */,
+ 491331711372645C00DFB46D /* CoreGraphics.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 491331961372653600DFB46D /* iPhone */ = {
+ isa = PBXGroup;
+ children = (
+ 491331971372653600DFB46D /* Box2D_Prefix.pch */,
+ 491331981372653600DFB46D /* Classes */,
+ 491331A71372653600DFB46D /* main.m */,
+ 491331A81372653600DFB46D /* MainWindow.xib */,
+ );
+ path = iPhone;
+ sourceTree = "<group>";
+ };
+ 491331981372653600DFB46D /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ 491331991372653600DFB46D /* Box2DAppDelegate.h */,
+ 4913319A1372653600DFB46D /* Box2DAppDelegate.mm */,
+ 4913319B1372653600DFB46D /* Box2DView.h */,
+ 4913319C1372653600DFB46D /* Box2DView.mm */,
+ 4913319D1372653600DFB46D /* Delegates.h */,
+ 4913319E1372653600DFB46D /* GLES-Render.h */,
+ 4913319F1372653600DFB46D /* GLES-Render.mm */,
+ 491331A01372653600DFB46D /* iPhoneTest.h */,
+ 491331A11372653600DFB46D /* iPhoneTest.mm */,
+ 491331A21372653600DFB46D /* iPhoneTestEntries.mm */,
+ 491331A31372653600DFB46D /* TestEntriesViewController.h */,
+ 491331A41372653600DFB46D /* TestEntriesViewController.mm */,
+ );
+ path = Classes;
+ sourceTree = "<group>";
+ };
+ 491331B31372654900DFB46D /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 491331A51372653600DFB46D /* Icon.png */,
+ 491331A61372653600DFB46D /* Info.plist */,
+ );
+ name = Resources;
+ path = iPhone;
+ sourceTree = "<group>";
+ };
+ 491331B51372661600DFB46D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 491331BC1372661700DFB46D /* libBox2D.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 4913320C13726B1F00DFB46D /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ 4913320D13726B1F00DFB46D /* ApplyForce.h */,
+ 4913320E13726B1F00DFB46D /* BodyTypes.h */,
+ 4913320F13726B1F00DFB46D /* Breakable.h */,
+ 4913321013726B1F00DFB46D /* Bridge.h */,
+ 4913321113726B1F00DFB46D /* BulletTest.h */,
+ 4913321213726B1F00DFB46D /* Cantilever.h */,
+ 4913321313726B1F00DFB46D /* Car.h */,
+ 4913321413726B1F00DFB46D /* Chain.h */,
+ 4913321513726B1F00DFB46D /* CharacterCollision.h */,
+ 4913321613726B1F00DFB46D /* CollisionFiltering.h */,
+ 4913321713726B1F00DFB46D /* CollisionProcessing.h */,
+ 4913321813726B1F00DFB46D /* CompoundShapes.h */,
+ 4913321913726B1F00DFB46D /* Confined.h */,
+ 4913321A13726B1F00DFB46D /* ContinuousTest.h */,
+ 4913321B13726B1F00DFB46D /* DistanceTest.h */,
+ 4913321C13726B1F00DFB46D /* Dominos.h */,
+ 4913321D13726B1F00DFB46D /* DynamicTreeTest.h */,
+ 4913321E13726B1F00DFB46D /* EdgeShapes.h */,
+ 4913321F13726B1F00DFB46D /* EdgeTest.h */,
+ 4913322013726B1F00DFB46D /* Gears.h */,
+ 4913322113726B1F00DFB46D /* LineJoint.h */,
+ 4913322213726B1F00DFB46D /* OneSidedPlatform.h */,
+ 4913322313726B1F00DFB46D /* Pinball.h */,
+ 4913322413726B1F00DFB46D /* PolyCollision.h */,
+ 4913322513726B1F00DFB46D /* PolyShapes.h */,
+ 4913322613726B1F00DFB46D /* Prismatic.h */,
+ 4913322713726B1F00DFB46D /* Pulleys.h */,
+ 4913322813726B1F00DFB46D /* Pyramid.h */,
+ 4913322913726B1F00DFB46D /* RayCast.h */,
+ 4913322A13726B1F00DFB46D /* Revolute.h */,
+ 4913322B13726B1F00DFB46D /* Rope.h */,
+ 4913322C13726B1F00DFB46D /* RopeJoint.h */,
+ 4913322D13726B1F00DFB46D /* SensorTest.h */,
+ 4913322E13726B1F00DFB46D /* ShapeEditing.h */,
+ 4913322F13726B1F00DFB46D /* SliderCrank.h */,
+ 4913323013726B1F00DFB46D /* SphereStack.h */,
+ 4913323113726B1F00DFB46D /* TheoJansen.h */,
+ 4913323213726B1F00DFB46D /* Tiles.h */,
+ 4913323313726B1F00DFB46D /* TimeOfImpact.h */,
+ 4913323413726B1F00DFB46D /* VaryingFriction.h */,
+ 4913323513726B1F00DFB46D /* VaryingRestitution.h */,
+ 4913323613726B1F00DFB46D /* VerticalStack.h */,
+ 4913323713726B1F00DFB46D /* Web.h */,
+ );
+ name = Tests;
+ path = src/Tests;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 491331E71372682200DFB46D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4913326F13726D2F00DFB46D /* Box2DAppDelegate.h in Headers */,
+ 4913327013726D2F00DFB46D /* Box2DView.h in Headers */,
+ 4913327113726D2F00DFB46D /* Delegates.h in Headers */,
+ 4913327213726D2F00DFB46D /* GLES-Render.h in Headers */,
+ 4913327313726D2F00DFB46D /* iPhoneTest.h in Headers */,
+ 4913327413726D2F00DFB46D /* TestEntriesViewController.h in Headers */,
+ 4913323813726B1F00DFB46D /* ApplyForce.h in Headers */,
+ 4913323913726B1F00DFB46D /* BodyTypes.h in Headers */,
+ 4913323A13726B1F00DFB46D /* Breakable.h in Headers */,
+ 4913323B13726B1F00DFB46D /* Bridge.h in Headers */,
+ 4913323C13726B1F00DFB46D /* BulletTest.h in Headers */,
+ 4913323D13726B1F00DFB46D /* Cantilever.h in Headers */,
+ 4913323E13726B1F00DFB46D /* Car.h in Headers */,
+ 4913323F13726B1F00DFB46D /* Chain.h in Headers */,
+ 4913324013726B1F00DFB46D /* CharacterCollision.h in Headers */,
+ 4913324113726B1F00DFB46D /* CollisionFiltering.h in Headers */,
+ 4913324213726B1F00DFB46D /* CollisionProcessing.h in Headers */,
+ 4913324313726B1F00DFB46D /* CompoundShapes.h in Headers */,
+ 4913324413726B1F00DFB46D /* Confined.h in Headers */,
+ 4913324513726B1F00DFB46D /* ContinuousTest.h in Headers */,
+ 4913324613726B1F00DFB46D /* DistanceTest.h in Headers */,
+ 4913324713726B1F00DFB46D /* Dominos.h in Headers */,
+ 4913324813726B1F00DFB46D /* DynamicTreeTest.h in Headers */,
+ 4913324913726B1F00DFB46D /* EdgeShapes.h in Headers */,
+ 4913324A13726B1F00DFB46D /* EdgeTest.h in Headers */,
+ 4913324B13726B1F00DFB46D /* Gears.h in Headers */,
+ 4913324C13726B1F00DFB46D /* LineJoint.h in Headers */,
+ 4913324D13726B1F00DFB46D /* OneSidedPlatform.h in Headers */,
+ 4913324E13726B1F00DFB46D /* Pinball.h in Headers */,
+ 4913324F13726B1F00DFB46D /* PolyCollision.h in Headers */,
+ 4913325013726B1F00DFB46D /* PolyShapes.h in Headers */,
+ 4913325113726B1F00DFB46D /* Prismatic.h in Headers */,
+ 4913325213726B1F00DFB46D /* Pulleys.h in Headers */,
+ 4913325313726B1F00DFB46D /* Pyramid.h in Headers */,
+ 4913325413726B1F00DFB46D /* RayCast.h in Headers */,
+ 4913325513726B1F00DFB46D /* Revolute.h in Headers */,
+ 4913325613726B1F00DFB46D /* Rope.h in Headers */,
+ 4913325713726B1F00DFB46D /* RopeJoint.h in Headers */,
+ 4913325813726B1F00DFB46D /* SensorTest.h in Headers */,
+ 4913325913726B1F00DFB46D /* ShapeEditing.h in Headers */,
+ 4913325A13726B1F00DFB46D /* SliderCrank.h in Headers */,
+ 4913325B13726B1F00DFB46D /* SphereStack.h in Headers */,
+ 4913325C13726B1F00DFB46D /* TheoJansen.h in Headers */,
+ 4913325D13726B1F00DFB46D /* Tiles.h in Headers */,
+ 4913325E13726B1F00DFB46D /* TimeOfImpact.h in Headers */,
+ 4913325F13726B1F00DFB46D /* VaryingFriction.h in Headers */,
+ 4913326013726B1F00DFB46D /* VaryingRestitution.h in Headers */,
+ 4913326113726B1F00DFB46D /* VerticalStack.h in Headers */,
+ 4913326213726B1F00DFB46D /* Web.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 491331681372645C00DFB46D /* box2d-iphone */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 491331841372645C00DFB46D /* Build configuration list for PBXNativeTarget "box2d-iphone" */;
+ buildPhases = (
+ 491331651372645C00DFB46D /* Sources */,
+ 491331661372645C00DFB46D /* Frameworks */,
+ 491331671372645C00DFB46D /* Resources */,
+ 491331E71372682200DFB46D /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "box2d-iphone";
+ productName = "box2d-iphone";
+ productReference = 491331691372645C00DFB46D /* box2d-iphone.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 491331601372645C00DFB46D /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 491331631372645C00DFB46D /* Build configuration list for PBXProject "box2d-iphone" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 4913315E1372645C00DFB46D;
+ productRefGroup = 4913316A1372645C00DFB46D /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 491331B51372661600DFB46D /* Products */;
+ ProjectRef = 491331B41372661600DFB46D /* box2d-ios.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 491331681372645C00DFB46D /* box2d-iphone */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 491331BC1372661700DFB46D /* libBox2D.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libBox2D.a;
+ remoteRef = 491331BB1372661700DFB46D /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 491331671372645C00DFB46D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 491331AF1372653600DFB46D /* Icon.png in Resources */,
+ 491331B01372653600DFB46D /* Info.plist in Resources */,
+ 491331B21372653600DFB46D /* MainWindow.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 491331651372645C00DFB46D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 491331A91372653600DFB46D /* Box2DAppDelegate.mm in Sources */,
+ 491331AA1372653600DFB46D /* Box2DView.mm in Sources */,
+ 491331AB1372653600DFB46D /* GLES-Render.mm in Sources */,
+ 491331AC1372653600DFB46D /* iPhoneTest.mm in Sources */,
+ 491331AD1372653600DFB46D /* iPhoneTestEntries.mm in Sources */,
+ 491331AE1372653600DFB46D /* TestEntriesViewController.mm in Sources */,
+ 491331B11372653600DFB46D /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 491331821372645C00DFB46D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvmgcc42;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 491331831372645C00DFB46D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = com.apple.compilers.llvmgcc42;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+ OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+ 491331851372645C00DFB46D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "box2d-iphone/box2d-iphone-Prefix.pch";
+ GCC_VERSION = 4.2;
+ HEADER_SEARCH_PATHS = "./src/**";
+ INFOPLIST_FILE = "box2d-iphone/box2d-iphone-Info.plist";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)\"",
+ );
+ OTHER_LDFLAGS = "-Wl,-search_paths_first";
+ PREBINDING = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ USER_HEADER_SEARCH_PATHS = "./src/**";
+ USE_HEADERMAP = NO;
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ 491331861372645C00DFB46D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ COPY_PHASE_STRIP = YES;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "box2d-iphone/box2d-iphone-Prefix.pch";
+ GCC_VERSION = 4.2;
+ HEADER_SEARCH_PATHS = "./src/**";
+ INFOPLIST_FILE = "box2d-iphone/box2d-iphone-Info.plist";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)\"",
+ );
+ OTHER_LDFLAGS = "-Wl,-search_paths_first";
+ PREBINDING = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ USER_HEADER_SEARCH_PATHS = "./src/**";
+ USE_HEADERMAP = NO;
+ VALIDATE_PRODUCT = YES;
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 491331631372645C00DFB46D /* Build configuration list for PBXProject "box2d-iphone" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 491331821372645C00DFB46D /* Debug */,
+ 491331831372645C00DFB46D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 491331841372645C00DFB46D /* Build configuration list for PBXNativeTarget "box2d-iphone" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 491331851372645C00DFB46D /* Debug */,
+ 491331861372645C00DFB46D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 491331601372645C00DFB46D /* Project object */;
+}
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 49132FCD13725D1000DFB46D /* Box2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F8013725D1000DFB46D /* Box2D.h */; };
+ 49132FCE13725D1000DFB46D /* b2BroadPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8213725D1000DFB46D /* b2BroadPhase.cpp */; };
+ 49132FCF13725D1000DFB46D /* b2BroadPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F8313725D1000DFB46D /* b2BroadPhase.h */; };
+ 49132FD013725D1000DFB46D /* b2CollideCircle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8413725D1000DFB46D /* b2CollideCircle.cpp */; };
+ 49132FD113725D1000DFB46D /* b2CollidePolygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8513725D1000DFB46D /* b2CollidePolygon.cpp */; };
+ 49132FD213725D1000DFB46D /* b2Collision.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8613725D1000DFB46D /* b2Collision.cpp */; };
+ 49132FD313725D1000DFB46D /* b2Collision.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F8713725D1000DFB46D /* b2Collision.h */; };
+ 49132FD413725D1000DFB46D /* b2Distance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8813725D1000DFB46D /* b2Distance.cpp */; };
+ 49132FD513725D1000DFB46D /* b2Distance.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F8913725D1000DFB46D /* b2Distance.h */; };
+ 49132FD613725D1000DFB46D /* b2DynamicTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8A13725D1000DFB46D /* b2DynamicTree.cpp */; };
+ 49132FD713725D1000DFB46D /* b2DynamicTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F8B13725D1000DFB46D /* b2DynamicTree.h */; };
+ 49132FD813725D1000DFB46D /* b2TimeOfImpact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8C13725D1000DFB46D /* b2TimeOfImpact.cpp */; };
+ 49132FD913725D1000DFB46D /* b2TimeOfImpact.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F8D13725D1000DFB46D /* b2TimeOfImpact.h */; };
+ 49132FDA13725D1000DFB46D /* b2CircleShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F8F13725D1000DFB46D /* b2CircleShape.cpp */; };
+ 49132FDB13725D1000DFB46D /* b2CircleShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9013725D1000DFB46D /* b2CircleShape.h */; };
+ 49132FDC13725D1000DFB46D /* b2PolygonShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F9113725D1000DFB46D /* b2PolygonShape.cpp */; };
+ 49132FDD13725D1000DFB46D /* b2PolygonShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9213725D1000DFB46D /* b2PolygonShape.h */; };
+ 49132FDE13725D1000DFB46D /* b2Shape.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9313725D1000DFB46D /* b2Shape.h */; };
+ 49132FDF13725D1000DFB46D /* b2BlockAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F9513725D1000DFB46D /* b2BlockAllocator.cpp */; };
+ 49132FE013725D1000DFB46D /* b2BlockAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9613725D1000DFB46D /* b2BlockAllocator.h */; };
+ 49132FE113725D1000DFB46D /* b2Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F9713725D1000DFB46D /* b2Math.cpp */; };
+ 49132FE213725D1000DFB46D /* b2Math.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9813725D1000DFB46D /* b2Math.h */; };
+ 49132FE313725D1000DFB46D /* b2Settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F9913725D1000DFB46D /* b2Settings.cpp */; };
+ 49132FE413725D1000DFB46D /* b2Settings.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9A13725D1000DFB46D /* b2Settings.h */; };
+ 49132FE513725D1000DFB46D /* b2StackAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F9B13725D1000DFB46D /* b2StackAllocator.cpp */; };
+ 49132FE613725D1000DFB46D /* b2StackAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9C13725D1000DFB46D /* b2StackAllocator.h */; };
+ 49132FE713725D1000DFB46D /* b2Body.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132F9E13725D1000DFB46D /* b2Body.cpp */; };
+ 49132FE813725D1000DFB46D /* b2Body.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132F9F13725D1000DFB46D /* b2Body.h */; };
+ 49132FE913725D1000DFB46D /* b2ContactManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FA013725D1000DFB46D /* b2ContactManager.cpp */; };
+ 49132FEA13725D1000DFB46D /* b2ContactManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FA113725D1000DFB46D /* b2ContactManager.h */; };
+ 49132FEB13725D1000DFB46D /* b2Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FA213725D1000DFB46D /* b2Fixture.cpp */; };
+ 49132FEC13725D1000DFB46D /* b2Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FA313725D1000DFB46D /* b2Fixture.h */; };
+ 49132FED13725D1000DFB46D /* b2Island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FA413725D1000DFB46D /* b2Island.cpp */; };
+ 49132FEE13725D1000DFB46D /* b2Island.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FA513725D1000DFB46D /* b2Island.h */; };
+ 49132FEF13725D1000DFB46D /* b2TimeStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FA613725D1000DFB46D /* b2TimeStep.h */; };
+ 49132FF013725D1000DFB46D /* b2World.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FA713725D1000DFB46D /* b2World.cpp */; };
+ 49132FF113725D1000DFB46D /* b2World.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FA813725D1000DFB46D /* b2World.h */; };
+ 49132FF213725D1000DFB46D /* b2WorldCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FA913725D1000DFB46D /* b2WorldCallbacks.cpp */; };
+ 49132FF313725D1000DFB46D /* b2WorldCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FAA13725D1000DFB46D /* b2WorldCallbacks.h */; };
+ 49132FF413725D1000DFB46D /* b2CircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FAC13725D1000DFB46D /* b2CircleContact.cpp */; };
+ 49132FF513725D1000DFB46D /* b2CircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FAD13725D1000DFB46D /* b2CircleContact.h */; };
+ 49132FF613725D1000DFB46D /* b2Contact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FAE13725D1000DFB46D /* b2Contact.cpp */; };
+ 49132FF713725D1000DFB46D /* b2Contact.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FAF13725D1000DFB46D /* b2Contact.h */; };
+ 49132FF813725D1000DFB46D /* b2ContactSolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FB013725D1000DFB46D /* b2ContactSolver.cpp */; };
+ 49132FF913725D1000DFB46D /* b2ContactSolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FB113725D1000DFB46D /* b2ContactSolver.h */; };
+ 49132FFA13725D1000DFB46D /* b2PolygonAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FB213725D1000DFB46D /* b2PolygonAndCircleContact.cpp */; };
+ 49132FFB13725D1000DFB46D /* b2PolygonAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FB313725D1000DFB46D /* b2PolygonAndCircleContact.h */; };
+ 49132FFC13725D1000DFB46D /* b2PolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FB413725D1000DFB46D /* b2PolygonContact.cpp */; };
+ 49132FFD13725D1000DFB46D /* b2PolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FB513725D1000DFB46D /* b2PolygonContact.h */; };
+ 49132FFE13725D1000DFB46D /* b2TOISolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FB613725D1000DFB46D /* b2TOISolver.cpp */; };
+ 49132FFF13725D1000DFB46D /* b2TOISolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FB713725D1000DFB46D /* b2TOISolver.h */; };
+ 4913300013725D1000DFB46D /* b2DistanceJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FB913725D1000DFB46D /* b2DistanceJoint.cpp */; };
+ 4913300113725D1000DFB46D /* b2DistanceJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FBA13725D1000DFB46D /* b2DistanceJoint.h */; };
+ 4913300213725D1000DFB46D /* b2FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FBB13725D1000DFB46D /* b2FrictionJoint.cpp */; };
+ 4913300313725D1000DFB46D /* b2FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FBC13725D1000DFB46D /* b2FrictionJoint.h */; };
+ 4913300413725D1000DFB46D /* b2GearJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FBD13725D1000DFB46D /* b2GearJoint.cpp */; };
+ 4913300513725D1000DFB46D /* b2GearJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FBE13725D1000DFB46D /* b2GearJoint.h */; };
+ 4913300613725D1000DFB46D /* b2Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FBF13725D1000DFB46D /* b2Joint.cpp */; };
+ 4913300713725D1000DFB46D /* b2Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FC013725D1000DFB46D /* b2Joint.h */; };
+ 4913300813725D1000DFB46D /* b2LineJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FC113725D1000DFB46D /* b2LineJoint.cpp */; };
+ 4913300913725D1000DFB46D /* b2LineJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FC213725D1000DFB46D /* b2LineJoint.h */; };
+ 4913300A13725D1000DFB46D /* b2MouseJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FC313725D1000DFB46D /* b2MouseJoint.cpp */; };
+ 4913300B13725D1000DFB46D /* b2MouseJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FC413725D1000DFB46D /* b2MouseJoint.h */; };
+ 4913300C13725D1000DFB46D /* b2PrismaticJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FC513725D1000DFB46D /* b2PrismaticJoint.cpp */; };
+ 4913300D13725D1000DFB46D /* b2PrismaticJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FC613725D1000DFB46D /* b2PrismaticJoint.h */; };
+ 4913300E13725D1000DFB46D /* b2PulleyJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FC713725D1000DFB46D /* b2PulleyJoint.cpp */; };
+ 4913300F13725D1000DFB46D /* b2PulleyJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FC813725D1000DFB46D /* b2PulleyJoint.h */; };
+ 4913301013725D1000DFB46D /* b2RevoluteJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FC913725D1000DFB46D /* b2RevoluteJoint.cpp */; };
+ 4913301113725D1000DFB46D /* b2RevoluteJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FCA13725D1000DFB46D /* b2RevoluteJoint.h */; };
+ 4913301213725D1000DFB46D /* b2WeldJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49132FCB13725D1000DFB46D /* b2WeldJoint.cpp */; };
+ 4913301313725D1000DFB46D /* b2WeldJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 49132FCC13725D1000DFB46D /* b2WeldJoint.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 49132F7113725CDD00DFB46D /* Box2D.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = Box2D.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 49132F7413725CDD00DFB46D /* Box2D-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Box2D-Prefix.pch"; sourceTree = "<group>"; };
+ 49132F7513725CDD00DFB46D /* Box2DProj.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Box2DProj.xcconfig; sourceTree = "<group>"; };
+ 49132F7613725CDD00DFB46D /* Box2DTarget.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Box2DTarget.xcconfig; sourceTree = "<group>"; };
+ 49132F8013725D1000DFB46D /* Box2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2D.h; sourceTree = "<group>"; };
+ 49132F8213725D1000DFB46D /* b2BroadPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BroadPhase.cpp; sourceTree = "<group>"; };
+ 49132F8313725D1000DFB46D /* b2BroadPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BroadPhase.h; sourceTree = "<group>"; };
+ 49132F8413725D1000DFB46D /* b2CollideCircle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideCircle.cpp; sourceTree = "<group>"; };
+ 49132F8513725D1000DFB46D /* b2CollidePolygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollidePolygon.cpp; sourceTree = "<group>"; };
+ 49132F8613725D1000DFB46D /* b2Collision.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Collision.cpp; sourceTree = "<group>"; };
+ 49132F8713725D1000DFB46D /* b2Collision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Collision.h; sourceTree = "<group>"; };
+ 49132F8813725D1000DFB46D /* b2Distance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Distance.cpp; sourceTree = "<group>"; };
+ 49132F8913725D1000DFB46D /* b2Distance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Distance.h; sourceTree = "<group>"; };
+ 49132F8A13725D1000DFB46D /* b2DynamicTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DynamicTree.cpp; sourceTree = "<group>"; };
+ 49132F8B13725D1000DFB46D /* b2DynamicTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DynamicTree.h; sourceTree = "<group>"; };
+ 49132F8C13725D1000DFB46D /* b2TimeOfImpact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2TimeOfImpact.cpp; sourceTree = "<group>"; };
+ 49132F8D13725D1000DFB46D /* b2TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeOfImpact.h; sourceTree = "<group>"; };
+ 49132F8F13725D1000DFB46D /* b2CircleShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleShape.cpp; sourceTree = "<group>"; };
+ 49132F9013725D1000DFB46D /* b2CircleShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleShape.h; sourceTree = "<group>"; };
+ 49132F9113725D1000DFB46D /* b2PolygonShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonShape.cpp; sourceTree = "<group>"; };
+ 49132F9213725D1000DFB46D /* b2PolygonShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonShape.h; sourceTree = "<group>"; };
+ 49132F9313725D1000DFB46D /* b2Shape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Shape.h; sourceTree = "<group>"; };
+ 49132F9513725D1000DFB46D /* b2BlockAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BlockAllocator.cpp; sourceTree = "<group>"; };
+ 49132F9613725D1000DFB46D /* b2BlockAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BlockAllocator.h; sourceTree = "<group>"; };
+ 49132F9713725D1000DFB46D /* b2Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Math.cpp; sourceTree = "<group>"; };
+ 49132F9813725D1000DFB46D /* b2Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Math.h; sourceTree = "<group>"; };
+ 49132F9913725D1000DFB46D /* b2Settings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Settings.cpp; sourceTree = "<group>"; };
+ 49132F9A13725D1000DFB46D /* b2Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Settings.h; sourceTree = "<group>"; };
+ 49132F9B13725D1000DFB46D /* b2StackAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2StackAllocator.cpp; sourceTree = "<group>"; };
+ 49132F9C13725D1000DFB46D /* b2StackAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2StackAllocator.h; sourceTree = "<group>"; };
+ 49132F9E13725D1000DFB46D /* b2Body.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Body.cpp; sourceTree = "<group>"; };
+ 49132F9F13725D1000DFB46D /* b2Body.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Body.h; sourceTree = "<group>"; };
+ 49132FA013725D1000DFB46D /* b2ContactManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactManager.cpp; sourceTree = "<group>"; };
+ 49132FA113725D1000DFB46D /* b2ContactManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactManager.h; sourceTree = "<group>"; };
+ 49132FA213725D1000DFB46D /* b2Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Fixture.cpp; sourceTree = "<group>"; };
+ 49132FA313725D1000DFB46D /* b2Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Fixture.h; sourceTree = "<group>"; };
+ 49132FA413725D1000DFB46D /* b2Island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Island.cpp; sourceTree = "<group>"; };
+ 49132FA513725D1000DFB46D /* b2Island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Island.h; sourceTree = "<group>"; };
+ 49132FA613725D1000DFB46D /* b2TimeStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeStep.h; sourceTree = "<group>"; };
+ 49132FA713725D1000DFB46D /* b2World.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2World.cpp; sourceTree = "<group>"; };
+ 49132FA813725D1000DFB46D /* b2World.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2World.h; sourceTree = "<group>"; };
+ 49132FA913725D1000DFB46D /* b2WorldCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WorldCallbacks.cpp; sourceTree = "<group>"; };
+ 49132FAA13725D1000DFB46D /* b2WorldCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WorldCallbacks.h; sourceTree = "<group>"; };
+ 49132FAC13725D1000DFB46D /* b2CircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleContact.cpp; sourceTree = "<group>"; };
+ 49132FAD13725D1000DFB46D /* b2CircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleContact.h; sourceTree = "<group>"; };
+ 49132FAE13725D1000DFB46D /* b2Contact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Contact.cpp; sourceTree = "<group>"; };
+ 49132FAF13725D1000DFB46D /* b2Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Contact.h; sourceTree = "<group>"; };
+ 49132FB013725D1000DFB46D /* b2ContactSolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactSolver.cpp; sourceTree = "<group>"; };
+ 49132FB113725D1000DFB46D /* b2ContactSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactSolver.h; sourceTree = "<group>"; };
+ 49132FB213725D1000DFB46D /* b2PolygonAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonAndCircleContact.cpp; sourceTree = "<group>"; };
+ 49132FB313725D1000DFB46D /* b2PolygonAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonAndCircleContact.h; sourceTree = "<group>"; };
+ 49132FB413725D1000DFB46D /* b2PolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonContact.cpp; sourceTree = "<group>"; };
+ 49132FB513725D1000DFB46D /* b2PolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonContact.h; sourceTree = "<group>"; };
+ 49132FB613725D1000DFB46D /* b2TOISolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2TOISolver.cpp; sourceTree = "<group>"; };
+ 49132FB713725D1000DFB46D /* b2TOISolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TOISolver.h; sourceTree = "<group>"; };
+ 49132FB913725D1000DFB46D /* b2DistanceJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DistanceJoint.cpp; sourceTree = "<group>"; };
+ 49132FBA13725D1000DFB46D /* b2DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DistanceJoint.h; sourceTree = "<group>"; };
+ 49132FBB13725D1000DFB46D /* b2FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2FrictionJoint.cpp; sourceTree = "<group>"; };
+ 49132FBC13725D1000DFB46D /* b2FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2FrictionJoint.h; sourceTree = "<group>"; };
+ 49132FBD13725D1000DFB46D /* b2GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2GearJoint.cpp; sourceTree = "<group>"; };
+ 49132FBE13725D1000DFB46D /* b2GearJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2GearJoint.h; sourceTree = "<group>"; };
+ 49132FBF13725D1000DFB46D /* b2Joint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Joint.cpp; sourceTree = "<group>"; };
+ 49132FC013725D1000DFB46D /* b2Joint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Joint.h; sourceTree = "<group>"; };
+ 49132FC113725D1000DFB46D /* b2LineJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2LineJoint.cpp; sourceTree = "<group>"; };
+ 49132FC213725D1000DFB46D /* b2LineJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2LineJoint.h; sourceTree = "<group>"; };
+ 49132FC313725D1000DFB46D /* b2MouseJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2MouseJoint.cpp; sourceTree = "<group>"; };
+ 49132FC413725D1000DFB46D /* b2MouseJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2MouseJoint.h; sourceTree = "<group>"; };
+ 49132FC513725D1000DFB46D /* b2PrismaticJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PrismaticJoint.cpp; sourceTree = "<group>"; };
+ 49132FC613725D1000DFB46D /* b2PrismaticJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PrismaticJoint.h; sourceTree = "<group>"; };
+ 49132FC713725D1000DFB46D /* b2PulleyJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PulleyJoint.cpp; sourceTree = "<group>"; };
+ 49132FC813725D1000DFB46D /* b2PulleyJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PulleyJoint.h; sourceTree = "<group>"; };
+ 49132FC913725D1000DFB46D /* b2RevoluteJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2RevoluteJoint.cpp; sourceTree = "<group>"; };
+ 49132FCA13725D1000DFB46D /* b2RevoluteJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2RevoluteJoint.h; sourceTree = "<group>"; };
+ 49132FCB13725D1000DFB46D /* b2WeldJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WeldJoint.cpp; sourceTree = "<group>"; };
+ 49132FCC13725D1000DFB46D /* b2WeldJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WeldJoint.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 49132F6E13725CDD00DFB46D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 49132EDD13725A9600DFB46D = {
+ isa = PBXGroup;
+ children = (
+ 49132F7F13725D1000DFB46D /* Box2D */,
+ 49132F7113725CDD00DFB46D /* Box2D.dylib */,
+ 49132F7213725CDD00DFB46D /* Box2D */,
+ );
+ sourceTree = "<group>";
+ };
+ 49132F7213725CDD00DFB46D /* Box2D */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F7513725CDD00DFB46D /* Box2DProj.xcconfig */,
+ 49132F7613725CDD00DFB46D /* Box2DTarget.xcconfig */,
+ 49132F7313725CDD00DFB46D /* Supporting Files */,
+ );
+ path = Box2D;
+ sourceTree = "<group>";
+ };
+ 49132F7313725CDD00DFB46D /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F7413725CDD00DFB46D /* Box2D-Prefix.pch */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 49132F7F13725D1000DFB46D /* Box2D */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F8013725D1000DFB46D /* Box2D.h */,
+ 49132F8113725D1000DFB46D /* Collision */,
+ 49132F9413725D1000DFB46D /* Common */,
+ 49132F9D13725D1000DFB46D /* Dynamics */,
+ );
+ name = Box2D;
+ path = src/Box2D;
+ sourceTree = "<group>";
+ };
+ 49132F8113725D1000DFB46D /* Collision */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F8213725D1000DFB46D /* b2BroadPhase.cpp */,
+ 49132F8313725D1000DFB46D /* b2BroadPhase.h */,
+ 49132F8413725D1000DFB46D /* b2CollideCircle.cpp */,
+ 49132F8513725D1000DFB46D /* b2CollidePolygon.cpp */,
+ 49132F8613725D1000DFB46D /* b2Collision.cpp */,
+ 49132F8713725D1000DFB46D /* b2Collision.h */,
+ 49132F8813725D1000DFB46D /* b2Distance.cpp */,
+ 49132F8913725D1000DFB46D /* b2Distance.h */,
+ 49132F8A13725D1000DFB46D /* b2DynamicTree.cpp */,
+ 49132F8B13725D1000DFB46D /* b2DynamicTree.h */,
+ 49132F8C13725D1000DFB46D /* b2TimeOfImpact.cpp */,
+ 49132F8D13725D1000DFB46D /* b2TimeOfImpact.h */,
+ 49132F8E13725D1000DFB46D /* Shapes */,
+ );
+ path = Collision;
+ sourceTree = "<group>";
+ };
+ 49132F8E13725D1000DFB46D /* Shapes */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F8F13725D1000DFB46D /* b2CircleShape.cpp */,
+ 49132F9013725D1000DFB46D /* b2CircleShape.h */,
+ 49132F9113725D1000DFB46D /* b2PolygonShape.cpp */,
+ 49132F9213725D1000DFB46D /* b2PolygonShape.h */,
+ 49132F9313725D1000DFB46D /* b2Shape.h */,
+ );
+ path = Shapes;
+ sourceTree = "<group>";
+ };
+ 49132F9413725D1000DFB46D /* Common */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F9513725D1000DFB46D /* b2BlockAllocator.cpp */,
+ 49132F9613725D1000DFB46D /* b2BlockAllocator.h */,
+ 49132F9713725D1000DFB46D /* b2Math.cpp */,
+ 49132F9813725D1000DFB46D /* b2Math.h */,
+ 49132F9913725D1000DFB46D /* b2Settings.cpp */,
+ 49132F9A13725D1000DFB46D /* b2Settings.h */,
+ 49132F9B13725D1000DFB46D /* b2StackAllocator.cpp */,
+ 49132F9C13725D1000DFB46D /* b2StackAllocator.h */,
+ );
+ path = Common;
+ sourceTree = "<group>";
+ };
+ 49132F9D13725D1000DFB46D /* Dynamics */ = {
+ isa = PBXGroup;
+ children = (
+ 49132F9E13725D1000DFB46D /* b2Body.cpp */,
+ 49132F9F13725D1000DFB46D /* b2Body.h */,
+ 49132FA013725D1000DFB46D /* b2ContactManager.cpp */,
+ 49132FA113725D1000DFB46D /* b2ContactManager.h */,
+ 49132FA213725D1000DFB46D /* b2Fixture.cpp */,
+ 49132FA313725D1000DFB46D /* b2Fixture.h */,
+ 49132FA413725D1000DFB46D /* b2Island.cpp */,
+ 49132FA513725D1000DFB46D /* b2Island.h */,
+ 49132FA613725D1000DFB46D /* b2TimeStep.h */,
+ 49132FA713725D1000DFB46D /* b2World.cpp */,
+ 49132FA813725D1000DFB46D /* b2World.h */,
+ 49132FA913725D1000DFB46D /* b2WorldCallbacks.cpp */,
+ 49132FAA13725D1000DFB46D /* b2WorldCallbacks.h */,
+ 49132FAB13725D1000DFB46D /* Contacts */,
+ 49132FB813725D1000DFB46D /* Joints */,
+ );
+ path = Dynamics;
+ sourceTree = "<group>";
+ };
+ 49132FAB13725D1000DFB46D /* Contacts */ = {
+ isa = PBXGroup;
+ children = (
+ 49132FAC13725D1000DFB46D /* b2CircleContact.cpp */,
+ 49132FAD13725D1000DFB46D /* b2CircleContact.h */,
+ 49132FAE13725D1000DFB46D /* b2Contact.cpp */,
+ 49132FAF13725D1000DFB46D /* b2Contact.h */,
+ 49132FB013725D1000DFB46D /* b2ContactSolver.cpp */,
+ 49132FB113725D1000DFB46D /* b2ContactSolver.h */,
+ 49132FB213725D1000DFB46D /* b2PolygonAndCircleContact.cpp */,
+ 49132FB313725D1000DFB46D /* b2PolygonAndCircleContact.h */,
+ 49132FB413725D1000DFB46D /* b2PolygonContact.cpp */,
+ 49132FB513725D1000DFB46D /* b2PolygonContact.h */,
+ 49132FB613725D1000DFB46D /* b2TOISolver.cpp */,
+ 49132FB713725D1000DFB46D /* b2TOISolver.h */,
+ );
+ path = Contacts;
+ sourceTree = "<group>";
+ };
+ 49132FB813725D1000DFB46D /* Joints */ = {
+ isa = PBXGroup;
+ children = (
+ 49132FB913725D1000DFB46D /* b2DistanceJoint.cpp */,
+ 49132FBA13725D1000DFB46D /* b2DistanceJoint.h */,
+ 49132FBB13725D1000DFB46D /* b2FrictionJoint.cpp */,
+ 49132FBC13725D1000DFB46D /* b2FrictionJoint.h */,
+ 49132FBD13725D1000DFB46D /* b2GearJoint.cpp */,
+ 49132FBE13725D1000DFB46D /* b2GearJoint.h */,
+ 49132FBF13725D1000DFB46D /* b2Joint.cpp */,
+ 49132FC013725D1000DFB46D /* b2Joint.h */,
+ 49132FC113725D1000DFB46D /* b2LineJoint.cpp */,
+ 49132FC213725D1000DFB46D /* b2LineJoint.h */,
+ 49132FC313725D1000DFB46D /* b2MouseJoint.cpp */,
+ 49132FC413725D1000DFB46D /* b2MouseJoint.h */,
+ 49132FC513725D1000DFB46D /* b2PrismaticJoint.cpp */,
+ 49132FC613725D1000DFB46D /* b2PrismaticJoint.h */,
+ 49132FC713725D1000DFB46D /* b2PulleyJoint.cpp */,
+ 49132FC813725D1000DFB46D /* b2PulleyJoint.h */,
+ 49132FC913725D1000DFB46D /* b2RevoluteJoint.cpp */,
+ 49132FCA13725D1000DFB46D /* b2RevoluteJoint.h */,
+ 49132FCB13725D1000DFB46D /* b2WeldJoint.cpp */,
+ 49132FCC13725D1000DFB46D /* b2WeldJoint.h */,
+ );
+ path = Joints;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 49132F6F13725CDD00DFB46D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 49132FCD13725D1000DFB46D /* Box2D.h in Headers */,
+ 49132FCF13725D1000DFB46D /* b2BroadPhase.h in Headers */,
+ 49132FD313725D1000DFB46D /* b2Collision.h in Headers */,
+ 49132FD513725D1000DFB46D /* b2Distance.h in Headers */,
+ 49132FD713725D1000DFB46D /* b2DynamicTree.h in Headers */,
+ 49132FD913725D1000DFB46D /* b2TimeOfImpact.h in Headers */,
+ 49132FDB13725D1000DFB46D /* b2CircleShape.h in Headers */,
+ 49132FDD13725D1000DFB46D /* b2PolygonShape.h in Headers */,
+ 49132FDE13725D1000DFB46D /* b2Shape.h in Headers */,
+ 49132FE013725D1000DFB46D /* b2BlockAllocator.h in Headers */,
+ 49132FE213725D1000DFB46D /* b2Math.h in Headers */,
+ 49132FE413725D1000DFB46D /* b2Settings.h in Headers */,
+ 49132FE613725D1000DFB46D /* b2StackAllocator.h in Headers */,
+ 49132FE813725D1000DFB46D /* b2Body.h in Headers */,
+ 49132FEA13725D1000DFB46D /* b2ContactManager.h in Headers */,
+ 49132FEC13725D1000DFB46D /* b2Fixture.h in Headers */,
+ 49132FEE13725D1000DFB46D /* b2Island.h in Headers */,
+ 49132FEF13725D1000DFB46D /* b2TimeStep.h in Headers */,
+ 49132FF113725D1000DFB46D /* b2World.h in Headers */,
+ 49132FF313725D1000DFB46D /* b2WorldCallbacks.h in Headers */,
+ 49132FF513725D1000DFB46D /* b2CircleContact.h in Headers */,
+ 49132FF713725D1000DFB46D /* b2Contact.h in Headers */,
+ 49132FF913725D1000DFB46D /* b2ContactSolver.h in Headers */,
+ 49132FFB13725D1000DFB46D /* b2PolygonAndCircleContact.h in Headers */,
+ 49132FFD13725D1000DFB46D /* b2PolygonContact.h in Headers */,
+ 49132FFF13725D1000DFB46D /* b2TOISolver.h in Headers */,
+ 4913300113725D1000DFB46D /* b2DistanceJoint.h in Headers */,
+ 4913300313725D1000DFB46D /* b2FrictionJoint.h in Headers */,
+ 4913300513725D1000DFB46D /* b2GearJoint.h in Headers */,
+ 4913300713725D1000DFB46D /* b2Joint.h in Headers */,
+ 4913300913725D1000DFB46D /* b2LineJoint.h in Headers */,
+ 4913300B13725D1000DFB46D /* b2MouseJoint.h in Headers */,
+ 4913300D13725D1000DFB46D /* b2PrismaticJoint.h in Headers */,
+ 4913300F13725D1000DFB46D /* b2PulleyJoint.h in Headers */,
+ 4913301113725D1000DFB46D /* b2RevoluteJoint.h in Headers */,
+ 4913301313725D1000DFB46D /* b2WeldJoint.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 49132F7013725CDD00DFB46D /* Box2D */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 49132F7C13725CDD00DFB46D /* Build configuration list for PBXNativeTarget "Box2D" */;
+ buildPhases = (
+ 49132F6D13725CDD00DFB46D /* Sources */,
+ 49132F6E13725CDD00DFB46D /* Frameworks */,
+ 49132F6F13725CDD00DFB46D /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Box2D;
+ productName = Box2D;
+ productReference = 49132F7113725CDD00DFB46D /* Box2D.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 49132EDF13725A9600DFB46D /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 49132EE213725A9600DFB46D /* Build configuration list for PBXProject "box2d" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 49132EDD13725A9600DFB46D;
+ productRefGroup = 49132EDD13725A9600DFB46D;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 49132F7013725CDD00DFB46D /* Box2D */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 49132F6D13725CDD00DFB46D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 49132FCE13725D1000DFB46D /* b2BroadPhase.cpp in Sources */,
+ 49132FD013725D1000DFB46D /* b2CollideCircle.cpp in Sources */,
+ 49132FD113725D1000DFB46D /* b2CollidePolygon.cpp in Sources */,
+ 49132FD213725D1000DFB46D /* b2Collision.cpp in Sources */,
+ 49132FD413725D1000DFB46D /* b2Distance.cpp in Sources */,
+ 49132FD613725D1000DFB46D /* b2DynamicTree.cpp in Sources */,
+ 49132FD813725D1000DFB46D /* b2TimeOfImpact.cpp in Sources */,
+ 49132FDA13725D1000DFB46D /* b2CircleShape.cpp in Sources */,
+ 49132FDC13725D1000DFB46D /* b2PolygonShape.cpp in Sources */,
+ 49132FDF13725D1000DFB46D /* b2BlockAllocator.cpp in Sources */,
+ 49132FE113725D1000DFB46D /* b2Math.cpp in Sources */,
+ 49132FE313725D1000DFB46D /* b2Settings.cpp in Sources */,
+ 49132FE513725D1000DFB46D /* b2StackAllocator.cpp in Sources */,
+ 49132FE713725D1000DFB46D /* b2Body.cpp in Sources */,
+ 49132FE913725D1000DFB46D /* b2ContactManager.cpp in Sources */,
+ 49132FEB13725D1000DFB46D /* b2Fixture.cpp in Sources */,
+ 49132FED13725D1000DFB46D /* b2Island.cpp in Sources */,
+ 49132FF013725D1000DFB46D /* b2World.cpp in Sources */,
+ 49132FF213725D1000DFB46D /* b2WorldCallbacks.cpp in Sources */,
+ 49132FF413725D1000DFB46D /* b2CircleContact.cpp in Sources */,
+ 49132FF613725D1000DFB46D /* b2Contact.cpp in Sources */,
+ 49132FF813725D1000DFB46D /* b2ContactSolver.cpp in Sources */,
+ 49132FFA13725D1000DFB46D /* b2PolygonAndCircleContact.cpp in Sources */,
+ 49132FFC13725D1000DFB46D /* b2PolygonContact.cpp in Sources */,
+ 49132FFE13725D1000DFB46D /* b2TOISolver.cpp in Sources */,
+ 4913300013725D1000DFB46D /* b2DistanceJoint.cpp in Sources */,
+ 4913300213725D1000DFB46D /* b2FrictionJoint.cpp in Sources */,
+ 4913300413725D1000DFB46D /* b2GearJoint.cpp in Sources */,
+ 4913300613725D1000DFB46D /* b2Joint.cpp in Sources */,
+ 4913300813725D1000DFB46D /* b2LineJoint.cpp in Sources */,
+ 4913300A13725D1000DFB46D /* b2MouseJoint.cpp in Sources */,
+ 4913300C13725D1000DFB46D /* b2PrismaticJoint.cpp in Sources */,
+ 4913300E13725D1000DFB46D /* b2PulleyJoint.cpp in Sources */,
+ 4913301013725D1000DFB46D /* b2RevoluteJoint.cpp in Sources */,
+ 4913301213725D1000DFB46D /* b2WeldJoint.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 49132EE413725A9600DFB46D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 49132EE513725A9600DFB46D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 49132F7D13725CDD00DFB46D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.6;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx;
+ SKIP_INSTALL = YES;
+ USER_HEADER_SEARCH_PATHS = "./src/**";
+ };
+ name = Debug;
+ };
+ 49132F7E13725CDD00DFB46D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_VERSION = 4.2;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.6;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx;
+ SKIP_INSTALL = YES;
+ USER_HEADER_SEARCH_PATHS = "./src/**";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 49132EE213725A9600DFB46D /* Build configuration list for PBXProject "box2d" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 49132EE413725A9600DFB46D /* Debug */,
+ 49132EE513725A9600DFB46D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 49132F7C13725CDD00DFB46D /* Build configuration list for PBXNativeTarget "Box2D" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 49132F7D13725CDD00DFB46D /* Debug */,
+ 49132F7E13725CDD00DFB46D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 49132EDF13725A9600DFB46D /* Project object */;
+}
--- /dev/null
+//
+// Prefix header for all source files of the 'Box2D' target in the 'Box2D' project
+//
+
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#endif
--- /dev/null
+//
+// Box2DAppDelegate.h
+// Box2D
+//
+// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+//
+
+#import <UIKit/UIKit.h>
+#import "TestEntriesViewController.h"
+#import "Delegates.h"
+
+@class Box2DView;
+
+@interface Box2DAppDelegate : NSObject <UIApplicationDelegate,TestSelectDelegate> {
+ UIWindow *window;
+ Box2DView *glView;
+ TestEntriesViewController *testEntriesView;
+}
+
+@property (nonatomic, retain) IBOutlet UIWindow *window;
+@property (nonatomic, retain) IBOutlet Box2DView *glView;
+
+@end
+
--- /dev/null
+//
+// Box2DAppDelegate.m
+// Box2D
+//
+// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+//
+
+#import <UIKit/UIKit.h>
+#import "Box2DAppDelegate.h"
+#import "Box2DView.h"
+
+@implementation Box2DAppDelegate
+
+@synthesize window;
+@synthesize glView;
+
+- (void)applicationDidFinishLaunching:(UIApplication *)application {
+ [application setStatusBarHidden:true];
+
+ [glView removeFromSuperview];
+
+ glView.animationInterval = 1.0 / 60.0;
+
+ testEntriesView=[[TestEntriesViewController alloc] initWithStyle:UITableViewStylePlain];
+ [testEntriesView setDelegate:self];
+ [glView setDelegate:self];
+
+ [window addSubview:[testEntriesView view]];
+}
+
+-(void) selectTest:(int) testIndex
+{
+ [[testEntriesView view] removeFromSuperview];
+ [window addSubview:glView];
+ [glView startAnimation];
+ [glView selectTestEntry:testIndex];
+}
+
+-(void) leaveTest
+{
+ [glView stopAnimation];
+ [glView removeFromSuperview];
+ [window addSubview:[testEntriesView view]];
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+ glView.animationInterval = 1.0 / 5.0;
+}
+
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ glView.animationInterval = 1.0 / 60.0;
+}
+
+
+- (void)dealloc {
+ [window release];
+ [glView release];
+ [super dealloc];
+}
+
+@end
--- /dev/null
+//
+// Box2DView.h
+// Box2D OpenGL View
+//
+// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+//
+
+
+#import <UIKit/UIKit.h>
+#import <OpenGLES/EAGL.h>
+#import <OpenGLES/ES1/gl.h>
+#import <OpenGLES/ES1/glext.h>
+
+#import "iPhoneTest.h"
+#import "Delegates.h"
+
+/*
+This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
+The view content is basically an EAGL surface you render your OpenGL scene into.
+Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
+*/
+@interface Box2DView : UIView <UIAccelerometerDelegate> {
+
+@private
+ /* The pixel dimensions of the backbuffer */
+ GLint backingWidth;
+ GLint backingHeight;
+
+ EAGLContext *context;
+
+ /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
+ GLuint viewRenderbuffer, viewFramebuffer;
+
+ /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
+ GLuint depthRenderbuffer;
+
+ NSTimer *animationTimer;
+ NSTimeInterval animationInterval;
+
+ TestEntry* entry;
+ Test* test;
+
+ // Position offset and scale
+ float sceneScale;
+ CGPoint positionOffset;
+ CGPoint lastWorldTouch;
+ CGPoint lastScreenTouch;
+
+ bool panning;
+ int doubleClickValidCountdown;
+
+ id<TestSelectDelegate> _delegate;
+
+}
+@property(assign) id<TestSelectDelegate> delegate;
+@property NSTimeInterval animationInterval;
+
+- (void)startAnimation;
+- (void)stopAnimation;
+- (void)drawView;
+-(void) selectTestEntry:(int) testIndex;
+
+@end
--- /dev/null
+//
+// Box2DView.mm
+// Box2D OpenGL View
+//
+// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+//
+
+#import <QuartzCore/QuartzCore.h>
+#import <OpenGLES/EAGLDrawable.h>
+
+#import "Box2DView.h"
+
+#define USE_DEPTH_BUFFER 0
+#define kAccelerometerFrequency 30
+#define FRAMES_BETWEEN_PRESSES_FOR_DOUBLE_CLICK 10
+
+Settings settings;
+
+// A class extension to declare private methods
+@interface Box2DView ()
+
+@property (nonatomic, retain) EAGLContext *context;
+@property (nonatomic, assign) NSTimer *animationTimer;
+
+- (BOOL) createFramebuffer;
+- (void) destroyFramebuffer;
+
+@end
+
+
+@implementation Box2DView
+
+@synthesize context;
+@synthesize animationTimer;
+@synthesize animationInterval;
+@synthesize delegate=_delegate;
+
+// You must implement this method
++ (Class)layerClass {
+ return [CAEAGLLayer class];
+}
+
+
+//The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
+- (id)initWithCoder:(NSCoder*)coder {
+
+ if ((self = [super initWithCoder:coder])) {
+ // Get the layer
+ CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
+
+ eaglLayer.opaque = YES;
+ eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
+
+ context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
+
+ if (!context || ![EAGLContext setCurrentContext:context]) {
+ [self release];
+ return nil;
+ }
+
+ animationInterval = 1.0 / 60.0;
+ sceneScale=10.0f;
+ positionOffset=CGPointMake(0, 0);
+ lastWorldTouch=CGPointMake(0, 0);
+
+ [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
+ [[UIAccelerometer sharedAccelerometer] setDelegate:self];
+
+ //[self setMultipleTouchEnabled:YES];
+ }
+
+
+ return self;
+}
+
+-(void) selectTestEntry:(int) testIndex
+{
+ // Destroy existing scene
+ delete test;
+
+ entry = g_testEntries + testIndex;
+ test = entry->createFcn();
+
+ doubleClickValidCountdown=0;
+
+ sceneScale=10.0f;
+ positionOffset=CGPointMake(0, 0);
+ lastWorldTouch=CGPointMake(0, 0);
+}
+
+
+
+- (void)drawView {
+
+
+
+ if (doubleClickValidCountdown>0) doubleClickValidCountdown--;
+
+ [EAGLContext setCurrentContext:context];
+
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+ glViewport(0, 0, backingWidth, backingHeight);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glOrthof(-sceneScale, sceneScale, -sceneScale*1.5f, sceneScale*1.5f, -1.0f, 1.0f);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(positionOffset.x, positionOffset.y,0);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ test->Step(&settings);
+
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+ [context presentRenderbuffer:GL_RENDERBUFFER_OES];
+}
+
+
+- (void)layoutSubviews {
+ [EAGLContext setCurrentContext:context];
+ [self destroyFramebuffer];
+ [self createFramebuffer];
+ [self drawView];
+}
+
+
+- (BOOL)createFramebuffer {
+
+ glGenFramebuffersOES(1, &viewFramebuffer);
+ glGenRenderbuffersOES(1, &viewRenderbuffer);
+
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+ [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
+
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+
+ if (USE_DEPTH_BUFFER) {
+ glGenRenderbuffersOES(1, &depthRenderbuffer);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
+ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
+ }
+
+ if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
+ NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
+ return NO;
+ }
+
+ return YES;
+}
+
+
+- (void)destroyFramebuffer {
+
+ glDeleteFramebuffersOES(1, &viewFramebuffer);
+ viewFramebuffer = 0;
+ glDeleteRenderbuffersOES(1, &viewRenderbuffer);
+ viewRenderbuffer = 0;
+
+ if(depthRenderbuffer) {
+ glDeleteRenderbuffersOES(1, &depthRenderbuffer);
+ depthRenderbuffer = 0;
+ }
+}
+
+
+- (void)startAnimation {
+ self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
+}
+
+
+- (void)stopAnimation {
+ self.animationTimer = nil;
+}
+
+
+- (void)setAnimationTimer:(NSTimer *)newTimer {
+ [animationTimer invalidate];
+ animationTimer = newTimer;
+}
+
+
+- (void)setAnimationInterval:(NSTimeInterval)interval {
+
+ animationInterval = interval;
+ if (animationTimer) {
+ [self stopAnimation];
+ [self startAnimation];
+ }
+}
+
+
+- (void)dealloc {
+
+ [self stopAnimation];
+
+ if ([EAGLContext currentContext] == context) {
+ [EAGLContext setCurrentContext:nil];
+ }
+
+ [context release];
+ [super dealloc];
+}
+
+-(CGPoint) screenSpaceToWorldSpace:(CGPoint) screenLocation
+{
+ screenLocation.x-=160;
+ screenLocation.y-=240;
+ screenLocation.x/=160;
+ screenLocation.y/=160;
+ screenLocation.x*=sceneScale;
+ screenLocation.y*=-sceneScale;
+
+ screenLocation.x-=positionOffset.x;
+ screenLocation.y-=positionOffset.y;
+ return screenLocation;
+}
+
+- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
+{
+
+ if (doubleClickValidCountdown>0)
+ {
+ [_delegate leaveTest];
+ return;
+ }
+
+ doubleClickValidCountdown=FRAMES_BETWEEN_PRESSES_FOR_DOUBLE_CLICK;
+
+
+ panning=false;
+ for (UITouch *touch in touches)
+ {
+ CGPoint touchLocation=[touch locationInView:self];
+ CGPoint worldPosition=[self screenSpaceToWorldSpace:touchLocation];
+ //printf("Screen touched %f,%f -> %f,%f\n",touchLocation.x,touchLocation.y,worldPosition.x,worldPosition.y);
+ lastScreenTouch=touchLocation;
+ lastWorldTouch=worldPosition;
+ b2Vec2 p = b2Vec2(lastWorldTouch.x,lastWorldTouch.y);
+ test->MouseDown(p);
+ //test->ShiftMouseDown(p);
+
+ if (!test->m_mouseJoint) panning=true;
+ }
+}
+
+- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
+{
+ for (UITouch *touch in touches)
+ {
+ CGPoint touchLocation=[touch locationInView:self];
+ CGPoint worldPosition=[self screenSpaceToWorldSpace:touchLocation];
+ //printf("Screen touched %f,%f -> %f,%f\n",touchLocation.x,touchLocation.y,worldPosition.x,worldPosition.y);
+
+
+ CGPoint screenDistanceMoved=CGPointMake(touchLocation.x-lastScreenTouch.x,touchLocation.y-lastScreenTouch.y);
+ if (panning)
+ {
+ screenDistanceMoved.x/=160;
+ screenDistanceMoved.y/=160;
+ screenDistanceMoved.x*=sceneScale;
+ screenDistanceMoved.y*=-sceneScale;
+ positionOffset.x+=screenDistanceMoved.x;
+ positionOffset.y+=screenDistanceMoved.y;
+ }
+
+ lastScreenTouch=touchLocation;
+ lastWorldTouch=worldPosition;
+ test->MouseMove(b2Vec2(lastWorldTouch.x,lastWorldTouch.y));
+
+ }
+}
+- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
+{
+ test->MouseUp(b2Vec2(lastWorldTouch.x,lastWorldTouch.y));
+}
+
+- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
+{
+ // Only run for valid values
+ if (acceleration.y!=0 && acceleration.x!=0)
+ {
+ if (test) test->SetGravity(acceleration.x,acceleration.y);
+ }
+}
+
+@end
--- /dev/null
+/*
+ * Delegates.h
+ * Box2D
+ *
+ * Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+ *
+ *
+ */
+
+@protocol TestSelectDelegate <NSObject>
+ -(void) selectTest:(int) testIndex;
+ -(void) leaveTest;
+
+@end
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef RENDER_H
+#define RENDER_H
+
+#import <UIKit/UIKit.h>
+#import <OpenGLES/EAGL.h>
+#import <OpenGLES/ES1/gl.h>
+#import <OpenGLES/ES1/glext.h>
+
+#include <Box2D/Box2D.h>
+
+struct b2AABB;
+
+// This class implements debug drawing callbacks that are invoked
+// inside b2World::Step.
+class GLESDebugDraw : public b2Draw
+{
+public:
+ void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
+
+ void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
+
+ void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color);
+
+ void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color);
+
+ void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
+
+ void DrawTransform(const b2Transform& xf);
+
+ void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color);
+
+ void DrawString(int x, int y, const char* string, ...);
+
+ void DrawAABB(b2AABB* aabb, const b2Color& color);
+};
+
+
+#endif
--- /dev/null
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "GLES-Render.h"
+
+
+#include <cstdio>
+#include <cstdarg>
+
+#include <cstring>
+
+void GLESDebugDraw::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
+{
+ glColor4f(color.r, color.g, color.b,1);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
+}
+
+void GLESDebugDraw::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
+{
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+
+ glColor4f(color.r, color.g, color.b,0.5f);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
+
+ glColor4f(color.r, color.g, color.b,1);
+ glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
+}
+
+void GLESDebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
+{
+ const float32 k_segments = 16.0f;
+ int vertexCount=16;
+ const float32 k_increment = 2.0f * b2_pi / k_segments;
+ float32 theta = 0.0f;
+
+ GLfloat glVertices[vertexCount*2];
+ for (int32 i = 0; i < k_segments; ++i)
+ {
+ b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
+ glVertices[i*2]=v.x;
+ glVertices[i*2+1]=v.y;
+ theta += k_increment;
+ }
+
+ glColor4f(color.r, color.g, color.b,1);
+ glVertexPointer(2, GL_FLOAT, 0, glVertices);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
+}
+
+void GLESDebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
+{
+ const float32 k_segments = 16.0f;
+ int vertexCount=16;
+ const float32 k_increment = 2.0f * b2_pi / k_segments;
+ float32 theta = 0.0f;
+
+ GLfloat glVertices[vertexCount*2];
+ for (int32 i = 0; i < k_segments; ++i)
+ {
+ b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
+ glVertices[i*2]=v.x;
+ glVertices[i*2+1]=v.y;
+ theta += k_increment;
+ }
+
+ glColor4f(color.r, color.g, color.b,0.5f);
+ glVertexPointer(2, GL_FLOAT, 0, glVertices);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
+ glColor4f(color.r, color.g, color.b,1);
+ glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
+
+ // Draw the axis line
+ DrawSegment(center,center+radius*axis,color);
+}
+
+void GLESDebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
+{
+ glColor4f(color.r, color.g, color.b,1);
+ GLfloat glVertices[] = {
+ p1.x,p1.y,p2.x,p2.y
+ };
+ glVertexPointer(2, GL_FLOAT, 0, glVertices);
+ glDrawArrays(GL_LINES, 0, 2);
+}
+
+void GLESDebugDraw::DrawTransform(const b2Transform& xf)
+{
+ b2Vec2 p1 = xf.position, p2;
+ const float32 k_axisScale = 0.4f;
+
+ p2 = p1 + k_axisScale * xf.R.col1;
+ DrawSegment(p1,p2,b2Color(1,0,0));
+
+ p2 = p1 + k_axisScale * xf.R.col2;
+ DrawSegment(p1,p2,b2Color(0,1,0));
+}
+
+void GLESDebugDraw::DrawPoint(const b2Vec2& p, float32 size, const b2Color& color)
+{
+ glColor4f(color.r, color.g, color.b,1);
+ glPointSize(size);
+ GLfloat glVertices[] = {
+ p.x,p.y
+ };
+ glVertexPointer(2, GL_FLOAT, 0, glVertices);
+ glDrawArrays(GL_POINTS, 0, 1);
+ glPointSize(1.0f);
+}
+
+void GLESDebugDraw::DrawString(int x, int y, const char *string, ...)
+{
+
+ /* Unsupported as yet. Could replace with bitmap font renderer at a later date */
+}
+
+void GLESDebugDraw::DrawAABB(b2AABB* aabb, const b2Color& c)
+{
+
+ glColor4f(c.r, c.g, c.b,1);
+
+ GLfloat glVertices[] = {
+ aabb->lowerBound.x, aabb->lowerBound.y,
+ aabb->upperBound.x, aabb->lowerBound.y,
+ aabb->upperBound.x, aabb->upperBound.y,
+ aabb->lowerBound.x, aabb->upperBound.y
+ };
+ glVertexPointer(2, GL_FLOAT, 0, glVertices);
+ glDrawArrays(GL_LINE_LOOP, 0, 8);
+
+}
--- /dev/null
+//
+// TestEntriesViewController.h
+// Box2D
+//
+// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+//
+
+#import <UIKit/UIKit.h>
+#import "iPhoneTest.h"
+#import "Delegates.h"
+
+@interface TestEntriesViewController : UITableViewController {
+ int32 testCount;
+ id<TestSelectDelegate> _delegate;
+}
+
+@property(assign) id<TestSelectDelegate> delegate;
+
+@end
--- /dev/null
+//
+// TestEntriesViewController.m
+// Box2D
+//
+// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+//
+
+#import "TestEntriesViewController.h"
+
+
+@implementation TestEntriesViewController
+
+@synthesize delegate=_delegate;
+
+- (id)initWithStyle:(UITableViewStyle)style {
+ if (self = [super initWithStyle:style]) {
+ testCount = 0;
+ TestEntry* e = g_testEntries;
+ while (e->createFcn)
+ {
+ ++testCount;
+ ++e;
+ }
+ }
+ return self;
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
+ // Release anything that's not essential, such as cached data
+}
+
+#pragma mark Table view methods
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+ return 1;
+}
+
+
+// Customize the number of rows in the table view.
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ return testCount;
+}
+
+
+// Customize the appearance of table view cells.
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+
+ static NSString *CellIdentifier = @"Cell";
+
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (cell == nil) {
+ cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
+ }
+
+ // Set up the cell...
+ TestEntry* e = g_testEntries;
+ e+=indexPath.row;
+
+ cell.textLabel.text = [NSString stringWithUTF8String:e->name];
+ return cell;
+}
+
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ [_delegate selectTest:indexPath.row];
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+
+@end
+
--- /dev/null
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+#ifndef TEST_H
+#define TEST_H
+
+#import <UIKit/UIKit.h>
+#include <Box2D/Box2D.h>
+#include "GLES-Render.h"
+
+#include <cstdlib>
+
+class Test;
+struct Settings;
+
+typedef Test* TestCreateFcn();
+
+#define RAND_LIMIT 32767
+
+/// Random number in range [-1,1]
+inline float32 RandomFloat()
+{
+ float32 r = (float32)(rand() & (RAND_LIMIT));
+ r /= RAND_LIMIT;
+ r = 2.0f * r - 1.0f;
+ return r;
+}
+
+/// Random floating point number in range [lo, hi]
+inline float32 RandomFloat(float32 lo, float32 hi)
+{
+ float32 r = (float32)(rand() & (RAND_LIMIT));
+ r /= RAND_LIMIT;
+ r = (hi - lo) * r + lo;
+ return r;
+}
+
+/// Test settings. Some can be controlled in the GUI.
+struct Settings
+{
+ Settings() :
+ viewCenter(0.0f, 20.0f),
+ hz(60.0f),
+ velocityIterations(8),
+ positionIterations(3),
+ drawShapes(1),
+ drawJoints(1),
+ drawAABBs(0),
+ drawPairs(0),
+ drawContactPoints(0),
+ drawContactNormals(0),
+ drawContactForces(0),
+ drawFrictionForces(0),
+ drawCOMs(0),
+ drawStats(0),
+ enableWarmStarting(1),
+ enableContinuous(1),
+ enableSubStepping(0),
+ pause(0),
+ singleStep(0)
+ {}
+
+ b2Vec2 viewCenter;
+ float32 hz;
+ int32 velocityIterations;
+ int32 positionIterations;
+ int32 drawShapes;
+ int32 drawJoints;
+ int32 drawAABBs;
+ int32 drawPairs;
+ int32 drawContactPoints;
+ int32 drawContactNormals;
+ int32 drawContactForces;
+ int32 drawFrictionForces;
+ int32 drawCOMs;
+ int32 drawStats;
+ int32 enableWarmStarting;
+ int32 enableContinuous;
+ int32 enableSubStepping;
+ int32 pause;
+ int32 singleStep;
+};
+
+struct TestEntry
+{
+ const char *name;
+ TestCreateFcn *createFcn;
+};
+
+extern TestEntry g_testEntries[];
+// This is called when a joint in the world is implicitly destroyed
+// because an attached body is destroyed. This gives us a chance to
+// nullify the mouse joint.
+class DestructionListener : public b2DestructionListener
+ {
+ public:
+ void SayGoodbye(b2Fixture* fixture) { B2_NOT_USED(fixture); }
+ void SayGoodbye(b2Joint* joint);
+
+ Test* test;
+ };
+
+const int32 k_maxContactPoints = 2048;
+
+struct ContactPoint
+{
+ b2Fixture* fixtureA;
+ b2Fixture* fixtureB;
+ b2Vec2 normal;
+ b2Vec2 position;
+ b2PointState state;
+};
+
+class Test : public b2ContactListener
+ {
+ public:
+
+ Test();
+ virtual ~Test();
+
+ void SetGravity(float x,float y);
+ void SetTextLine(int32 line) { m_textLine = line; }
+ void DrawTitle(int x, int y, const char *string);
+ virtual void Step(Settings* settings);
+ virtual void Keyboard(unsigned char key) { B2_NOT_USED(key); }
+ void ShiftMouseDown(const b2Vec2& p);
+ virtual void MouseDown(const b2Vec2& p);
+ virtual void MouseUp(const b2Vec2& p);
+ void MouseMove(const b2Vec2& p);
+ void LaunchBomb();
+ void LaunchBomb(const b2Vec2& position, const b2Vec2& velocity);
+
+ void SpawnBomb(const b2Vec2& worldPt);
+ void CompleteBombSpawn(const b2Vec2& p);
+
+ // Let derived tests know that a joint was destroyed.
+ virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); }
+
+ // Callbacks for derived classes.
+ virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
+ virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
+ virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
+ virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
+ {
+ B2_NOT_USED(contact);
+ B2_NOT_USED(impulse);
+ }
+
+ protected:
+ friend class DestructionListener;
+ friend class BoundaryListener;
+ friend class ContactListener;
+
+ b2Body* m_groundBody;
+ b2AABB m_worldAABB;
+ ContactPoint m_points[k_maxContactPoints];
+ int32 m_pointCount;
+ DestructionListener m_destructionListener;
+ GLESDebugDraw m_debugDraw;
+ int32 m_textLine;
+ b2World* m_world;
+ b2Body* m_bomb;
+ b2MouseJoint* m_mouseJoint;
+ b2Vec2 m_bombSpawnPoint;
+ bool m_bombSpawning;
+ b2Vec2 m_mouseWorld;
+ int32 m_stepCount;
+ };
+
+#endif
--- /dev/null
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+*
+* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "iPhoneTest.h"
+#include "GLES-Render.h"
+
+#include <cstdio>
+
+void DestructionListener::SayGoodbye(b2Joint* joint)
+{
+ if (test->m_mouseJoint == joint)
+ {
+ test->m_mouseJoint = NULL;
+ }
+ else
+ {
+ test->JointDestroyed(joint);
+ }
+}
+
+Test::Test()
+: m_debugDraw()
+{
+ b2Vec2 gravity;
+ gravity.Set(0.0f, -10.0f);
+ bool doSleep = true;
+ m_world = new b2World(gravity, doSleep);
+ m_bomb = NULL;
+ m_textLine = 30;
+ m_mouseJoint = NULL;
+ m_pointCount = 0;
+
+ m_destructionListener.test = this;
+ m_world->SetDestructionListener(&m_destructionListener);
+ m_world->SetContactListener(this);
+ m_world->SetDebugDraw(&m_debugDraw);
+
+ m_bombSpawning = false;
+
+ m_stepCount = 0;
+
+ b2BodyDef bodyDef;
+ m_groundBody = m_world->CreateBody(&bodyDef);
+}
+
+Test::~Test()
+{
+ // By deleting the world, we delete the bomb, mouse joint, etc.
+ delete m_world;
+ m_world = NULL;
+
+}
+
+void Test::SetGravity( float x, float y)
+{
+ float tVectorLength=sqrt(x*x+y*y);
+ float newGravityX=9.81f*x/tVectorLength;
+ float newGravityY=9.81f*y/tVectorLength;
+ m_world->SetGravity(b2Vec2(newGravityX,newGravityY));
+}
+
+void Test::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
+{
+ const b2Manifold* manifold = contact->GetManifold();
+
+ if (manifold->pointCount == 0)
+ {
+ return;
+ }
+
+ b2Fixture* fixtureA = contact->GetFixtureA();
+ b2Fixture* fixtureB = contact->GetFixtureB();
+
+ b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints];
+ b2GetPointStates(state1, state2, oldManifold, manifold);
+
+ b2WorldManifold worldManifold;
+ contact->GetWorldManifold(&worldManifold);
+
+ for (int32 i = 0; i < manifold->pointCount && m_pointCount < k_maxContactPoints; ++i)
+ {
+ ContactPoint* cp = m_points + m_pointCount;
+ cp->fixtureA = fixtureA;
+ cp->fixtureB = fixtureB;
+ cp->position = worldManifold.points[i];
+ cp->normal = worldManifold.normal;
+ cp->state = state2[i];
+ ++m_pointCount;
+ }
+}
+
+void Test::DrawTitle(int x, int y, const char *string)
+{
+ m_debugDraw.DrawString(x, y, string);
+}
+
+class QueryCallback : public b2QueryCallback
+{
+public:
+ QueryCallback(const b2Vec2& point)
+ {
+ m_point = point;
+ m_fixture = NULL;
+ }
+
+ bool ReportFixture(b2Fixture* fixture)
+ {
+ b2Body* body = fixture->GetBody();
+ if (body->GetType() == b2_dynamicBody)
+ {
+ bool inside = fixture->TestPoint(m_point);
+ if (inside)
+ {
+ m_fixture = fixture;
+
+ // We are done, terminate the query.
+ return false;
+ }
+ }
+
+ // Continue the query.
+ return true;
+ }
+
+ b2Vec2 m_point;
+ b2Fixture* m_fixture;
+};
+
+void Test::MouseDown(const b2Vec2& p)
+{
+ m_mouseWorld = p;
+
+ if (m_mouseJoint != NULL)
+ {
+ return;
+ }
+
+ // Make a small box.
+ b2AABB aabb;
+ b2Vec2 d;
+ d.Set(0.001f, 0.001f);
+ aabb.lowerBound = p - d;
+ aabb.upperBound = p + d;
+
+ // Query the world for overlapping shapes.
+ QueryCallback callback(p);
+ m_world->QueryAABB(&callback, aabb);
+
+ if (callback.m_fixture)
+ {
+ b2Body* body = callback.m_fixture->GetBody();
+ b2MouseJointDef md;
+ md.bodyA = m_groundBody;
+ md.bodyB = body;
+ md.target = p;
+#ifdef TARGET_FLOAT32_IS_FIXED
+ md.maxForce = (body->GetMass() < 16.0)?
+ (1000.0f * body->GetMass()) : float32(16000.0);
+#else
+ md.maxForce = 1000.0f * body->GetMass();
+#endif
+ m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md);
+ body->SetAwake(true);
+ }
+}
+
+void Test::SpawnBomb(const b2Vec2& worldPt)
+{
+ m_bombSpawnPoint = worldPt;
+ m_bombSpawning = true;
+}
+
+void Test::CompleteBombSpawn(const b2Vec2& p)
+{
+ if (m_bombSpawning == false)
+ {
+ return;
+ }
+
+ const float multiplier = 30.0f;
+ b2Vec2 vel = m_bombSpawnPoint - p;
+ vel *= multiplier;
+ LaunchBomb(m_bombSpawnPoint,vel);
+ m_bombSpawning = false;
+}
+
+void Test::ShiftMouseDown(const b2Vec2& p)
+{
+ m_mouseWorld = p;
+
+ if (m_mouseJoint != NULL)
+ {
+ return;
+ }
+
+ SpawnBomb(p);
+}
+
+void Test::MouseUp(const b2Vec2& p)
+{
+ if (m_mouseJoint)
+ {
+ m_world->DestroyJoint(m_mouseJoint);
+ m_mouseJoint = NULL;
+ }
+
+ if (m_bombSpawning)
+ {
+ CompleteBombSpawn(p);
+ }
+}
+
+void Test::MouseMove(const b2Vec2& p)
+{
+ m_mouseWorld = p;
+
+ if (m_mouseJoint)
+ {
+ m_mouseJoint->SetTarget(p);
+ }
+}
+
+void Test::LaunchBomb()
+{
+ b2Vec2 p(RandomFloat(-15.0f, 15.0f), 30.0f);
+ b2Vec2 v = -5.0f * p;
+ LaunchBomb(p, v);
+}
+
+void Test::LaunchBomb(const b2Vec2& position, const b2Vec2& velocity)
+{
+ if (m_bomb)
+ {
+ m_world->DestroyBody(m_bomb);
+ m_bomb = NULL;
+ }
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = position;
+ bd.bullet = true;
+ m_bomb = m_world->CreateBody(&bd);
+ m_bomb->SetLinearVelocity(velocity);
+
+ b2CircleShape circle;
+ circle.m_radius = 0.3f;
+
+ b2FixtureDef fd;
+ fd.shape = &circle;
+ fd.density = 20.0f;
+ fd.restitution = 0.0f;
+
+ b2Vec2 minV = position - b2Vec2(0.3f,0.3f);
+ b2Vec2 maxV = position + b2Vec2(0.3f,0.3f);
+
+ b2AABB aabb;
+ aabb.lowerBound = minV;
+ aabb.upperBound = maxV;
+
+ m_bomb->CreateFixture(&fd);
+}
+
+void Test::Step(Settings* settings)
+{
+ float32 timeStep = settings->hz > 0.0f ? 1.0f / settings->hz : float32(0.0f);
+
+ if (settings->pause)
+ {
+ if (settings->singleStep)
+ {
+ settings->singleStep = 0;
+ }
+ else
+ {
+ timeStep = 0.0f;
+ }
+
+ m_debugDraw.DrawString(5, m_textLine, "****PAUSED****");
+ m_textLine += 15;
+ }
+
+ uint32 flags = 0;
+ flags += settings->drawShapes * b2Draw::e_shapeBit;
+ flags += settings->drawJoints * b2Draw::e_jointBit;
+ flags += settings->drawAABBs * b2Draw::e_aabbBit;
+ flags += settings->drawPairs * b2Draw::e_pairBit;
+ flags += settings->drawCOMs * b2Draw::e_centerOfMassBit;
+ m_debugDraw.SetFlags(flags);
+
+ m_world->SetWarmStarting(settings->enableWarmStarting > 0);
+ m_world->SetContinuousPhysics(settings->enableContinuous > 0);
+ m_world->SetSubStepping(settings->enableSubStepping > 0);
+
+ m_pointCount = 0;
+
+ m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations);
+
+ m_world->DrawDebugData();
+
+ if (timeStep > 0.0f)
+ {
+ ++m_stepCount;
+ }
+
+ if (settings->drawStats)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "bodies/contacts/joints/proxies = %d/%d/%d",
+ m_world->GetBodyCount(), m_world->GetContactCount(), m_world->GetJointCount(), m_world->GetProxyCount());
+ m_textLine += 15;
+ }
+
+ if (m_mouseJoint)
+ {
+ b2Vec2 p1 = m_mouseJoint->GetAnchorB();
+ b2Vec2 p2 = m_mouseJoint->GetTarget();
+
+ glPointSize(4.0f);
+ glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
+ GLbyte verts1[2 * 3] = {
+ p1.x, p1.y, 0.0f,
+ p2.x, p2.y, 0.0f
+ };
+ glVertexPointer(3, GL_BYTE, 0, verts1);
+ glDrawArrays(GL_POINTS, 0, 2);
+ glPointSize(1.0f);
+
+ glColor4f(0.8f, 0.8f, 0.8f, 1.0f);
+ GLbyte verts2[2 * 3] = {
+ p1.x, p1.y, 0.0f,
+ p2.x, p2.y, 0.0f
+ };
+ glVertexPointer(3, GL_BYTE, 0, verts2);
+ glDrawArrays(GL_LINES, 0, 2);
+ }
+
+ if (m_bombSpawning)
+ {
+ glPointSize(4.0f);
+ glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
+ glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
+ GLbyte verts1[1 * 3] = {
+ m_bombSpawnPoint.x, m_bombSpawnPoint.y, 0.0f
+ };
+ glVertexPointer(3, GL_BYTE, 0, verts1);
+ glDrawArrays(GL_POINTS, 0, 1);
+
+ glColor4f(0.8f, 0.8f, 0.8f, 1.0f);
+ GLbyte verts2[2 * 3] = {
+ m_mouseWorld.x, m_mouseWorld.y, 0.0f,
+ m_bombSpawnPoint.x, m_bombSpawnPoint.y, 0.0f
+ };
+ glVertexPointer(3, GL_BYTE, 0, verts2);
+ glDrawArrays(GL_LINES, 0, 2);
+ }
+
+ if (settings->drawContactPoints)
+ {
+ //const float32 k_impulseScale = 0.1f;
+ const float32 k_axisScale = 0.3f;
+
+ for (int32 i = 0; i < m_pointCount; ++i)
+ {
+ ContactPoint* point = m_points + i;
+
+ if (point->state == b2_addState)
+ {
+ // Add
+ m_debugDraw.DrawPoint(point->position, 10.0f, b2Color(0.3f, 0.95f, 0.3f));
+ }
+ else if (point->state == b2_persistState)
+ {
+ // Persist
+ m_debugDraw.DrawPoint(point->position, 5.0f, b2Color(0.3f, 0.3f, 0.95f));
+ }
+
+ if (settings->drawContactNormals == 1)
+ {
+ b2Vec2 p1 = point->position;
+ b2Vec2 p2 = p1 + k_axisScale * point->normal;
+ m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.9f));
+ }
+ else if (settings->drawContactForces == 1)
+ {
+ //b2Vec2 p1 = point->position;
+ //b2Vec2 p2 = p1 + k_forceScale * point->normalForce * point->normal;
+ //DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
+ }
+
+ if (settings->drawFrictionForces == 1)
+ {
+ //b2Vec2 tangent = b2Cross(point->normal, 1.0f);
+ //b2Vec2 p1 = point->position;
+ //b2Vec2 p2 = p1 + k_forceScale * point->tangentForce * tangent;
+ //DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
+ }
+ }
+ }
+}
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include "iPhoneTest.h"\r
+#include <cstring>\r
+using namespace std;\r
+\r
+#include "ApplyForce.h"\r
+#include "BodyTypes.h"\r
+#include "Breakable.h"\r
+#include "Bridge.h"\r
+#include "BulletTest.h"\r
+#include "Cantilever.h"\r
+#include "Car.h"\r
+#include "ContinuousTest.h"\r
+#include "Chain.h"\r
+#include "CharacterCollision.h"\r
+#include "CollisionFiltering.h"\r
+#include "CollisionProcessing.h"\r
+#include "CompoundShapes.h"\r
+#include "Confined.h"\r
+#include "DistanceTest.h"\r
+#include "Dominos.h"\r
+#include "DynamicTreeTest.h"\r
+#include "EdgeShapes.h"\r
+#include "EdgeTest.h"\r
+#include "Gears.h"\r
+#include "OneSidedPlatform.h"\r
+#include "Pinball.h"\r
+#include "PolyCollision.h"\r
+#include "PolyShapes.h"\r
+#include "Prismatic.h"\r
+#include "Pulleys.h"\r
+#include "Pyramid.h"\r
+#include "RayCast.h"\r
+#include "Revolute.h"\r
+#include "Rope.h"\r
+#include "RopeJoint.h"\r
+#include "SensorTest.h"\r
+#include "ShapeEditing.h"\r
+#include "SliderCrank.h"\r
+#include "SphereStack.h"\r
+#include "TheoJansen.h"\r
+#include "Tiles.h"\r
+#include "TimeOfImpact.h"\r
+#include "VaryingFriction.h"\r
+#include "VaryingRestitution.h"\r
+#include "VerticalStack.h"\r
+#include "Web.h"\r
+\r
+TestEntry g_testEntries[] =\r
+{\r
+ {"Pulleys", Pulleys::Create},\r
+ {"SphereStack", SphereStack::Create},\r
+ {"Tiles", Tiles::Create},\r
+ {"Polygon Shapes", PolyShapes::Create},\r
+ {"Rope", Rope::Create},\r
+ {"Web", Web::Create},\r
+ {"Car", Car::Create},\r
+ {"Vertical Stack", VerticalStack::Create},\r
+ {"RopeJoint", RopeJoint::Create},\r
+ {"Character Collision", CharacterCollision::Create},\r
+ {"Edge Test", EdgeTest::Create},\r
+ {"One-Sided Platform", OneSidedPlatform::Create},\r
+ {"Pinball", Pinball::Create},\r
+ {"Bullet Test", BulletTest::Create},\r
+ {"Continuous Test", ContinuousTest::Create},\r
+ {"Time of Impact", TimeOfImpact::Create},\r
+ {"Ray-Cast", RayCast::Create},\r
+ {"Confined", Confined::Create},\r
+ {"Pyramid", Pyramid::Create},\r
+ {"Varying Restitution", VaryingRestitution::Create},\r
+ {"Theo Jansen's Walker", TheoJansen::Create},\r
+ {"Body Types", BodyTypes::Create},\r
+ {"Prismatic", Prismatic::Create},\r
+ {"Edge Shapes", EdgeShapes::Create},\r
+ {"PolyCollision", PolyCollision::Create},\r
+ {"Apply Force", ApplyForce::Create},\r
+ {"Cantilever", Cantilever::Create},\r
+ {"Bridge", Bridge::Create},\r
+ {"Breakable", Breakable::Create},\r
+ {"Chain", Chain::Create},\r
+ {"Collision Filtering", CollisionFiltering::Create},\r
+ {"Collision Processing", CollisionProcessing::Create},\r
+ {"Compound Shapes", CompoundShapes::Create},\r
+ {"Distance Test", DistanceTest::Create},\r
+ {"Dominos", Dominos::Create},\r
+ {"Dynamic Tree", DynamicTreeTest::Create},\r
+ {"Gears", Gears::Create},\r
+ {"Revolute", Revolute::Create},\r
+ {"Sensor Test", SensorTest::Create},\r
+ {"Shape Editing", ShapeEditing::Create},\r
+ {"Slider Crank", SliderCrank::Create},\r
+ {"Varying Friction", VaryingFriction::Create},\r
+ {NULL, NULL}\r
+};\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>NSMainNibFile</key>
+ <string>MainWindow</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.03">
+ <data>
+ <int key="IBDocument.SystemTarget">528</int>
+ <string key="IBDocument.SystemVersion">9G55</string>
+ <string key="IBDocument.InterfaceBuilderVersion">677</string>
+ <string key="IBDocument.AppKitVersion">949.43</string>
+ <string key="IBDocument.HIToolboxVersion">353.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="8"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBProxyObject" id="841351856">
+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+ </object>
+ <object class="IBProxyObject" id="191355593">
+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+ </object>
+ <object class="IBUICustomObject" id="664661524"/>
+ <object class="IBUIWindow" id="380026005">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">1316</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIView" id="773737154">
+ <reference key="NSNextResponder" ref="380026005"/>
+ <int key="NSvFlags">1298</int>
+ <string key="NSFrameSize">{320, 480}</string>
+ <reference key="NSSuperview" ref="380026005"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ <object class="NSColorSpace" key="NSCustomColorSpace">
+ <int key="NSID">2</int>
+ </object>
+ </object>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ </object>
+ </object>
+ <object class="NSPSMatrix" key="NSFrameMatrix"/>
+ <string key="NSFrameSize">{320, 480}</string>
+ <reference key="NSSuperview"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MSAxIDEAA</bytes>
+ </object>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <bool key="IBUIVisibleAtLaunch">YES</bool>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="841351856"/>
+ <reference key="destination" ref="664661524"/>
+ </object>
+ <int key="connectionID">4</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="664661524"/>
+ <reference key="destination" ref="380026005"/>
+ </object>
+ <int key="connectionID">5</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">glView</string>
+ <reference key="source" ref="664661524"/>
+ <reference key="destination" ref="773737154"/>
+ </object>
+ <int key="connectionID">9</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="957960031">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="380026005"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="773737154"/>
+ </object>
+ <reference key="parent" ref="957960031"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="841351856"/>
+ <reference key="parent" ref="957960031"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">3</int>
+ <reference key="object" ref="664661524"/>
+ <reference key="parent" ref="957960031"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">8</int>
+ <reference key="object" ref="773737154"/>
+ <reference key="parent" ref="380026005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="191355593"/>
+ <reference key="parent" ref="957960031"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.CustomClassName</string>
+ <string>-2.CustomClassName</string>
+ <string>2.IBAttributePlaceholdersKey</string>
+ <string>2.IBEditorWindowLastContentRect</string>
+ <string>2.IBPluginDependency</string>
+ <string>3.CustomClassName</string>
+ <string>3.IBPluginDependency</string>
+ <string>8.CustomClassName</string>
+ <string>8.IBPluginDependency</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UIApplication</string>
+ <string>UIResponder</string>
+ <object class="NSMutableDictionary">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <string>{{500, 343}, {320, 480}}</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>Box2DAppDelegate</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>Box2DView</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">9</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">Box2DAppDelegate</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>glView</string>
+ <string>window</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>Box2DView</string>
+ <string>UIWindow</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">Classes/Box2DAppDelegate.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">Box2DView</string>
+ <string key="superclassName">UIView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">Classes/Box2DView.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">Box2D.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
--- /dev/null
+//
+// main.m
+// Box2D
+//
+// Created by Simon Oliver on 14/01/2009.
+// Copyright HandCircus 2009. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+int main(int argc, char *argv[]) {
+
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int retVal = UIApplicationMain(argc, argv, nil, nil);
+ [pool release];
+ return retVal;
+}
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef BOX2D_H\r
+#define BOX2D_H\r
+\r
+/**\r
+\mainpage Box2D API Documentation\r
+\r
+\section intro_sec Getting Started\r
+\r
+For documentation please see http://box2d.org/documentation.html\r
+\r
+For discussion please visit http://box2d.org/forum\r
+*/\r
+\r
+// These include files constitute the main Box2D API\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+\r
+#include <Box2D/Collision/b2BroadPhase.h>\r
+#include <Box2D/Collision/b2Distance.h>\r
+#include <Box2D/Collision/b2DynamicTree.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2WorldCallbacks.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+#include <Box2D/Dynamics/b2World.h>\r
+\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+\r
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2LineJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <new>\r
+\r
+b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const\r
+{\r
+ void* mem = allocator->Allocate(sizeof(b2CircleShape));\r
+ b2CircleShape* clone = new (mem) b2CircleShape;\r
+ *clone = *this;\r
+ return clone;\r
+}\r
+\r
+bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const\r
+{\r
+ b2Vec2 center = transform.position + b2Mul(transform.R, m_p);\r
+ b2Vec2 d = p - center;\r
+ return b2Dot(d, d) <= m_radius * m_radius;\r
+}\r
+\r
+// Collision Detection in Interactive 3D Environments by Gino van den Bergen\r
+// From Section 3.1.2\r
+// x = s + a * r\r
+// norm(x) = radius\r
+bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const\r
+{\r
+ b2Vec2 position = transform.position + b2Mul(transform.R, m_p);\r
+ b2Vec2 s = input.p1 - position;\r
+ float32 b = b2Dot(s, s) - m_radius * m_radius;\r
+\r
+ // Solve quadratic equation.\r
+ b2Vec2 r = input.p2 - input.p1;\r
+ float32 c = b2Dot(s, r);\r
+ float32 rr = b2Dot(r, r);\r
+ float32 sigma = c * c - rr * b;\r
+\r
+ // Check for negative discriminant and short segment.\r
+ if (sigma < 0.0f || rr < b2_epsilon)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // Find the point of intersection of the line with the circle.\r
+ float32 a = -(c + b2Sqrt(sigma));\r
+\r
+ // Is the intersection point on the segment?\r
+ if (0.0f <= a && a <= input.maxFraction * rr)\r
+ {\r
+ a /= rr;\r
+ output->fraction = a;\r
+ output->normal = s + a * r;\r
+ output->normal.Normalize();\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+}\r
+\r
+void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform) const\r
+{\r
+ b2Vec2 p = transform.position + b2Mul(transform.R, m_p);\r
+ aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);\r
+ aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);\r
+}\r
+\r
+void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const\r
+{\r
+ massData->mass = density * b2_pi * m_radius * m_radius;\r
+ massData->center = m_p;\r
+\r
+ // inertia about the local origin\r
+ massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p));\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_CIRCLE_SHAPE_H\r
+#define B2_CIRCLE_SHAPE_H\r
+\r
+#include <Box2D/Collision/Shapes/b2Shape.h>\r
+\r
+/// A circle shape.\r
+class b2CircleShape : public b2Shape\r
+{\r
+public:\r
+ b2CircleShape();\r
+\r
+ /// Implement b2Shape.\r
+ b2Shape* Clone(b2BlockAllocator* allocator) const;\r
+\r
+ /// Implement b2Shape.\r
+ bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;\r
+\r
+ /// Implement b2Shape.\r
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const;\r
+\r
+ /// @see b2Shape::ComputeAABB\r
+ void ComputeAABB(b2AABB* aabb, const b2Transform& transform) const;\r
+\r
+ /// @see b2Shape::ComputeMass\r
+ void ComputeMass(b2MassData* massData, float32 density) const;\r
+\r
+ /// Get the supporting vertex index in the given direction.\r
+ int32 GetSupport(const b2Vec2& d) const;\r
+\r
+ /// Get the supporting vertex in the given direction.\r
+ const b2Vec2& GetSupportVertex(const b2Vec2& d) const;\r
+\r
+ /// Get the vertex count.\r
+ int32 GetVertexCount() const { return 1; }\r
+\r
+ /// Get a vertex by index. Used by b2Distance.\r
+ const b2Vec2& GetVertex(int32 index) const;\r
+\r
+ /// Position\r
+ b2Vec2 m_p;\r
+};\r
+\r
+inline b2CircleShape::b2CircleShape()\r
+{\r
+ m_type = e_circle;\r
+ m_radius = 0.0f;\r
+ m_p.SetZero();\r
+}\r
+\r
+inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const\r
+{\r
+ B2_NOT_USED(d);\r
+ return 0;\r
+}\r
+\r
+inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const\r
+{\r
+ B2_NOT_USED(d);\r
+ return m_p;\r
+}\r
+\r
+inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const\r
+{\r
+ B2_NOT_USED(index);\r
+ b2Assert(index == 0);\r
+ return m_p;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+#include <new>\r
+\r
+b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const\r
+{\r
+ void* mem = allocator->Allocate(sizeof(b2PolygonShape));\r
+ b2PolygonShape* clone = new (mem) b2PolygonShape;\r
+ *clone = *this;\r
+ return clone;\r
+}\r
+\r
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy)\r
+{\r
+ m_vertexCount = 4;\r
+ m_vertices[0].Set(-hx, -hy);\r
+ m_vertices[1].Set( hx, -hy);\r
+ m_vertices[2].Set( hx, hy);\r
+ m_vertices[3].Set(-hx, hy);\r
+ m_normals[0].Set(0.0f, -1.0f);\r
+ m_normals[1].Set(1.0f, 0.0f);\r
+ m_normals[2].Set(0.0f, 1.0f);\r
+ m_normals[3].Set(-1.0f, 0.0f);\r
+ m_centroid.SetZero();\r
+}\r
+\r
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)\r
+{\r
+ m_vertexCount = 4;\r
+ m_vertices[0].Set(-hx, -hy);\r
+ m_vertices[1].Set( hx, -hy);\r
+ m_vertices[2].Set( hx, hy);\r
+ m_vertices[3].Set(-hx, hy);\r
+ m_normals[0].Set(0.0f, -1.0f);\r
+ m_normals[1].Set(1.0f, 0.0f);\r
+ m_normals[2].Set(0.0f, 1.0f);\r
+ m_normals[3].Set(-1.0f, 0.0f);\r
+ m_centroid = center;\r
+\r
+ b2Transform xf;\r
+ xf.position = center;\r
+ xf.R.Set(angle);\r
+\r
+ // Transform vertices and normals.\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ m_vertices[i] = b2Mul(xf, m_vertices[i]);\r
+ m_normals[i] = b2Mul(xf.R, m_normals[i]);\r
+ }\r
+}\r
+\r
+void b2PolygonShape::SetAsEdge(const b2Vec2& v1, const b2Vec2& v2)\r
+{\r
+ m_vertexCount = 2;\r
+ m_vertices[0] = v1;\r
+ m_vertices[1] = v2;\r
+ m_centroid = 0.5f * (v1 + v2);\r
+ m_normals[0] = b2Cross(v2 - v1, 1.0f);\r
+ m_normals[0].Normalize();\r
+ m_normals[1] = -m_normals[0];\r
+}\r
+\r
+static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)\r
+{\r
+ b2Assert(count >= 2);\r
+\r
+ b2Vec2 c; c.Set(0.0f, 0.0f);\r
+ float32 area = 0.0f;\r
+\r
+ if (count == 2)\r
+ {\r
+ c = 0.5f * (vs[0] + vs[1]);\r
+ return c;\r
+ }\r
+\r
+ // pRef is the reference point for forming triangles.\r
+ // It's location doesn't change the result (except for rounding error).\r
+ b2Vec2 pRef(0.0f, 0.0f);\r
+#if 0\r
+ // This code would put the reference point inside the polygon.\r
+ for (int32 i = 0; i < count; ++i)\r
+ {\r
+ pRef += vs[i];\r
+ }\r
+ pRef *= 1.0f / count;\r
+#endif\r
+\r
+ const float32 inv3 = 1.0f / 3.0f;\r
+\r
+ for (int32 i = 0; i < count; ++i)\r
+ {\r
+ // Triangle vertices.\r
+ b2Vec2 p1 = pRef;\r
+ b2Vec2 p2 = vs[i];\r
+ b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];\r
+\r
+ b2Vec2 e1 = p2 - p1;\r
+ b2Vec2 e2 = p3 - p1;\r
+\r
+ float32 D = b2Cross(e1, e2);\r
+\r
+ float32 triangleArea = 0.5f * D;\r
+ area += triangleArea;\r
+\r
+ // Area weighted centroid\r
+ c += triangleArea * inv3 * (p1 + p2 + p3);\r
+ }\r
+\r
+ // Centroid\r
+ b2Assert(area > b2_epsilon);\r
+ c *= 1.0f / area;\r
+ return c;\r
+}\r
+\r
+void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)\r
+{\r
+ b2Assert(2 <= count && count <= b2_maxPolygonVertices);\r
+ m_vertexCount = count;\r
+\r
+ // Copy vertices.\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ m_vertices[i] = vertices[i];\r
+ }\r
+\r
+ // Compute normals. Ensure the edges have non-zero length.\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ int32 i1 = i;\r
+ int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;\r
+ b2Vec2 edge = m_vertices[i2] - m_vertices[i1];\r
+ b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon);\r
+ m_normals[i] = b2Cross(edge, 1.0f);\r
+ m_normals[i].Normalize();\r
+ }\r
+\r
+#ifdef _DEBUG\r
+ // Ensure the polygon is convex and the interior\r
+ // is to the left of each edge.\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ int32 i1 = i;\r
+ int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;\r
+ b2Vec2 edge = m_vertices[i2] - m_vertices[i1];\r
+\r
+ for (int32 j = 0; j < m_vertexCount; ++j)\r
+ {\r
+ // Don't check vertices on the current edge.\r
+ if (j == i1 || j == i2)\r
+ {\r
+ continue;\r
+ }\r
+ \r
+ b2Vec2 r = m_vertices[j] - m_vertices[i1];\r
+\r
+ // Your polygon is non-convex (it has an indentation) or\r
+ // has colinear edges.\r
+ float32 s = b2Cross(edge, r);\r
+ b2Assert(s > 0.0f);\r
+ }\r
+ }\r
+#endif\r
+\r
+ // Compute the polygon centroid.\r
+ m_centroid = ComputeCentroid(m_vertices, m_vertexCount);\r
+}\r
+\r
+bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const\r
+{\r
+ b2Vec2 pLocal = b2MulT(xf.R, p - xf.position);\r
+\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);\r
+ if (dot > 0.0f)\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& xf) const\r
+{\r
+ // Put the ray into the polygon's frame of reference.\r
+ b2Vec2 p1 = b2MulT(xf.R, input.p1 - xf.position);\r
+ b2Vec2 p2 = b2MulT(xf.R, input.p2 - xf.position);\r
+ b2Vec2 d = p2 - p1;\r
+\r
+ if (m_vertexCount == 2)\r
+ {\r
+ b2Vec2 v1 = m_vertices[0];\r
+ b2Vec2 v2 = m_vertices[1];\r
+ b2Vec2 normal = m_normals[0];\r
+\r
+ // q = p1 + t * d\r
+ // dot(normal, q - v1) = 0\r
+ // dot(normal, p1 - v1) + t * dot(normal, d) = 0\r
+ float32 numerator = b2Dot(normal, v1 - p1);\r
+ float32 denominator = b2Dot(normal, d);\r
+\r
+ if (denominator == 0.0f)\r
+ {\r
+ return false;\r
+ }\r
+ \r
+ float32 t = numerator / denominator;\r
+ if (t < 0.0f || 1.0f < t)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ b2Vec2 q = p1 + t * d;\r
+\r
+ // q = v1 + s * r\r
+ // s = dot(q - v1, r) / dot(r, r)\r
+ b2Vec2 r = v2 - v1;\r
+ float32 rr = b2Dot(r, r);\r
+ if (rr == 0.0f)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ float32 s = b2Dot(q - v1, r) / rr;\r
+ if (s < 0.0f || 1.0f < s)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ output->fraction = t;\r
+ if (numerator > 0.0f)\r
+ {\r
+ output->normal = -normal;\r
+ }\r
+ else\r
+ {\r
+ output->normal = normal;\r
+ }\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ float32 lower = 0.0f, upper = input.maxFraction;\r
+\r
+ int32 index = -1;\r
+\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ // p = p1 + a * d\r
+ // dot(normal, p - v) = 0\r
+ // dot(normal, p1 - v) + a * dot(normal, d) = 0\r
+ float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);\r
+ float32 denominator = b2Dot(m_normals[i], d);\r
+\r
+ if (denominator == 0.0f)\r
+ { \r
+ if (numerator < 0.0f)\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Note: we want this predicate without division:\r
+ // lower < numerator / denominator, where denominator < 0\r
+ // Since denominator < 0, we have to flip the inequality:\r
+ // lower < numerator / denominator <==> denominator * lower > numerator.\r
+ if (denominator < 0.0f && numerator < lower * denominator)\r
+ {\r
+ // Increase lower.\r
+ // The segment enters this half-space.\r
+ lower = numerator / denominator;\r
+ index = i;\r
+ }\r
+ else if (denominator > 0.0f && numerator < upper * denominator)\r
+ {\r
+ // Decrease upper.\r
+ // The segment exits this half-space.\r
+ upper = numerator / denominator;\r
+ }\r
+ }\r
+\r
+ // The use of epsilon here causes the assert on lower to trip\r
+ // in some cases. Apparently the use of epsilon was to make edge\r
+ // shapes work, but now those are handled separately.\r
+ //if (upper < lower - b2_epsilon)\r
+ if (upper < lower)\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ b2Assert(0.0f <= lower && lower <= input.maxFraction);\r
+\r
+ if (index >= 0)\r
+ {\r
+ output->fraction = lower;\r
+ output->normal = b2Mul(xf.R, m_normals[index]);\r
+ return true;\r
+ }\r
+ }\r
+\r
+ return false;\r
+}\r
+\r
+void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf) const\r
+{\r
+ b2Vec2 lower = b2Mul(xf, m_vertices[0]);\r
+ b2Vec2 upper = lower;\r
+\r
+ for (int32 i = 1; i < m_vertexCount; ++i)\r
+ {\r
+ b2Vec2 v = b2Mul(xf, m_vertices[i]);\r
+ lower = b2Min(lower, v);\r
+ upper = b2Max(upper, v);\r
+ }\r
+\r
+ b2Vec2 r(m_radius, m_radius);\r
+ aabb->lowerBound = lower - r;\r
+ aabb->upperBound = upper + r;\r
+}\r
+\r
+void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const\r
+{\r
+ // Polygon mass, centroid, and inertia.\r
+ // Let rho be the polygon density in mass per unit area.\r
+ // Then:\r
+ // mass = rho * int(dA)\r
+ // centroid.x = (1/mass) * rho * int(x * dA)\r
+ // centroid.y = (1/mass) * rho * int(y * dA)\r
+ // I = rho * int((x*x + y*y) * dA)\r
+ //\r
+ // We can compute these integrals by summing all the integrals\r
+ // for each triangle of the polygon. To evaluate the integral\r
+ // for a single triangle, we make a change of variables to\r
+ // the (u,v) coordinates of the triangle:\r
+ // x = x0 + e1x * u + e2x * v\r
+ // y = y0 + e1y * u + e2y * v\r
+ // where 0 <= u && 0 <= v && u + v <= 1.\r
+ //\r
+ // We integrate u from [0,1-v] and then v from [0,1].\r
+ // We also need to use the Jacobian of the transformation:\r
+ // D = cross(e1, e2)\r
+ //\r
+ // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)\r
+ //\r
+ // The rest of the derivation is handled by computer algebra.\r
+\r
+ b2Assert(m_vertexCount >= 2);\r
+\r
+ // A line segment has zero mass.\r
+ if (m_vertexCount == 2)\r
+ {\r
+ massData->center = 0.5f * (m_vertices[0] + m_vertices[1]);\r
+ massData->mass = 0.0f;\r
+ massData->I = 0.0f;\r
+ return;\r
+ }\r
+\r
+ b2Vec2 center; center.Set(0.0f, 0.0f);\r
+ float32 area = 0.0f;\r
+ float32 I = 0.0f;\r
+\r
+ // pRef is the reference point for forming triangles.\r
+ // It's location doesn't change the result (except for rounding error).\r
+ b2Vec2 pRef(0.0f, 0.0f);\r
+#if 0\r
+ // This code would put the reference point inside the polygon.\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ pRef += m_vertices[i];\r
+ }\r
+ pRef *= 1.0f / count;\r
+#endif\r
+\r
+ const float32 k_inv3 = 1.0f / 3.0f;\r
+\r
+ for (int32 i = 0; i < m_vertexCount; ++i)\r
+ {\r
+ // Triangle vertices.\r
+ b2Vec2 p1 = pRef;\r
+ b2Vec2 p2 = m_vertices[i];\r
+ b2Vec2 p3 = i + 1 < m_vertexCount ? m_vertices[i+1] : m_vertices[0];\r
+\r
+ b2Vec2 e1 = p2 - p1;\r
+ b2Vec2 e2 = p3 - p1;\r
+\r
+ float32 D = b2Cross(e1, e2);\r
+\r
+ float32 triangleArea = 0.5f * D;\r
+ area += triangleArea;\r
+\r
+ // Area weighted centroid\r
+ center += triangleArea * k_inv3 * (p1 + p2 + p3);\r
+\r
+ float32 px = p1.x, py = p1.y;\r
+ float32 ex1 = e1.x, ey1 = e1.y;\r
+ float32 ex2 = e2.x, ey2 = e2.y;\r
+\r
+ float32 intx2 = k_inv3 * (0.25f * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5f*px*px;\r
+ float32 inty2 = k_inv3 * (0.25f * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5f*py*py;\r
+\r
+ I += D * (intx2 + inty2);\r
+ }\r
+\r
+ // Total mass\r
+ massData->mass = density * area;\r
+\r
+ // Center of mass\r
+ b2Assert(area > b2_epsilon);\r
+ center *= 1.0f / area;\r
+ massData->center = center;\r
+\r
+ // Inertia tensor relative to the local origin.\r
+ massData->I = density * I;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_POLYGON_SHAPE_H\r
+#define B2_POLYGON_SHAPE_H\r
+\r
+#include <Box2D/Collision/Shapes/b2Shape.h>\r
+\r
+/// A convex polygon. It is assumed that the interior of the polygon is to\r
+/// the left of each edge.\r
+class b2PolygonShape : public b2Shape\r
+{\r
+public:\r
+ b2PolygonShape();\r
+\r
+ /// Implement b2Shape.\r
+ b2Shape* Clone(b2BlockAllocator* allocator) const;\r
+\r
+ /// Copy vertices. This assumes the vertices define a convex polygon.\r
+ /// It is assumed that the exterior is the the right of each edge.\r
+ void Set(const b2Vec2* vertices, int32 vertexCount);\r
+\r
+ /// Build vertices to represent an axis-aligned box.\r
+ /// @param hx the half-width.\r
+ /// @param hy the half-height.\r
+ void SetAsBox(float32 hx, float32 hy);\r
+\r
+ /// Build vertices to represent an oriented box.\r
+ /// @param hx the half-width.\r
+ /// @param hy the half-height.\r
+ /// @param center the center of the box in local coordinates.\r
+ /// @param angle the rotation of the box in local coordinates.\r
+ void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);\r
+\r
+ /// Set this as a single edge.\r
+ void SetAsEdge(const b2Vec2& v1, const b2Vec2& v2);\r
+\r
+ /// @see b2Shape::TestPoint\r
+ bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;\r
+\r
+ /// Implement b2Shape.\r
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const;\r
+\r
+ /// @see b2Shape::ComputeAABB\r
+ void ComputeAABB(b2AABB* aabb, const b2Transform& transform) const;\r
+\r
+ /// @see b2Shape::ComputeMass\r
+ void ComputeMass(b2MassData* massData, float32 density) const;\r
+\r
+ /// Get the supporting vertex index in the given direction.\r
+ int32 GetSupport(const b2Vec2& d) const;\r
+\r
+ /// Get the supporting vertex in the given direction.\r
+ const b2Vec2& GetSupportVertex(const b2Vec2& d) const;\r
+\r
+ /// Get the vertex count.\r
+ int32 GetVertexCount() const { return m_vertexCount; }\r
+\r
+ /// Get a vertex by index.\r
+ const b2Vec2& GetVertex(int32 index) const;\r
+\r
+ b2Vec2 m_centroid;\r
+ b2Vec2 m_vertices[b2_maxPolygonVertices];\r
+ b2Vec2 m_normals[b2_maxPolygonVertices];\r
+ int32 m_vertexCount;\r
+};\r
+\r
+inline b2PolygonShape::b2PolygonShape()\r
+{\r
+ m_type = e_polygon;\r
+ m_radius = b2_polygonRadius;\r
+ m_vertexCount = 0;\r
+ m_centroid.SetZero();\r
+}\r
+\r
+inline int32 b2PolygonShape::GetSupport(const b2Vec2& d) const\r
+{\r
+ int32 bestIndex = 0;\r
+ float32 bestValue = b2Dot(m_vertices[0], d);\r
+ for (int32 i = 1; i < m_vertexCount; ++i)\r
+ {\r
+ float32 value = b2Dot(m_vertices[i], d);\r
+ if (value > bestValue)\r
+ {\r
+ bestIndex = i;\r
+ bestValue = value;\r
+ }\r
+ }\r
+\r
+ return bestIndex;\r
+}\r
+\r
+inline const b2Vec2& b2PolygonShape::GetSupportVertex(const b2Vec2& d) const\r
+{\r
+ int32 bestIndex = 0;\r
+ float32 bestValue = b2Dot(m_vertices[0], d);\r
+ for (int32 i = 1; i < m_vertexCount; ++i)\r
+ {\r
+ float32 value = b2Dot(m_vertices[i], d);\r
+ if (value > bestValue)\r
+ {\r
+ bestIndex = i;\r
+ bestValue = value;\r
+ }\r
+ }\r
+\r
+ return m_vertices[bestIndex];\r
+}\r
+\r
+inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const\r
+{\r
+ b2Assert(0 <= index && index < m_vertexCount);\r
+ return m_vertices[index];\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_SHAPE_H\r
+#define B2_SHAPE_H\r
+\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+#include <Box2D/Common/b2Math.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+\r
+/// This holds the mass data computed for a shape.\r
+struct b2MassData\r
+{\r
+ /// The mass of the shape, usually in kilograms.\r
+ float32 mass;\r
+\r
+ /// The position of the shape's centroid relative to the shape's origin.\r
+ b2Vec2 center;\r
+\r
+ /// The rotational inertia of the shape about the local origin.\r
+ float32 I;\r
+};\r
+\r
+/// A shape is used for collision detection. You can create a shape however you like.\r
+/// Shapes used for simulation in b2World are created automatically when a b2Fixture\r
+/// is created.\r
+class b2Shape\r
+{\r
+public:\r
+ \r
+ enum Type\r
+ {\r
+ e_unknown= -1,\r
+ e_circle = 0,\r
+ e_polygon = 1,\r
+ e_typeCount = 2,\r
+ };\r
+\r
+ b2Shape() { m_type = e_unknown; }\r
+ virtual ~b2Shape() {}\r
+\r
+ /// Clone the concrete shape using the provided allocator.\r
+ virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;\r
+\r
+ /// Get the type of this shape. You can use this to down cast to the concrete shape.\r
+ /// @return the shape type.\r
+ Type GetType() const;\r
+\r
+ /// Test a point for containment in this shape. This only works for convex shapes.\r
+ /// @param xf the shape world transform.\r
+ /// @param p a point in world coordinates.\r
+ virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;\r
+\r
+ /// Cast a ray against this shape.\r
+ /// @param output the ray-cast results.\r
+ /// @param input the ray-cast input parameters.\r
+ /// @param transform the transform to be applied to the shape.\r
+ virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const = 0;\r
+\r
+ /// Given a transform, compute the associated axis aligned bounding box for this shape.\r
+ /// @param aabb returns the axis aligned box.\r
+ /// @param xf the world transform of the shape.\r
+ virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf) const = 0;\r
+\r
+ /// Compute the mass properties of this shape using its dimensions and density.\r
+ /// The inertia tensor is computed about the local origin.\r
+ /// @param massData returns the mass data for this shape.\r
+ /// @param density the density in kilograms per meter squared.\r
+ virtual void ComputeMass(b2MassData* massData, float32 density) const = 0;\r
+\r
+ Type m_type;\r
+ float32 m_radius;\r
+};\r
+\r
+inline b2Shape::Type b2Shape::GetType() const\r
+{\r
+ return m_type;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2BroadPhase.h>\r
+#include <cstring>\r
+\r
+b2BroadPhase::b2BroadPhase()\r
+{\r
+ m_proxyCount = 0;\r
+\r
+ m_pairCapacity = 16;\r
+ m_pairCount = 0;\r
+ m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));\r
+\r
+ m_moveCapacity = 16;\r
+ m_moveCount = 0;\r
+ m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));\r
+}\r
+\r
+b2BroadPhase::~b2BroadPhase()\r
+{\r
+ b2Free(m_moveBuffer);\r
+ b2Free(m_pairBuffer);\r
+}\r
+\r
+int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData)\r
+{\r
+ int32 proxyId = m_tree.CreateProxy(aabb, userData);\r
+ ++m_proxyCount;\r
+ BufferMove(proxyId);\r
+ return proxyId;\r
+}\r
+\r
+void b2BroadPhase::DestroyProxy(int32 proxyId)\r
+{\r
+ UnBufferMove(proxyId);\r
+ --m_proxyCount;\r
+ m_tree.DestroyProxy(proxyId);\r
+}\r
+\r
+void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)\r
+{\r
+ bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement);\r
+ if (buffer)\r
+ {\r
+ BufferMove(proxyId);\r
+ }\r
+}\r
+\r
+void b2BroadPhase::BufferMove(int32 proxyId)\r
+{\r
+ if (m_moveCount == m_moveCapacity)\r
+ {\r
+ int32* oldBuffer = m_moveBuffer;\r
+ m_moveCapacity *= 2;\r
+ m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));\r
+ memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32));\r
+ b2Free(oldBuffer);\r
+ }\r
+\r
+ m_moveBuffer[m_moveCount] = proxyId;\r
+ ++m_moveCount;\r
+}\r
+\r
+void b2BroadPhase::UnBufferMove(int32 proxyId)\r
+{\r
+ for (int32 i = 0; i < m_moveCount; ++i)\r
+ {\r
+ if (m_moveBuffer[i] == proxyId)\r
+ {\r
+ m_moveBuffer[i] = e_nullProxy;\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+// This is called from b2DynamicTree::Query when we are gathering pairs.\r
+bool b2BroadPhase::QueryCallback(int32 proxyId)\r
+{\r
+ // A proxy cannot form a pair with itself.\r
+ if (proxyId == m_queryProxyId)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ // Grow the pair buffer as needed.\r
+ if (m_pairCount == m_pairCapacity)\r
+ {\r
+ b2Pair* oldBuffer = m_pairBuffer;\r
+ m_pairCapacity *= 2;\r
+ m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));\r
+ memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));\r
+ b2Free(oldBuffer);\r
+ }\r
+\r
+ m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId);\r
+ m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId);\r
+ ++m_pairCount;\r
+\r
+ return true;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_BROAD_PHASE_H\r
+#define B2_BROAD_PHASE_H\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/b2DynamicTree.h>\r
+#include <algorithm>\r
+\r
+struct b2Pair\r
+{\r
+ int32 proxyIdA;\r
+ int32 proxyIdB;\r
+ int32 next;\r
+};\r
+\r
+/// The broad-phase is used for computing pairs and performing volume queries and ray casts.\r
+/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.\r
+/// It is up to the client to consume the new pairs and to track subsequent overlap.\r
+class b2BroadPhase\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_nullProxy = -1,\r
+ };\r
+\r
+ b2BroadPhase();\r
+ ~b2BroadPhase();\r
+\r
+ /// Create a proxy with an initial AABB. Pairs are not reported until\r
+ /// UpdatePairs is called.\r
+ int32 CreateProxy(const b2AABB& aabb, void* userData);\r
+\r
+ /// Destroy a proxy. It is up to the client to remove any pairs.\r
+ void DestroyProxy(int32 proxyId);\r
+\r
+ /// Call MoveProxy as many times as you like, then when you are done\r
+ /// call UpdatePairs to finalized the proxy pairs (for your time step).\r
+ void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement);\r
+\r
+ /// Get the fat AABB for a proxy.\r
+ const b2AABB& GetFatAABB(int32 proxyId) const;\r
+\r
+ /// Get user data from a proxy. Returns NULL if the id is invalid.\r
+ void* GetUserData(int32 proxyId) const;\r
+\r
+ /// Test overlap of fat AABBs.\r
+ bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const;\r
+\r
+ /// Get the number of proxies.\r
+ int32 GetProxyCount() const;\r
+\r
+ /// Update the pairs. This results in pair callbacks. This can only add pairs.\r
+ template <typename T>\r
+ void UpdatePairs(T* callback);\r
+\r
+ /// Query an AABB for overlapping proxies. The callback class\r
+ /// is called for each proxy that overlaps the supplied AABB.\r
+ template <typename T>\r
+ void Query(T* callback, const b2AABB& aabb) const;\r
+\r
+ /// Ray-cast against the proxies in the tree. This relies on the callback\r
+ /// to perform a exact ray-cast in the case were the proxy contains a shape.\r
+ /// The callback also performs the any collision filtering. This has performance\r
+ /// roughly equal to k * log(n), where k is the number of collisions and n is the\r
+ /// number of proxies in the tree.\r
+ /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).\r
+ /// @param callback a callback class that is called for each proxy that is hit by the ray.\r
+ template <typename T>\r
+ void RayCast(T* callback, const b2RayCastInput& input) const;\r
+\r
+ /// Compute the height of the embedded tree.\r
+ int32 ComputeHeight() const;\r
+\r
+private:\r
+\r
+ friend class b2DynamicTree;\r
+\r
+ void BufferMove(int32 proxyId);\r
+ void UnBufferMove(int32 proxyId);\r
+\r
+ bool QueryCallback(int32 proxyId);\r
+\r
+ b2DynamicTree m_tree;\r
+\r
+ int32 m_proxyCount;\r
+\r
+ int32* m_moveBuffer;\r
+ int32 m_moveCapacity;\r
+ int32 m_moveCount;\r
+\r
+ b2Pair* m_pairBuffer;\r
+ int32 m_pairCapacity;\r
+ int32 m_pairCount;\r
+\r
+ int32 m_queryProxyId;\r
+};\r
+\r
+/// This is used to sort pairs.\r
+inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2)\r
+{\r
+ if (pair1.proxyIdA < pair2.proxyIdA)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ if (pair1.proxyIdA == pair2.proxyIdA)\r
+ {\r
+ return pair1.proxyIdB < pair2.proxyIdB;\r
+ }\r
+\r
+ return false;\r
+}\r
+\r
+inline void* b2BroadPhase::GetUserData(int32 proxyId) const\r
+{\r
+ return m_tree.GetUserData(proxyId);\r
+}\r
+\r
+inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const\r
+{\r
+ const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA);\r
+ const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB);\r
+ return b2TestOverlap(aabbA, aabbB);\r
+}\r
+\r
+inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const\r
+{\r
+ return m_tree.GetFatAABB(proxyId);\r
+}\r
+\r
+inline int32 b2BroadPhase::GetProxyCount() const\r
+{\r
+ return m_proxyCount;\r
+}\r
+\r
+inline int32 b2BroadPhase::ComputeHeight() const\r
+{\r
+ return m_tree.ComputeHeight();\r
+}\r
+\r
+template <typename T>\r
+void b2BroadPhase::UpdatePairs(T* callback)\r
+{\r
+ // Reset pair buffer\r
+ m_pairCount = 0;\r
+\r
+ // Perform tree queries for all moving proxies.\r
+ for (int32 i = 0; i < m_moveCount; ++i)\r
+ {\r
+ m_queryProxyId = m_moveBuffer[i];\r
+ if (m_queryProxyId == e_nullProxy)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // We have to query the tree with the fat AABB so that\r
+ // we don't fail to create a pair that may touch later.\r
+ const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId);\r
+\r
+ // Query tree, create pairs and add them pair buffer.\r
+ m_tree.Query(this, fatAABB);\r
+ }\r
+\r
+ // Reset move buffer\r
+ m_moveCount = 0;\r
+\r
+ // Sort the pair buffer to expose duplicates.\r
+ std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan);\r
+\r
+ // Send the pairs back to the client.\r
+ int32 i = 0;\r
+ while (i < m_pairCount)\r
+ {\r
+ b2Pair* primaryPair = m_pairBuffer + i;\r
+ void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA);\r
+ void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB);\r
+\r
+ callback->AddPair(userDataA, userDataB);\r
+ ++i;\r
+\r
+ // Skip any duplicate pairs.\r
+ while (i < m_pairCount)\r
+ {\r
+ b2Pair* pair = m_pairBuffer + i;\r
+ if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)\r
+ {\r
+ break;\r
+ }\r
+ ++i;\r
+ }\r
+ }\r
+\r
+ // Try to keep the tree balanced.\r
+ m_tree.Rebalance(4);\r
+}\r
+\r
+template <typename T>\r
+inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const\r
+{\r
+ m_tree.Query(callback, aabb);\r
+}\r
+\r
+template <typename T>\r
+inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const\r
+{\r
+ m_tree.RayCast(callback, input);\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+\r
+void b2CollideCircles(\r
+ b2Manifold* manifold,\r
+ const b2CircleShape* circleA, const b2Transform& xfA,\r
+ const b2CircleShape* circleB, const b2Transform& xfB)\r
+{\r
+ manifold->pointCount = 0;\r
+\r
+ b2Vec2 pA = b2Mul(xfA, circleA->m_p);\r
+ b2Vec2 pB = b2Mul(xfB, circleB->m_p);\r
+\r
+ b2Vec2 d = pB - pA;\r
+ float32 distSqr = b2Dot(d, d);\r
+ float32 rA = circleA->m_radius, rB = circleB->m_radius;\r
+ float32 radius = rA + rB;\r
+ if (distSqr > radius * radius)\r
+ {\r
+ return;\r
+ }\r
+\r
+ manifold->type = b2Manifold::e_circles;\r
+ manifold->localPoint = circleA->m_p;\r
+ manifold->localNormal.SetZero();\r
+ manifold->pointCount = 1;\r
+\r
+ manifold->points[0].localPoint = circleB->m_p;\r
+ manifold->points[0].id.key = 0;\r
+}\r
+\r
+void b2CollidePolygonAndCircle(\r
+ b2Manifold* manifold,\r
+ const b2PolygonShape* polygonA, const b2Transform& xfA,\r
+ const b2CircleShape* circleB, const b2Transform& xfB)\r
+{\r
+ manifold->pointCount = 0;\r
+\r
+ // Compute circle position in the frame of the polygon.\r
+ b2Vec2 c = b2Mul(xfB, circleB->m_p);\r
+ b2Vec2 cLocal = b2MulT(xfA, c);\r
+\r
+ // Find the min separating edge.\r
+ int32 normalIndex = 0;\r
+ float32 separation = -b2_maxFloat;\r
+ float32 radius = polygonA->m_radius + circleB->m_radius;\r
+ int32 vertexCount = polygonA->m_vertexCount;\r
+ const b2Vec2* vertices = polygonA->m_vertices;\r
+ const b2Vec2* normals = polygonA->m_normals;\r
+\r
+ for (int32 i = 0; i < vertexCount; ++i)\r
+ {\r
+ float32 s = b2Dot(normals[i], cLocal - vertices[i]);\r
+\r
+ if (s > radius)\r
+ {\r
+ // Early out.\r
+ return;\r
+ }\r
+\r
+ if (s > separation)\r
+ {\r
+ separation = s;\r
+ normalIndex = i;\r
+ }\r
+ }\r
+\r
+ // Vertices that subtend the incident face.\r
+ int32 vertIndex1 = normalIndex;\r
+ int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;\r
+ b2Vec2 v1 = vertices[vertIndex1];\r
+ b2Vec2 v2 = vertices[vertIndex2];\r
+\r
+ // If the center is inside the polygon ...\r
+ if (separation < b2_epsilon)\r
+ {\r
+ manifold->pointCount = 1;\r
+ manifold->type = b2Manifold::e_faceA;\r
+ manifold->localNormal = normals[normalIndex];\r
+ manifold->localPoint = 0.5f * (v1 + v2);\r
+ manifold->points[0].localPoint = circleB->m_p;\r
+ manifold->points[0].id.key = 0;\r
+ return;\r
+ }\r
+\r
+ // Compute barycentric coordinates\r
+ float32 u1 = b2Dot(cLocal - v1, v2 - v1);\r
+ float32 u2 = b2Dot(cLocal - v2, v1 - v2);\r
+ if (u1 <= 0.0f)\r
+ {\r
+ if (b2DistanceSquared(cLocal, v1) > radius * radius)\r
+ {\r
+ return;\r
+ }\r
+\r
+ manifold->pointCount = 1;\r
+ manifold->type = b2Manifold::e_faceA;\r
+ manifold->localNormal = cLocal - v1;\r
+ manifold->localNormal.Normalize();\r
+ manifold->localPoint = v1;\r
+ manifold->points[0].localPoint = circleB->m_p;\r
+ manifold->points[0].id.key = 0;\r
+ }\r
+ else if (u2 <= 0.0f)\r
+ {\r
+ if (b2DistanceSquared(cLocal, v2) > radius * radius)\r
+ {\r
+ return;\r
+ }\r
+\r
+ manifold->pointCount = 1;\r
+ manifold->type = b2Manifold::e_faceA;\r
+ manifold->localNormal = cLocal - v2;\r
+ manifold->localNormal.Normalize();\r
+ manifold->localPoint = v2;\r
+ manifold->points[0].localPoint = circleB->m_p;\r
+ manifold->points[0].id.key = 0;\r
+ }\r
+ else\r
+ {\r
+ b2Vec2 faceCenter = 0.5f * (v1 + v2);\r
+ float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]);\r
+ if (separation > radius)\r
+ {\r
+ return;\r
+ }\r
+\r
+ manifold->pointCount = 1;\r
+ manifold->type = b2Manifold::e_faceA;\r
+ manifold->localNormal = normals[vertIndex1];\r
+ manifold->localPoint = faceCenter;\r
+ manifold->points[0].localPoint = circleB->m_p;\r
+ manifold->points[0].id.key = 0;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+\r
+// Find the separation between poly1 and poly2 for a give edge normal on poly1.\r
+static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,\r
+ const b2PolygonShape* poly2, const b2Transform& xf2)\r
+{\r
+ int32 count1 = poly1->m_vertexCount;\r
+ const b2Vec2* vertices1 = poly1->m_vertices;\r
+ const b2Vec2* normals1 = poly1->m_normals;\r
+\r
+ int32 count2 = poly2->m_vertexCount;\r
+ const b2Vec2* vertices2 = poly2->m_vertices;\r
+\r
+ b2Assert(0 <= edge1 && edge1 < count1);\r
+\r
+ // Convert normal from poly1's frame into poly2's frame.\r
+ b2Vec2 normal1World = b2Mul(xf1.R, normals1[edge1]);\r
+ b2Vec2 normal1 = b2MulT(xf2.R, normal1World);\r
+\r
+ // Find support vertex on poly2 for -normal.\r
+ int32 index = 0;\r
+ float32 minDot = b2_maxFloat;\r
+\r
+ for (int32 i = 0; i < count2; ++i)\r
+ {\r
+ float32 dot = b2Dot(vertices2[i], normal1);\r
+ if (dot < minDot)\r
+ {\r
+ minDot = dot;\r
+ index = i;\r
+ }\r
+ }\r
+\r
+ b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]);\r
+ b2Vec2 v2 = b2Mul(xf2, vertices2[index]);\r
+ float32 separation = b2Dot(v2 - v1, normal1World);\r
+ return separation;\r
+}\r
+\r
+// Find the max separation between poly1 and poly2 using edge normals from poly1.\r
+static float32 b2FindMaxSeparation(int32* edgeIndex,\r
+ const b2PolygonShape* poly1, const b2Transform& xf1,\r
+ const b2PolygonShape* poly2, const b2Transform& xf2)\r
+{\r
+ int32 count1 = poly1->m_vertexCount;\r
+ const b2Vec2* normals1 = poly1->m_normals;\r
+\r
+ // Vector pointing from the centroid of poly1 to the centroid of poly2.\r
+ b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid);\r
+ b2Vec2 dLocal1 = b2MulT(xf1.R, d);\r
+\r
+ // Find edge normal on poly1 that has the largest projection onto d.\r
+ int32 edge = 0;\r
+ float32 maxDot = -b2_maxFloat;\r
+ for (int32 i = 0; i < count1; ++i)\r
+ {\r
+ float32 dot = b2Dot(normals1[i], dLocal1);\r
+ if (dot > maxDot)\r
+ {\r
+ maxDot = dot;\r
+ edge = i;\r
+ }\r
+ }\r
+\r
+ // Get the separation for the edge normal.\r
+ float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);\r
+\r
+ // Check the separation for the previous edge normal.\r
+ int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;\r
+ float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);\r
+\r
+ // Check the separation for the next edge normal.\r
+ int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0;\r
+ float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);\r
+\r
+ // Find the best edge and the search direction.\r
+ int32 bestEdge;\r
+ float32 bestSeparation;\r
+ int32 increment;\r
+ if (sPrev > s && sPrev > sNext)\r
+ {\r
+ increment = -1;\r
+ bestEdge = prevEdge;\r
+ bestSeparation = sPrev;\r
+ }\r
+ else if (sNext > s)\r
+ {\r
+ increment = 1;\r
+ bestEdge = nextEdge;\r
+ bestSeparation = sNext;\r
+ }\r
+ else\r
+ {\r
+ *edgeIndex = edge;\r
+ return s;\r
+ }\r
+\r
+ // Perform a local search for the best edge normal.\r
+ for ( ; ; )\r
+ {\r
+ if (increment == -1)\r
+ edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;\r
+ else\r
+ edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;\r
+\r
+ s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);\r
+\r
+ if (s > bestSeparation)\r
+ {\r
+ bestEdge = edge;\r
+ bestSeparation = s;\r
+ }\r
+ else\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ *edgeIndex = bestEdge;\r
+ return bestSeparation;\r
+}\r
+\r
+static void b2FindIncidentEdge(b2ClipVertex c[2],\r
+ const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,\r
+ const b2PolygonShape* poly2, const b2Transform& xf2)\r
+{\r
+ int32 count1 = poly1->m_vertexCount;\r
+ const b2Vec2* normals1 = poly1->m_normals;\r
+\r
+ int32 count2 = poly2->m_vertexCount;\r
+ const b2Vec2* vertices2 = poly2->m_vertices;\r
+ const b2Vec2* normals2 = poly2->m_normals;\r
+\r
+ b2Assert(0 <= edge1 && edge1 < count1);\r
+\r
+ // Get the normal of the reference edge in poly2's frame.\r
+ b2Vec2 normal1 = b2MulT(xf2.R, b2Mul(xf1.R, normals1[edge1]));\r
+\r
+ // Find the incident edge on poly2.\r
+ int32 index = 0;\r
+ float32 minDot = b2_maxFloat;\r
+ for (int32 i = 0; i < count2; ++i)\r
+ {\r
+ float32 dot = b2Dot(normal1, normals2[i]);\r
+ if (dot < minDot)\r
+ {\r
+ minDot = dot;\r
+ index = i;\r
+ }\r
+ }\r
+\r
+ // Build the clip vertices for the incident edge.\r
+ int32 i1 = index;\r
+ int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;\r
+\r
+ c[0].v = b2Mul(xf2, vertices2[i1]);\r
+ c[0].id.features.referenceEdge = (uint8)edge1;\r
+ c[0].id.features.incidentEdge = (uint8)i1;\r
+ c[0].id.features.incidentVertex = 0;\r
+\r
+ c[1].v = b2Mul(xf2, vertices2[i2]);\r
+ c[1].id.features.referenceEdge = (uint8)edge1;\r
+ c[1].id.features.incidentEdge = (uint8)i2;\r
+ c[1].id.features.incidentVertex = 1;\r
+}\r
+\r
+// Find edge normal of max separation on A - return if separating axis is found\r
+// Find edge normal of max separation on B - return if separation axis is found\r
+// Choose reference edge as min(minA, minB)\r
+// Find incident edge\r
+// Clip\r
+\r
+// The normal points from 1 to 2\r
+void b2CollidePolygons(b2Manifold* manifold,\r
+ const b2PolygonShape* polyA, const b2Transform& xfA,\r
+ const b2PolygonShape* polyB, const b2Transform& xfB)\r
+{\r
+ manifold->pointCount = 0;\r
+ float32 totalRadius = polyA->m_radius + polyB->m_radius;\r
+\r
+ int32 edgeA = 0;\r
+ float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);\r
+ if (separationA > totalRadius)\r
+ return;\r
+\r
+ int32 edgeB = 0;\r
+ float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);\r
+ if (separationB > totalRadius)\r
+ return;\r
+\r
+ const b2PolygonShape* poly1; // reference polygon\r
+ const b2PolygonShape* poly2; // incident polygon\r
+ b2Transform xf1, xf2;\r
+ int32 edge1; // reference edge\r
+ uint8 flip;\r
+ const float32 k_relativeTol = 0.98f;\r
+ const float32 k_absoluteTol = 0.001f;\r
+\r
+ if (separationB > k_relativeTol * separationA + k_absoluteTol)\r
+ {\r
+ poly1 = polyB;\r
+ poly2 = polyA;\r
+ xf1 = xfB;\r
+ xf2 = xfA;\r
+ edge1 = edgeB;\r
+ manifold->type = b2Manifold::e_faceB;\r
+ flip = 1;\r
+ }\r
+ else\r
+ {\r
+ poly1 = polyA;\r
+ poly2 = polyB;\r
+ xf1 = xfA;\r
+ xf2 = xfB;\r
+ edge1 = edgeA;\r
+ manifold->type = b2Manifold::e_faceA;\r
+ flip = 0;\r
+ }\r
+\r
+ b2ClipVertex incidentEdge[2];\r
+ b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);\r
+\r
+ int32 count1 = poly1->m_vertexCount;\r
+ const b2Vec2* vertices1 = poly1->m_vertices;\r
+\r
+ b2Vec2 v11 = vertices1[edge1];\r
+ b2Vec2 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0];\r
+\r
+ b2Vec2 localTangent = v12 - v11;\r
+ localTangent.Normalize();\r
+ \r
+ b2Vec2 localNormal = b2Cross(localTangent, 1.0f);\r
+ b2Vec2 planePoint = 0.5f * (v11 + v12);\r
+\r
+ b2Vec2 tangent = b2Mul(xf1.R, localTangent);\r
+ b2Vec2 normal = b2Cross(tangent, 1.0f);\r
+ \r
+ v11 = b2Mul(xf1, v11);\r
+ v12 = b2Mul(xf1, v12);\r
+\r
+ // Face offset.\r
+ float32 frontOffset = b2Dot(normal, v11);\r
+\r
+ // Side offsets, extended by polytope skin thickness.\r
+ float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;\r
+ float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;\r
+\r
+ // Clip incident edge against extruded edge1 side edges.\r
+ b2ClipVertex clipPoints1[2];\r
+ b2ClipVertex clipPoints2[2];\r
+ int np;\r
+\r
+ // Clip to box side 1\r
+ np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1);\r
+\r
+ if (np < 2)\r
+ return;\r
+\r
+ // Clip to negative box side 1\r
+ np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2);\r
+\r
+ if (np < 2)\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Now clipPoints2 contains the clipped points.\r
+ manifold->localNormal = localNormal;\r
+ manifold->localPoint = planePoint;\r
+\r
+ int32 pointCount = 0;\r
+ for (int32 i = 0; i < b2_maxManifoldPoints; ++i)\r
+ {\r
+ float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;\r
+\r
+ if (separation <= totalRadius)\r
+ {\r
+ b2ManifoldPoint* cp = manifold->points + pointCount;\r
+ cp->localPoint = b2MulT(xf2, clipPoints2[i].v);\r
+ cp->id = clipPoints2[i].id;\r
+ cp->id.features.flip = flip;\r
+ ++pointCount;\r
+ }\r
+ }\r
+\r
+ manifold->pointCount = pointCount;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/b2Distance.h>\r
+\r
+void b2WorldManifold::Initialize(const b2Manifold* manifold,\r
+ const b2Transform& xfA, float32 radiusA,\r
+ const b2Transform& xfB, float32 radiusB)\r
+{\r
+ if (manifold->pointCount == 0)\r
+ {\r
+ return;\r
+ }\r
+\r
+ switch (manifold->type)\r
+ {\r
+ case b2Manifold::e_circles:\r
+ {\r
+ normal.Set(1.0f, 0.0f);\r
+ b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);\r
+ b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);\r
+ if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)\r
+ {\r
+ normal = pointB - pointA;\r
+ normal.Normalize();\r
+ }\r
+\r
+ b2Vec2 cA = pointA + radiusA * normal;\r
+ b2Vec2 cB = pointB - radiusB * normal;\r
+ points[0] = 0.5f * (cA + cB);\r
+ }\r
+ break;\r
+\r
+ case b2Manifold::e_faceA:\r
+ {\r
+ normal = b2Mul(xfA.R, manifold->localNormal);\r
+ b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);\r
+ \r
+ for (int32 i = 0; i < manifold->pointCount; ++i)\r
+ {\r
+ b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);\r
+ b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;\r
+ b2Vec2 cB = clipPoint - radiusB * normal;\r
+ points[i] = 0.5f * (cA + cB);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case b2Manifold::e_faceB:\r
+ {\r
+ normal = b2Mul(xfB.R, manifold->localNormal);\r
+ b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);\r
+\r
+ for (int32 i = 0; i < manifold->pointCount; ++i)\r
+ {\r
+ b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);\r
+ b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;\r
+ b2Vec2 cA = clipPoint - radiusA * normal;\r
+ points[i] = 0.5f * (cA + cB);\r
+ }\r
+\r
+ // Ensure normal points from A to B.\r
+ normal = -normal;\r
+ }\r
+ break;\r
+ }\r
+}\r
+\r
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],\r
+ const b2Manifold* manifold1, const b2Manifold* manifold2)\r
+{\r
+ for (int32 i = 0; i < b2_maxManifoldPoints; ++i)\r
+ {\r
+ state1[i] = b2_nullState;\r
+ state2[i] = b2_nullState;\r
+ }\r
+\r
+ // Detect persists and removes.\r
+ for (int32 i = 0; i < manifold1->pointCount; ++i)\r
+ {\r
+ b2ContactID id = manifold1->points[i].id;\r
+\r
+ state1[i] = b2_removeState;\r
+\r
+ for (int32 j = 0; j < manifold2->pointCount; ++j)\r
+ {\r
+ if (manifold2->points[j].id.key == id.key)\r
+ {\r
+ state1[i] = b2_persistState;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Detect persists and adds.\r
+ for (int32 i = 0; i < manifold2->pointCount; ++i)\r
+ {\r
+ b2ContactID id = manifold2->points[i].id;\r
+\r
+ state2[i] = b2_addState;\r
+\r
+ for (int32 j = 0; j < manifold1->pointCount; ++j)\r
+ {\r
+ if (manifold1->points[j].id.key == id.key)\r
+ {\r
+ state2[i] = b2_persistState;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+// From Real-time Collision Detection, p179.\r
+bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const\r
+{\r
+ float32 tmin = -b2_maxFloat;\r
+ float32 tmax = b2_maxFloat;\r
+\r
+ b2Vec2 p = input.p1;\r
+ b2Vec2 d = input.p2 - input.p1;\r
+ b2Vec2 absD = b2Abs(d);\r
+\r
+ b2Vec2 normal;\r
+\r
+ for (int32 i = 0; i < 2; ++i)\r
+ {\r
+ if (absD(i) < b2_epsilon)\r
+ {\r
+ // Parallel.\r
+ if (p(i) < lowerBound(i) || upperBound(i) < p(i))\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ float32 inv_d = 1.0f / d(i);\r
+ float32 t1 = (lowerBound(i) - p(i)) * inv_d;\r
+ float32 t2 = (upperBound(i) - p(i)) * inv_d;\r
+\r
+ // Sign of the normal vector.\r
+ float32 s = -1.0f;\r
+\r
+ if (t1 > t2)\r
+ {\r
+ b2Swap(t1, t2);\r
+ s = 1.0f;\r
+ }\r
+\r
+ // Push the min up\r
+ if (t1 > tmin)\r
+ {\r
+ normal.SetZero();\r
+ normal(i) = s;\r
+ tmin = t1;\r
+ }\r
+\r
+ // Pull the max down\r
+ tmax = b2Min(tmax, t2);\r
+\r
+ if (tmin > tmax)\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Does the ray start inside the box?\r
+ // Does the ray intersect beyond the max fraction?\r
+ if (tmin < 0.0f || input.maxFraction < tmin)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // Intersection.\r
+ output->fraction = tmin;\r
+ output->normal = normal;\r
+ return true;\r
+}\r
+\r
+// Sutherland-Hodgman clipping.\r
+int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],\r
+ const b2Vec2& normal, float32 offset)\r
+{\r
+ // Start with no output points\r
+ int32 numOut = 0;\r
+\r
+ // Calculate the distance of end points to the line\r
+ float32 distance0 = b2Dot(normal, vIn[0].v) - offset;\r
+ float32 distance1 = b2Dot(normal, vIn[1].v) - offset;\r
+\r
+ // If the points are behind the plane\r
+ if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];\r
+ if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];\r
+\r
+ // If the points are on different sides of the plane\r
+ if (distance0 * distance1 < 0.0f)\r
+ {\r
+ // Find intersection point of edge and plane\r
+ float32 interp = distance0 / (distance0 - distance1);\r
+ vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);\r
+ if (distance0 > 0.0f)\r
+ {\r
+ vOut[numOut].id = vIn[0].id;\r
+ }\r
+ else\r
+ {\r
+ vOut[numOut].id = vIn[1].id;\r
+ }\r
+ ++numOut;\r
+ }\r
+\r
+ return numOut;\r
+}\r
+\r
+bool b2TestOverlap(const b2Shape* shapeA, const b2Shape* shapeB,\r
+ const b2Transform& xfA, const b2Transform& xfB)\r
+{\r
+ b2DistanceInput input;\r
+ input.proxyA.Set(shapeA);\r
+ input.proxyB.Set(shapeB);\r
+ input.transformA = xfA;\r
+ input.transformB = xfB;\r
+ input.useRadii = true;\r
+\r
+ b2SimplexCache cache;\r
+ cache.count = 0;\r
+\r
+ b2DistanceOutput output;\r
+\r
+ b2Distance(&output, &cache, &input);\r
+\r
+ return output.distance < 10.0f * b2_epsilon;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_COLLISION_H\r
+#define B2_COLLISION_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <climits>\r
+\r
+/// @file\r
+/// Structures and functions used for computing contact points, distance\r
+/// queries, and TOI queries.\r
+\r
+class b2Shape;\r
+class b2CircleShape;\r
+class b2PolygonShape;\r
+\r
+const uint8 b2_nullFeature = UCHAR_MAX;\r
+\r
+/// Contact ids to facilitate warm starting.\r
+union b2ContactID\r
+{\r
+ /// The features that intersect to form the contact point\r
+ struct Features\r
+ {\r
+ uint8 referenceEdge; ///< The edge that defines the outward contact normal.\r
+ uint8 incidentEdge; ///< The edge most anti-parallel to the reference edge.\r
+ uint8 incidentVertex; ///< The vertex (0 or 1) on the incident edge that was clipped.\r
+ uint8 flip; ///< A value of 1 indicates that the reference edge is on shape2.\r
+ } features;\r
+ uint32 key; ///< Used to quickly compare contact ids.\r
+};\r
+\r
+/// A manifold point is a contact point belonging to a contact\r
+/// manifold. It holds details related to the geometry and dynamics\r
+/// of the contact points.\r
+/// The local point usage depends on the manifold type:\r
+/// -e_circles: the local center of circleB\r
+/// -e_faceA: the local center of cirlceB or the clip point of polygonB\r
+/// -e_faceB: the clip point of polygonA\r
+/// This structure is stored across time steps, so we keep it small.\r
+/// Note: the impulses are used for internal caching and may not\r
+/// provide reliable contact forces, especially for high speed collisions.\r
+struct b2ManifoldPoint\r
+{\r
+ b2Vec2 localPoint; ///< usage depends on manifold type\r
+ float32 normalImpulse; ///< the non-penetration impulse\r
+ float32 tangentImpulse; ///< the friction impulse\r
+ b2ContactID id; ///< uniquely identifies a contact point between two shapes\r
+};\r
+\r
+/// A manifold for two touching convex shapes.\r
+/// Box2D supports multiple types of contact:\r
+/// - clip point versus plane with radius\r
+/// - point versus point with radius (circles)\r
+/// The local point usage depends on the manifold type:\r
+/// -e_circles: the local center of circleA\r
+/// -e_faceA: the center of faceA\r
+/// -e_faceB: the center of faceB\r
+/// Similarly the local normal usage:\r
+/// -e_circles: not used\r
+/// -e_faceA: the normal on polygonA\r
+/// -e_faceB: the normal on polygonB\r
+/// We store contacts in this way so that position correction can\r
+/// account for movement, which is critical for continuous physics.\r
+/// All contact scenarios must be expressed in one of these types.\r
+/// This structure is stored across time steps, so we keep it small.\r
+struct b2Manifold\r
+{\r
+ enum Type\r
+ {\r
+ e_circles,\r
+ e_faceA,\r
+ e_faceB\r
+ };\r
+\r
+ b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact\r
+ b2Vec2 localNormal; ///< not use for Type::e_points\r
+ b2Vec2 localPoint; ///< usage depends on manifold type\r
+ Type type;\r
+ int32 pointCount; ///< the number of manifold points\r
+};\r
+\r
+/// This is used to compute the current state of a contact manifold.\r
+struct b2WorldManifold\r
+{\r
+ /// Evaluate the manifold with supplied transforms. This assumes\r
+ /// modest motion from the original state. This does not change the\r
+ /// point count, impulses, etc. The radii must come from the shapes\r
+ /// that generated the manifold.\r
+ void Initialize(const b2Manifold* manifold,\r
+ const b2Transform& xfA, float32 radiusA,\r
+ const b2Transform& xfB, float32 radiusB);\r
+\r
+ b2Vec2 normal; ///< world vector pointing from A to B\r
+ b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)\r
+};\r
+\r
+/// This is used for determining the state of contact points.\r
+enum b2PointState\r
+{\r
+ b2_nullState, ///< point does not exist\r
+ b2_addState, ///< point was added in the update\r
+ b2_persistState, ///< point persisted across the update\r
+ b2_removeState ///< point was removed in the update\r
+};\r
+\r
+/// Compute the point states given two manifolds. The states pertain to the transition from manifold1\r
+/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.\r
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],\r
+ const b2Manifold* manifold1, const b2Manifold* manifold2);\r
+\r
+/// Used for computing contact manifolds.\r
+struct b2ClipVertex\r
+{\r
+ b2Vec2 v;\r
+ b2ContactID id;\r
+};\r
+\r
+/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).\r
+struct b2RayCastInput\r
+{\r
+ b2Vec2 p1, p2;\r
+ float32 maxFraction;\r
+};\r
+\r
+/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2\r
+/// come from b2RayCastInput.\r
+struct b2RayCastOutput\r
+{\r
+ b2Vec2 normal;\r
+ float32 fraction;\r
+};\r
+\r
+/// An axis aligned bounding box.\r
+struct b2AABB\r
+{\r
+ /// Verify that the bounds are sorted.\r
+ bool IsValid() const;\r
+\r
+ /// Get the center of the AABB.\r
+ b2Vec2 GetCenter() const\r
+ {\r
+ return 0.5f * (lowerBound + upperBound);\r
+ }\r
+\r
+ /// Get the extents of the AABB (half-widths).\r
+ b2Vec2 GetExtents() const\r
+ {\r
+ return 0.5f * (upperBound - lowerBound);\r
+ }\r
+\r
+ /// Combine two AABBs into this one.\r
+ void Combine(const b2AABB& aabb1, const b2AABB& aabb2)\r
+ {\r
+ lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);\r
+ upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);\r
+ }\r
+\r
+ /// Does this aabb contain the provided AABB.\r
+ bool Contains(const b2AABB& aabb) const\r
+ {\r
+ bool result = true;\r
+ result = result && lowerBound.x <= aabb.lowerBound.x;\r
+ result = result && lowerBound.y <= aabb.lowerBound.y;\r
+ result = result && aabb.upperBound.x <= upperBound.x;\r
+ result = result && aabb.upperBound.y <= upperBound.y;\r
+ return result;\r
+ }\r
+\r
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;\r
+\r
+ b2Vec2 lowerBound; ///< the lower vertex\r
+ b2Vec2 upperBound; ///< the upper vertex\r
+};\r
+\r
+/// Compute the collision manifold between two circles.\r
+void b2CollideCircles(b2Manifold* manifold,\r
+ const b2CircleShape* circle1, const b2Transform& xf1,\r
+ const b2CircleShape* circle2, const b2Transform& xf2);\r
+\r
+/// Compute the collision manifold between a polygon and a circle.\r
+void b2CollidePolygonAndCircle(b2Manifold* manifold,\r
+ const b2PolygonShape* polygon, const b2Transform& xf1,\r
+ const b2CircleShape* circle, const b2Transform& xf2);\r
+\r
+/// Compute the collision manifold between two polygons.\r
+void b2CollidePolygons(b2Manifold* manifold,\r
+ const b2PolygonShape* polygon1, const b2Transform& xf1,\r
+ const b2PolygonShape* polygon2, const b2Transform& xf2);\r
+\r
+/// Clipping for contact manifolds.\r
+int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],\r
+ const b2Vec2& normal, float32 offset);\r
+\r
+/// Determine if two generic shapes overlap.\r
+bool b2TestOverlap(const b2Shape* shapeA, const b2Shape* shapeB,\r
+ const b2Transform& xfA, const b2Transform& xfB);\r
+\r
+// ---------------- Inline Functions ------------------------------------------\r
+\r
+inline bool b2AABB::IsValid() const\r
+{\r
+ b2Vec2 d = upperBound - lowerBound;\r
+ bool valid = d.x >= 0.0f && d.y >= 0.0f;\r
+ valid = valid && lowerBound.IsValid() && upperBound.IsValid();\r
+ return valid;\r
+}\r
+\r
+inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)\r
+{\r
+ b2Vec2 d1, d2;\r
+ d1 = b.lowerBound - a.upperBound;\r
+ d2 = a.lowerBound - b.upperBound;\r
+\r
+ if (d1.x > 0.0f || d1.y > 0.0f)\r
+ return false;\r
+\r
+ if (d2.x > 0.0f || d2.y > 0.0f)\r
+ return false;\r
+\r
+ return true;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2Distance.h>\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+\r
+// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.\r
+int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;\r
+\r
+void b2DistanceProxy::Set(const b2Shape* shape)\r
+{\r
+ switch (shape->GetType())\r
+ {\r
+ case b2Shape::e_circle:\r
+ {\r
+ const b2CircleShape* circle = (b2CircleShape*)shape;\r
+ m_vertices = &circle->m_p;\r
+ m_count = 1;\r
+ m_radius = circle->m_radius;\r
+ }\r
+ break;\r
+\r
+ case b2Shape::e_polygon:\r
+ {\r
+ const b2PolygonShape* polygon = (b2PolygonShape*)shape;\r
+ m_vertices = polygon->m_vertices;\r
+ m_count = polygon->m_vertexCount;\r
+ m_radius = polygon->m_radius;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ }\r
+}\r
+\r
+\r
+struct b2SimplexVertex\r
+{\r
+ b2Vec2 wA; // support point in proxyA\r
+ b2Vec2 wB; // support point in proxyB\r
+ b2Vec2 w; // wB - wA\r
+ float32 a; // barycentric coordinate for closest point\r
+ int32 indexA; // wA index\r
+ int32 indexB; // wB index\r
+};\r
+\r
+struct b2Simplex\r
+{\r
+ void ReadCache( const b2SimplexCache* cache,\r
+ const b2DistanceProxy* proxyA, const b2Transform& transformA,\r
+ const b2DistanceProxy* proxyB, const b2Transform& transformB)\r
+ {\r
+ b2Assert(cache->count <= 3);\r
+ \r
+ // Copy data from cache.\r
+ m_count = cache->count;\r
+ b2SimplexVertex* vertices = &m_v1;\r
+ for (int32 i = 0; i < m_count; ++i)\r
+ {\r
+ b2SimplexVertex* v = vertices + i;\r
+ v->indexA = cache->indexA[i];\r
+ v->indexB = cache->indexB[i];\r
+ b2Vec2 wALocal = proxyA->GetVertex(v->indexA);\r
+ b2Vec2 wBLocal = proxyB->GetVertex(v->indexB);\r
+ v->wA = b2Mul(transformA, wALocal);\r
+ v->wB = b2Mul(transformB, wBLocal);\r
+ v->w = v->wB - v->wA;\r
+ v->a = 0.0f;\r
+ }\r
+\r
+ // Compute the new simplex metric, if it is substantially different than\r
+ // old metric then flush the simplex.\r
+ if (m_count > 1)\r
+ {\r
+ float32 metric1 = cache->metric;\r
+ float32 metric2 = GetMetric();\r
+ if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon)\r
+ {\r
+ // Reset the simplex.\r
+ m_count = 0;\r
+ }\r
+ }\r
+\r
+ // If the cache is empty or invalid ...\r
+ if (m_count == 0)\r
+ {\r
+ b2SimplexVertex* v = vertices + 0;\r
+ v->indexA = 0;\r
+ v->indexB = 0;\r
+ b2Vec2 wALocal = proxyA->GetVertex(0);\r
+ b2Vec2 wBLocal = proxyB->GetVertex(0);\r
+ v->wA = b2Mul(transformA, wALocal);\r
+ v->wB = b2Mul(transformB, wBLocal);\r
+ v->w = v->wB - v->wA;\r
+ m_count = 1;\r
+ }\r
+ }\r
+\r
+ void WriteCache(b2SimplexCache* cache) const\r
+ {\r
+ cache->metric = GetMetric();\r
+ cache->count = uint16(m_count);\r
+ const b2SimplexVertex* vertices = &m_v1;\r
+ for (int32 i = 0; i < m_count; ++i)\r
+ {\r
+ cache->indexA[i] = uint8(vertices[i].indexA);\r
+ cache->indexB[i] = uint8(vertices[i].indexB);\r
+ }\r
+ }\r
+\r
+ b2Vec2 GetSearchDirection() const\r
+ {\r
+ switch (m_count)\r
+ {\r
+ case 1:\r
+ return -m_v1.w;\r
+\r
+ case 2:\r
+ {\r
+ b2Vec2 e12 = m_v2.w - m_v1.w;\r
+ float32 sgn = b2Cross(e12, -m_v1.w);\r
+ if (sgn > 0.0f)\r
+ {\r
+ // Origin is left of e12.\r
+ return b2Cross(1.0f, e12);\r
+ }\r
+ else\r
+ {\r
+ // Origin is right of e12.\r
+ return b2Cross(e12, 1.0f);\r
+ }\r
+ }\r
+\r
+ default:\r
+ b2Assert(false);\r
+ return b2Vec2_zero;\r
+ }\r
+ }\r
+\r
+ b2Vec2 GetClosestPoint() const\r
+ {\r
+ switch (m_count)\r
+ {\r
+ case 0:\r
+ b2Assert(false);\r
+ return b2Vec2_zero;\r
+\r
+ case 1:\r
+ return m_v1.w;\r
+\r
+ case 2:\r
+ return m_v1.a * m_v1.w + m_v2.a * m_v2.w;\r
+\r
+ case 3:\r
+ return b2Vec2_zero;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ return b2Vec2_zero;\r
+ }\r
+ }\r
+\r
+ void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const\r
+ {\r
+ switch (m_count)\r
+ {\r
+ case 0:\r
+ b2Assert(false);\r
+ break;\r
+\r
+ case 1:\r
+ *pA = m_v1.wA;\r
+ *pB = m_v1.wB;\r
+ break;\r
+\r
+ case 2:\r
+ *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA;\r
+ *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB;\r
+ break;\r
+\r
+ case 3:\r
+ *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;\r
+ *pB = *pA;\r
+ break;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ break;\r
+ }\r
+ }\r
+\r
+ float32 GetMetric() const\r
+ {\r
+ switch (m_count)\r
+ {\r
+ case 0:\r
+ b2Assert(false);\r
+ return 0.0;\r
+\r
+ case 1:\r
+ return 0.0f;\r
+\r
+ case 2:\r
+ return b2Distance(m_v1.w, m_v2.w);\r
+\r
+ case 3:\r
+ return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w);\r
+\r
+ default:\r
+ b2Assert(false);\r
+ return 0.0f;\r
+ }\r
+ }\r
+\r
+ void Solve2();\r
+ void Solve3();\r
+\r
+ b2SimplexVertex m_v1, m_v2, m_v3;\r
+ int32 m_count;\r
+};\r
+\r
+\r
+// Solve a line segment using barycentric coordinates.\r
+//\r
+// p = a1 * w1 + a2 * w2\r
+// a1 + a2 = 1\r
+//\r
+// The vector from the origin to the closest point on the line is\r
+// perpendicular to the line.\r
+// e12 = w2 - w1\r
+// dot(p, e) = 0\r
+// a1 * dot(w1, e) + a2 * dot(w2, e) = 0\r
+//\r
+// 2-by-2 linear system\r
+// [1 1 ][a1] = [1]\r
+// [w1.e12 w2.e12][a2] = [0]\r
+//\r
+// Define\r
+// d12_1 = dot(w2, e12)\r
+// d12_2 = -dot(w1, e12)\r
+// d12 = d12_1 + d12_2\r
+//\r
+// Solution\r
+// a1 = d12_1 / d12\r
+// a2 = d12_2 / d12\r
+void b2Simplex::Solve2()\r
+{\r
+ b2Vec2 w1 = m_v1.w;\r
+ b2Vec2 w2 = m_v2.w;\r
+ b2Vec2 e12 = w2 - w1;\r
+\r
+ // w1 region\r
+ float32 d12_2 = -b2Dot(w1, e12);\r
+ if (d12_2 <= 0.0f)\r
+ {\r
+ // a2 <= 0, so we clamp it to 0\r
+ m_v1.a = 1.0f;\r
+ m_count = 1;\r
+ return;\r
+ }\r
+\r
+ // w2 region\r
+ float32 d12_1 = b2Dot(w2, e12);\r
+ if (d12_1 <= 0.0f)\r
+ {\r
+ // a1 <= 0, so we clamp it to 0\r
+ m_v2.a = 1.0f;\r
+ m_count = 1;\r
+ m_v1 = m_v2;\r
+ return;\r
+ }\r
+\r
+ // Must be in e12 region.\r
+ float32 inv_d12 = 1.0f / (d12_1 + d12_2);\r
+ m_v1.a = d12_1 * inv_d12;\r
+ m_v2.a = d12_2 * inv_d12;\r
+ m_count = 2;\r
+}\r
+\r
+// Possible regions:\r
+// - points[2]\r
+// - edge points[0]-points[2]\r
+// - edge points[1]-points[2]\r
+// - inside the triangle\r
+void b2Simplex::Solve3()\r
+{\r
+ b2Vec2 w1 = m_v1.w;\r
+ b2Vec2 w2 = m_v2.w;\r
+ b2Vec2 w3 = m_v3.w;\r
+\r
+ // Edge12\r
+ // [1 1 ][a1] = [1]\r
+ // [w1.e12 w2.e12][a2] = [0]\r
+ // a3 = 0\r
+ b2Vec2 e12 = w2 - w1;\r
+ float32 w1e12 = b2Dot(w1, e12);\r
+ float32 w2e12 = b2Dot(w2, e12);\r
+ float32 d12_1 = w2e12;\r
+ float32 d12_2 = -w1e12;\r
+\r
+ // Edge13\r
+ // [1 1 ][a1] = [1]\r
+ // [w1.e13 w3.e13][a3] = [0]\r
+ // a2 = 0\r
+ b2Vec2 e13 = w3 - w1;\r
+ float32 w1e13 = b2Dot(w1, e13);\r
+ float32 w3e13 = b2Dot(w3, e13);\r
+ float32 d13_1 = w3e13;\r
+ float32 d13_2 = -w1e13;\r
+\r
+ // Edge23\r
+ // [1 1 ][a2] = [1]\r
+ // [w2.e23 w3.e23][a3] = [0]\r
+ // a1 = 0\r
+ b2Vec2 e23 = w3 - w2;\r
+ float32 w2e23 = b2Dot(w2, e23);\r
+ float32 w3e23 = b2Dot(w3, e23);\r
+ float32 d23_1 = w3e23;\r
+ float32 d23_2 = -w2e23;\r
+ \r
+ // Triangle123\r
+ float32 n123 = b2Cross(e12, e13);\r
+\r
+ float32 d123_1 = n123 * b2Cross(w2, w3);\r
+ float32 d123_2 = n123 * b2Cross(w3, w1);\r
+ float32 d123_3 = n123 * b2Cross(w1, w2);\r
+\r
+ // w1 region\r
+ if (d12_2 <= 0.0f && d13_2 <= 0.0f)\r
+ {\r
+ m_v1.a = 1.0f;\r
+ m_count = 1;\r
+ return;\r
+ }\r
+\r
+ // e12\r
+ if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)\r
+ {\r
+ float32 inv_d12 = 1.0f / (d12_1 + d12_2);\r
+ m_v1.a = d12_1 * inv_d12;\r
+ m_v2.a = d12_2 * inv_d12;\r
+ m_count = 2;\r
+ return;\r
+ }\r
+\r
+ // e13\r
+ if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)\r
+ {\r
+ float32 inv_d13 = 1.0f / (d13_1 + d13_2);\r
+ m_v1.a = d13_1 * inv_d13;\r
+ m_v3.a = d13_2 * inv_d13;\r
+ m_count = 2;\r
+ m_v2 = m_v3;\r
+ return;\r
+ }\r
+\r
+ // w2 region\r
+ if (d12_1 <= 0.0f && d23_2 <= 0.0f)\r
+ {\r
+ m_v2.a = 1.0f;\r
+ m_count = 1;\r
+ m_v1 = m_v2;\r
+ return;\r
+ }\r
+\r
+ // w3 region\r
+ if (d13_1 <= 0.0f && d23_1 <= 0.0f)\r
+ {\r
+ m_v3.a = 1.0f;\r
+ m_count = 1;\r
+ m_v1 = m_v3;\r
+ return;\r
+ }\r
+\r
+ // e23\r
+ if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)\r
+ {\r
+ float32 inv_d23 = 1.0f / (d23_1 + d23_2);\r
+ m_v2.a = d23_1 * inv_d23;\r
+ m_v3.a = d23_2 * inv_d23;\r
+ m_count = 2;\r
+ m_v1 = m_v3;\r
+ return;\r
+ }\r
+\r
+ // Must be in triangle123\r
+ float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);\r
+ m_v1.a = d123_1 * inv_d123;\r
+ m_v2.a = d123_2 * inv_d123;\r
+ m_v3.a = d123_3 * inv_d123;\r
+ m_count = 3;\r
+}\r
+\r
+void b2Distance(b2DistanceOutput* output,\r
+ b2SimplexCache* cache,\r
+ const b2DistanceInput* input)\r
+{\r
+ ++b2_gjkCalls;\r
+\r
+ const b2DistanceProxy* proxyA = &input->proxyA;\r
+ const b2DistanceProxy* proxyB = &input->proxyB;\r
+\r
+ b2Transform transformA = input->transformA;\r
+ b2Transform transformB = input->transformB;\r
+\r
+ // Initialize the simplex.\r
+ b2Simplex simplex;\r
+ simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB);\r
+\r
+ // Get simplex vertices as an array.\r
+ b2SimplexVertex* vertices = &simplex.m_v1;\r
+ const int32 k_maxIters = 20;\r
+\r
+ // These store the vertices of the last simplex so that we\r
+ // can check for duplicates and prevent cycling.\r
+ int32 saveA[3], saveB[3];\r
+ int32 saveCount = 0;\r
+\r
+ b2Vec2 closestPoint = simplex.GetClosestPoint();\r
+ float32 distanceSqr1 = closestPoint.LengthSquared();\r
+ float32 distanceSqr2 = distanceSqr1;\r
+\r
+ // Main iteration loop.\r
+ int32 iter = 0;\r
+ while (iter < k_maxIters)\r
+ {\r
+ // Copy simplex so we can identify duplicates.\r
+ saveCount = simplex.m_count;\r
+ for (int32 i = 0; i < saveCount; ++i)\r
+ {\r
+ saveA[i] = vertices[i].indexA;\r
+ saveB[i] = vertices[i].indexB;\r
+ }\r
+\r
+ switch (simplex.m_count)\r
+ {\r
+ case 1:\r
+ break;\r
+\r
+ case 2:\r
+ simplex.Solve2();\r
+ break;\r
+\r
+ case 3:\r
+ simplex.Solve3();\r
+ break;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ }\r
+\r
+ // If we have 3 points, then the origin is in the corresponding triangle.\r
+ if (simplex.m_count == 3)\r
+ {\r
+ break;\r
+ }\r
+\r
+ // Compute closest point.\r
+ b2Vec2 p = simplex.GetClosestPoint();\r
+ distanceSqr2 = p.LengthSquared();\r
+\r
+ // Ensure progress\r
+ if (distanceSqr2 >= distanceSqr1)\r
+ {\r
+ //break;\r
+ }\r
+ distanceSqr1 = distanceSqr2;\r
+\r
+ // Get search direction.\r
+ b2Vec2 d = simplex.GetSearchDirection();\r
+\r
+ // Ensure the search direction is numerically fit.\r
+ if (d.LengthSquared() < b2_epsilon * b2_epsilon)\r
+ {\r
+ // The origin is probably contained by a line segment\r
+ // or triangle. Thus the shapes are overlapped.\r
+\r
+ // We can't return zero here even though there may be overlap.\r
+ // In case the simplex is a point, segment, or triangle it is difficult\r
+ // to determine if the origin is contained in the CSO or very close to it.\r
+ break;\r
+ }\r
+\r
+ // Compute a tentative new simplex vertex using support points.\r
+ b2SimplexVertex* vertex = vertices + simplex.m_count;\r
+ vertex->indexA = proxyA->GetSupport(b2MulT(transformA.R, -d));\r
+ vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA));\r
+ b2Vec2 wBLocal;\r
+ vertex->indexB = proxyB->GetSupport(b2MulT(transformB.R, d));\r
+ vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB));\r
+ vertex->w = vertex->wB - vertex->wA;\r
+\r
+ // Iteration count is equated to the number of support point calls.\r
+ ++iter;\r
+ ++b2_gjkIters;\r
+\r
+ // Check for duplicate support points. This is the main termination criteria.\r
+ bool duplicate = false;\r
+ for (int32 i = 0; i < saveCount; ++i)\r
+ {\r
+ if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i])\r
+ {\r
+ duplicate = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ // If we found a duplicate support point we must exit to avoid cycling.\r
+ if (duplicate)\r
+ {\r
+ break;\r
+ }\r
+\r
+ // New vertex is ok and needed.\r
+ ++simplex.m_count;\r
+ }\r
+\r
+ b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter);\r
+\r
+ // Prepare output.\r
+ simplex.GetWitnessPoints(&output->pointA, &output->pointB);\r
+ output->distance = b2Distance(output->pointA, output->pointB);\r
+ output->iterations = iter;\r
+\r
+ // Cache the simplex.\r
+ simplex.WriteCache(cache);\r
+\r
+ // Apply radii if requested.\r
+ if (input->useRadii)\r
+ {\r
+ float32 rA = proxyA->m_radius;\r
+ float32 rB = proxyB->m_radius;\r
+\r
+ if (output->distance > rA + rB && output->distance > b2_epsilon)\r
+ {\r
+ // Shapes are still no overlapped.\r
+ // Move the witness points to the outer surface.\r
+ output->distance -= rA + rB;\r
+ b2Vec2 normal = output->pointB - output->pointA;\r
+ normal.Normalize();\r
+ output->pointA += rA * normal;\r
+ output->pointB -= rB * normal;\r
+ }\r
+ else\r
+ {\r
+ // Shapes are overlapped when radii are considered.\r
+ // Move the witness points to the middle.\r
+ b2Vec2 p = 0.5f * (output->pointA + output->pointB);\r
+ output->pointA = p;\r
+ output->pointB = p;\r
+ output->distance = 0.0f;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+\r
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_DISTANCE_H\r
+#define B2_DISTANCE_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <climits>\r
+\r
+class b2Shape;\r
+\r
+/// A distance proxy is used by the GJK algorithm.\r
+/// It encapsulates any shape.\r
+struct b2DistanceProxy\r
+{\r
+ b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}\r
+\r
+ /// Initialize the proxy using the given shape. The shape\r
+ /// must remain in scope while the proxy is in use.\r
+ void Set(const b2Shape* shape);\r
+\r
+ /// Get the supporting vertex index in the given direction.\r
+ int32 GetSupport(const b2Vec2& d) const;\r
+\r
+ /// Get the supporting vertex in the given direction.\r
+ const b2Vec2& GetSupportVertex(const b2Vec2& d) const;\r
+\r
+ /// Get the vertex count.\r
+ int32 GetVertexCount() const;\r
+\r
+ /// Get a vertex by index. Used by b2Distance.\r
+ const b2Vec2& GetVertex(int32 index) const;\r
+\r
+ const b2Vec2* m_vertices;\r
+ int32 m_count;\r
+ float32 m_radius;\r
+};\r
+\r
+/// Used to warm start b2Distance.\r
+/// Set count to zero on first call.\r
+struct b2SimplexCache\r
+{\r
+ float32 metric; ///< length or area\r
+ uint16 count;\r
+ uint8 indexA[3]; ///< vertices on shape A\r
+ uint8 indexB[3]; ///< vertices on shape B\r
+};\r
+\r
+/// Input for b2Distance.\r
+/// You have to option to use the shape radii\r
+/// in the computation. Even \r
+struct b2DistanceInput\r
+{\r
+ b2DistanceProxy proxyA;\r
+ b2DistanceProxy proxyB;\r
+ b2Transform transformA;\r
+ b2Transform transformB;\r
+ bool useRadii;\r
+};\r
+\r
+/// Output for b2Distance.\r
+struct b2DistanceOutput\r
+{\r
+ b2Vec2 pointA; ///< closest point on shapeA\r
+ b2Vec2 pointB; ///< closest point on shapeB\r
+ float32 distance;\r
+ int32 iterations; ///< number of GJK iterations used\r
+};\r
+\r
+/// Compute the closest points between two shapes. Supports any combination of:\r
+/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.\r
+/// On the first call set b2SimplexCache.count to zero.\r
+void b2Distance(b2DistanceOutput* output,\r
+ b2SimplexCache* cache, \r
+ const b2DistanceInput* input);\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////\r
+\r
+inline int32 b2DistanceProxy::GetVertexCount() const\r
+{\r
+ return m_count;\r
+}\r
+\r
+inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const\r
+{\r
+ b2Assert(0 <= index && index < m_count);\r
+ return m_vertices[index];\r
+}\r
+\r
+inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const\r
+{\r
+ int32 bestIndex = 0;\r
+ float32 bestValue = b2Dot(m_vertices[0], d);\r
+ for (int32 i = 1; i < m_count; ++i)\r
+ {\r
+ float32 value = b2Dot(m_vertices[i], d);\r
+ if (value > bestValue)\r
+ {\r
+ bestIndex = i;\r
+ bestValue = value;\r
+ }\r
+ }\r
+\r
+ return bestIndex;\r
+}\r
+\r
+inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const\r
+{\r
+ int32 bestIndex = 0;\r
+ float32 bestValue = b2Dot(m_vertices[0], d);\r
+ for (int32 i = 1; i < m_count; ++i)\r
+ {\r
+ float32 value = b2Dot(m_vertices[i], d);\r
+ if (value > bestValue)\r
+ {\r
+ bestIndex = i;\r
+ bestValue = value;\r
+ }\r
+ }\r
+\r
+ return m_vertices[bestIndex];\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2DynamicTree.h>\r
+#include <cstring>\r
+#include <cfloat>\r
+\r
+b2DynamicTree::b2DynamicTree()\r
+{\r
+ m_root = b2_nullNode;\r
+\r
+ m_nodeCapacity = 16;\r
+ m_nodeCount = 0;\r
+ m_nodes = (b2DynamicTreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2DynamicTreeNode));\r
+ memset(m_nodes, 0, m_nodeCapacity * sizeof(b2DynamicTreeNode));\r
+\r
+ // Build a linked list for the free list.\r
+ for (int32 i = 0; i < m_nodeCapacity - 1; ++i)\r
+ {\r
+ m_nodes[i].next = i + 1;\r
+ }\r
+ m_nodes[m_nodeCapacity-1].next = b2_nullNode;\r
+ m_freeList = 0;\r
+\r
+ m_path = 0;\r
+\r
+ m_insertionCount = 0;\r
+}\r
+\r
+b2DynamicTree::~b2DynamicTree()\r
+{\r
+ // This frees the entire tree in one shot.\r
+ b2Free(m_nodes);\r
+}\r
+\r
+// Allocate a node from the pool. Grow the pool if necessary.\r
+int32 b2DynamicTree::AllocateNode()\r
+{\r
+ // Expand the node pool as needed.\r
+ if (m_freeList == b2_nullNode)\r
+ {\r
+ b2Assert(m_nodeCount == m_nodeCapacity);\r
+\r
+ // The free list is empty. Rebuild a bigger pool.\r
+ b2DynamicTreeNode* oldNodes = m_nodes;\r
+ m_nodeCapacity *= 2;\r
+ m_nodes = (b2DynamicTreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2DynamicTreeNode));\r
+ memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2DynamicTreeNode));\r
+ b2Free(oldNodes);\r
+\r
+ // Build a linked list for the free list. The parent\r
+ // pointer becomes the "next" pointer.\r
+ for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)\r
+ {\r
+ m_nodes[i].next = i + 1;\r
+ }\r
+ m_nodes[m_nodeCapacity-1].next = b2_nullNode;\r
+ m_freeList = m_nodeCount;\r
+ }\r
+\r
+ // Peel a node off the free list.\r
+ int32 nodeId = m_freeList;\r
+ m_freeList = m_nodes[nodeId].next;\r
+ m_nodes[nodeId].parent = b2_nullNode;\r
+ m_nodes[nodeId].child1 = b2_nullNode;\r
+ m_nodes[nodeId].child2 = b2_nullNode;\r
+ ++m_nodeCount;\r
+ return nodeId;\r
+}\r
+\r
+// Return a node to the pool.\r
+void b2DynamicTree::FreeNode(int32 nodeId)\r
+{\r
+ b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);\r
+ b2Assert(0 < m_nodeCount);\r
+ m_nodes[nodeId].next = m_freeList;\r
+ m_freeList = nodeId;\r
+ --m_nodeCount;\r
+}\r
+\r
+// Create a proxy in the tree as a leaf node. We return the index\r
+// of the node instead of a pointer so that we can grow\r
+// the node pool.\r
+int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData)\r
+{\r
+ int32 proxyId = AllocateNode();\r
+\r
+ // Fatten the aabb.\r
+ b2Vec2 r(b2_aabbExtension, b2_aabbExtension);\r
+ m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r;\r
+ m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r;\r
+ m_nodes[proxyId].userData = userData;\r
+\r
+ InsertLeaf(proxyId);\r
+\r
+ // Rebalance if necessary.\r
+ int32 iterationCount = m_nodeCount >> 4;\r
+ int32 tryCount = 0;\r
+ int32 height = ComputeHeight();\r
+ while (height > 64 && tryCount < 10)\r
+ {\r
+ Rebalance(iterationCount);\r
+ height = ComputeHeight();\r
+ ++tryCount;\r
+ }\r
+\r
+ return proxyId;\r
+}\r
+\r
+void b2DynamicTree::DestroyProxy(int32 proxyId)\r
+{\r
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);\r
+ b2Assert(m_nodes[proxyId].IsLeaf());\r
+\r
+ RemoveLeaf(proxyId);\r
+ FreeNode(proxyId);\r
+}\r
+\r
+bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)\r
+{\r
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);\r
+\r
+ b2Assert(m_nodes[proxyId].IsLeaf());\r
+\r
+ if (m_nodes[proxyId].aabb.Contains(aabb))\r
+ {\r
+ return false;\r
+ }\r
+\r
+ RemoveLeaf(proxyId);\r
+\r
+ // Extend AABB.\r
+ b2AABB b = aabb;\r
+ b2Vec2 r(b2_aabbExtension, b2_aabbExtension);\r
+ b.lowerBound = b.lowerBound - r;\r
+ b.upperBound = b.upperBound + r;\r
+\r
+ // Predict AABB displacement.\r
+ b2Vec2 d = b2_aabbMultiplier * displacement;\r
+\r
+ if (d.x < 0.0f)\r
+ {\r
+ b.lowerBound.x += d.x;\r
+ }\r
+ else\r
+ {\r
+ b.upperBound.x += d.x;\r
+ }\r
+\r
+ if (d.y < 0.0f)\r
+ {\r
+ b.lowerBound.y += d.y;\r
+ }\r
+ else\r
+ {\r
+ b.upperBound.y += d.y;\r
+ }\r
+\r
+ m_nodes[proxyId].aabb = b;\r
+\r
+ InsertLeaf(proxyId);\r
+ return true;\r
+}\r
+\r
+void b2DynamicTree::InsertLeaf(int32 leaf)\r
+{\r
+ ++m_insertionCount;\r
+\r
+ if (m_root == b2_nullNode)\r
+ {\r
+ m_root = leaf;\r
+ m_nodes[m_root].parent = b2_nullNode;\r
+ return;\r
+ }\r
+\r
+ // Find the best sibling for this node.\r
+ b2Vec2 center = m_nodes[leaf].aabb.GetCenter();\r
+ int32 sibling = m_root;\r
+ if (m_nodes[sibling].IsLeaf() == false)\r
+ {\r
+ do \r
+ {\r
+ int32 child1 = m_nodes[sibling].child1;\r
+ int32 child2 = m_nodes[sibling].child2;\r
+\r
+ b2Vec2 delta1 = b2Abs(m_nodes[child1].aabb.GetCenter() - center);\r
+ b2Vec2 delta2 = b2Abs(m_nodes[child2].aabb.GetCenter() - center);\r
+\r
+ float32 norm1 = delta1.x + delta1.y;\r
+ float32 norm2 = delta2.x + delta2.y;\r
+\r
+ if (norm1 < norm2)\r
+ {\r
+ sibling = child1;\r
+ }\r
+ else\r
+ {\r
+ sibling = child2;\r
+ }\r
+\r
+ }\r
+ while(m_nodes[sibling].IsLeaf() == false);\r
+ }\r
+\r
+ // Create a parent for the siblings.\r
+ int32 node1 = m_nodes[sibling].parent;\r
+ int32 node2 = AllocateNode();\r
+ m_nodes[node2].parent = node1;\r
+ m_nodes[node2].userData = NULL;\r
+ m_nodes[node2].aabb.Combine(m_nodes[leaf].aabb, m_nodes[sibling].aabb);\r
+\r
+ if (node1 != b2_nullNode)\r
+ {\r
+ if (m_nodes[m_nodes[sibling].parent].child1 == sibling)\r
+ {\r
+ m_nodes[node1].child1 = node2;\r
+ }\r
+ else\r
+ {\r
+ m_nodes[node1].child2 = node2;\r
+ }\r
+\r
+ m_nodes[node2].child1 = sibling;\r
+ m_nodes[node2].child2 = leaf;\r
+ m_nodes[sibling].parent = node2;\r
+ m_nodes[leaf].parent = node2;\r
+\r
+ do \r
+ {\r
+ if (m_nodes[node1].aabb.Contains(m_nodes[node2].aabb))\r
+ {\r
+ break;\r
+ }\r
+\r
+ m_nodes[node1].aabb.Combine(m_nodes[m_nodes[node1].child1].aabb, m_nodes[m_nodes[node1].child2].aabb);\r
+ node2 = node1;\r
+ node1 = m_nodes[node1].parent;\r
+ }\r
+ while(node1 != b2_nullNode);\r
+ }\r
+ else\r
+ {\r
+ m_nodes[node2].child1 = sibling;\r
+ m_nodes[node2].child2 = leaf;\r
+ m_nodes[sibling].parent = node2;\r
+ m_nodes[leaf].parent = node2;\r
+ m_root = node2;\r
+ }\r
+}\r
+\r
+void b2DynamicTree::RemoveLeaf(int32 leaf)\r
+{\r
+ if (leaf == m_root)\r
+ {\r
+ m_root = b2_nullNode;\r
+ return;\r
+ }\r
+\r
+ int32 node2 = m_nodes[leaf].parent;\r
+ int32 node1 = m_nodes[node2].parent;\r
+ int32 sibling;\r
+ if (m_nodes[node2].child1 == leaf)\r
+ {\r
+ sibling = m_nodes[node2].child2;\r
+ }\r
+ else\r
+ {\r
+ sibling = m_nodes[node2].child1;\r
+ }\r
+\r
+ if (node1 != b2_nullNode)\r
+ {\r
+ // Destroy node2 and connect node1 to sibling.\r
+ if (m_nodes[node1].child1 == node2)\r
+ {\r
+ m_nodes[node1].child1 = sibling;\r
+ }\r
+ else\r
+ {\r
+ m_nodes[node1].child2 = sibling;\r
+ }\r
+ m_nodes[sibling].parent = node1;\r
+ FreeNode(node2);\r
+\r
+ // Adjust ancestor bounds.\r
+ while (node1 != b2_nullNode)\r
+ {\r
+ b2AABB oldAABB = m_nodes[node1].aabb;\r
+ m_nodes[node1].aabb.Combine(m_nodes[m_nodes[node1].child1].aabb, m_nodes[m_nodes[node1].child2].aabb);\r
+\r
+ if (oldAABB.Contains(m_nodes[node1].aabb))\r
+ {\r
+ break;\r
+ }\r
+\r
+ node1 = m_nodes[node1].parent;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_root = sibling;\r
+ m_nodes[sibling].parent = b2_nullNode;\r
+ FreeNode(node2);\r
+ }\r
+}\r
+\r
+void b2DynamicTree::Rebalance(int32 iterations)\r
+{\r
+ if (m_root == b2_nullNode)\r
+ {\r
+ return;\r
+ }\r
+\r
+ for (int32 i = 0; i < iterations; ++i)\r
+ {\r
+ int32 node = m_root;\r
+\r
+ uint32 bit = 0;\r
+ while (m_nodes[node].IsLeaf() == false)\r
+ {\r
+ int32* children = &m_nodes[node].child1;\r
+ node = children[(m_path >> bit) & 1];\r
+ bit = (bit + 1) & (8* sizeof(uint32) - 1);\r
+ }\r
+ ++m_path;\r
+\r
+ RemoveLeaf(node);\r
+ InsertLeaf(node);\r
+ }\r
+}\r
+\r
+// Compute the height of a sub-tree.\r
+int32 b2DynamicTree::ComputeHeight(int32 nodeId) const\r
+{\r
+ if (nodeId == b2_nullNode)\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);\r
+ b2DynamicTreeNode* node = m_nodes + nodeId;\r
+ int32 height1 = ComputeHeight(node->child1);\r
+ int32 height2 = ComputeHeight(node->child2);\r
+ return 1 + b2Max(height1, height2);\r
+}\r
+\r
+int32 b2DynamicTree::ComputeHeight() const\r
+{\r
+ return ComputeHeight(m_root);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_DYNAMIC_TREE_H\r
+#define B2_DYNAMIC_TREE_H\r
+\r
+#include <Box2D/Collision/b2Collision.h>\r
+\r
+/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.\r
+\r
+#define b2_nullNode (-1)\r
+\r
+/// A node in the dynamic tree. The client does not interact with this directly.\r
+struct b2DynamicTreeNode\r
+{\r
+ bool IsLeaf() const\r
+ {\r
+ return child1 == b2_nullNode;\r
+ }\r
+\r
+ /// This is the fattened AABB.\r
+ b2AABB aabb;\r
+\r
+ //int32 userData;\r
+ void* userData;\r
+\r
+ union\r
+ {\r
+ int32 parent;\r
+ int32 next;\r
+ };\r
+\r
+ int32 child1;\r
+ int32 child2;\r
+};\r
+\r
+/// A dynamic tree arranges data in a binary tree to accelerate\r
+/// queries such as volume queries and ray casts. Leafs are proxies\r
+/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor\r
+/// so that the proxy AABB is bigger than the client object. This allows the client\r
+/// object to move by small amounts without triggering a tree update.\r
+///\r
+/// Nodes are pooled and relocatable, so we use node indices rather than pointers.\r
+class b2DynamicTree\r
+{\r
+public:\r
+\r
+ /// Constructing the tree initializes the node pool.\r
+ b2DynamicTree();\r
+\r
+ /// Destroy the tree, freeing the node pool.\r
+ ~b2DynamicTree();\r
+\r
+ /// Create a proxy. Provide a tight fitting AABB and a userData pointer.\r
+ int32 CreateProxy(const b2AABB& aabb, void* userData);\r
+\r
+ /// Destroy a proxy. This asserts if the id is invalid.\r
+ void DestroyProxy(int32 proxyId);\r
+\r
+ /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,\r
+ /// then the proxy is removed from the tree and re-inserted. Otherwise\r
+ /// the function returns immediately.\r
+ /// @return true if the proxy was re-inserted.\r
+ bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);\r
+\r
+ /// Perform some iterations to re-balance the tree.\r
+ void Rebalance(int32 iterations);\r
+\r
+ /// Get proxy user data.\r
+ /// @return the proxy user data or 0 if the id is invalid.\r
+ void* GetUserData(int32 proxyId) const;\r
+\r
+ /// Get the fat AABB for a proxy.\r
+ const b2AABB& GetFatAABB(int32 proxyId) const;\r
+\r
+ /// Compute the height of the tree.\r
+ int32 ComputeHeight() const;\r
+\r
+ /// Query an AABB for overlapping proxies. The callback class\r
+ /// is called for each proxy that overlaps the supplied AABB.\r
+ template <typename T>\r
+ void Query(T* callback, const b2AABB& aabb) const;\r
+\r
+ /// Ray-cast against the proxies in the tree. This relies on the callback\r
+ /// to perform a exact ray-cast in the case were the proxy contains a shape.\r
+ /// The callback also performs the any collision filtering. This has performance\r
+ /// roughly equal to k * log(n), where k is the number of collisions and n is the\r
+ /// number of proxies in the tree.\r
+ /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).\r
+ /// @param callback a callback class that is called for each proxy that is hit by the ray.\r
+ template <typename T>\r
+ void RayCast(T* callback, const b2RayCastInput& input) const;\r
+\r
+private:\r
+\r
+ int32 AllocateNode();\r
+ void FreeNode(int32 node);\r
+\r
+ void InsertLeaf(int32 node);\r
+ void RemoveLeaf(int32 node);\r
+\r
+ int32 ComputeHeight(int32 nodeId) const;\r
+\r
+ int32 m_root;\r
+\r
+ b2DynamicTreeNode* m_nodes;\r
+ int32 m_nodeCount;\r
+ int32 m_nodeCapacity;\r
+\r
+ int32 m_freeList;\r
+\r
+ /// This is used incrementally traverse the tree for re-balancing.\r
+ uint32 m_path;\r
+\r
+ int32 m_insertionCount;\r
+};\r
+\r
+inline void* b2DynamicTree::GetUserData(int32 proxyId) const\r
+{\r
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);\r
+ return m_nodes[proxyId].userData;\r
+}\r
+\r
+inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const\r
+{\r
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);\r
+ return m_nodes[proxyId].aabb;\r
+}\r
+\r
+template <typename T>\r
+inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const\r
+{\r
+ const int32 k_stackSize = 128;\r
+ int32 stack[k_stackSize];\r
+\r
+ int32 count = 0;\r
+ stack[count++] = m_root;\r
+\r
+ while (count > 0)\r
+ {\r
+ int32 nodeId = stack[--count];\r
+ if (nodeId == b2_nullNode)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ const b2DynamicTreeNode* node = m_nodes + nodeId;\r
+\r
+ if (b2TestOverlap(node->aabb, aabb))\r
+ {\r
+ if (node->IsLeaf())\r
+ {\r
+ bool proceed = callback->QueryCallback(nodeId);\r
+ if (proceed == false)\r
+ {\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (count < k_stackSize)\r
+ {\r
+ stack[count++] = node->child1;\r
+ }\r
+\r
+ if (count < k_stackSize)\r
+ {\r
+ stack[count++] = node->child2;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+template <typename T>\r
+inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const\r
+{\r
+ b2Vec2 p1 = input.p1;\r
+ b2Vec2 p2 = input.p2;\r
+ b2Vec2 r = p2 - p1;\r
+ b2Assert(r.LengthSquared() > 0.0f);\r
+ r.Normalize();\r
+\r
+ // v is perpendicular to the segment.\r
+ b2Vec2 v = b2Cross(1.0f, r);\r
+ b2Vec2 abs_v = b2Abs(v);\r
+\r
+ // Separating axis for segment (Gino, p80).\r
+ // |dot(v, p1 - c)| > dot(|v|, h)\r
+\r
+ float32 maxFraction = input.maxFraction;\r
+\r
+ // Build a bounding box for the segment.\r
+ b2AABB segmentAABB;\r
+ {\r
+ b2Vec2 t = p1 + maxFraction * (p2 - p1);\r
+ segmentAABB.lowerBound = b2Min(p1, t);\r
+ segmentAABB.upperBound = b2Max(p1, t);\r
+ }\r
+\r
+ const int32 k_stackSize = 128;\r
+ int32 stack[k_stackSize];\r
+\r
+ int32 count = 0;\r
+ stack[count++] = m_root;\r
+\r
+ while (count > 0)\r
+ {\r
+ int32 nodeId = stack[--count];\r
+ if (nodeId == b2_nullNode)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ const b2DynamicTreeNode* node = m_nodes + nodeId;\r
+\r
+ if (b2TestOverlap(node->aabb, segmentAABB) == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Separating axis for segment (Gino, p80).\r
+ // |dot(v, p1 - c)| > dot(|v|, h)\r
+ b2Vec2 c = node->aabb.GetCenter();\r
+ b2Vec2 h = node->aabb.GetExtents();\r
+ float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);\r
+ if (separation > 0.0f)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (node->IsLeaf())\r
+ {\r
+ b2RayCastInput subInput;\r
+ subInput.p1 = input.p1;\r
+ subInput.p2 = input.p2;\r
+ subInput.maxFraction = maxFraction;\r
+\r
+ float32 value = callback->RayCastCallback(subInput, nodeId);\r
+\r
+ if (value == 0.0f)\r
+ {\r
+ // The client has terminated the ray cast.\r
+ return;\r
+ }\r
+\r
+ if (value > 0.0f)\r
+ {\r
+ // Update segment bounding box.\r
+ maxFraction = value;\r
+ b2Vec2 t = p1 + maxFraction * (p2 - p1);\r
+ segmentAABB.lowerBound = b2Min(p1, t);\r
+ segmentAABB.upperBound = b2Max(p1, t);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (count < k_stackSize)\r
+ {\r
+ stack[count++] = node->child1;\r
+ }\r
+\r
+ if (count < k_stackSize)\r
+ {\r
+ stack[count++] = node->child2;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/b2Distance.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+\r
+#include <cstdio>\r
+\r
+int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;\r
+int32 b2_toiRootIters, b2_toiMaxRootIters;\r
+\r
+int32 b2_toiMaxOptIters;\r
+\r
+struct b2SeparationFunction\r
+{\r
+ enum Type\r
+ {\r
+ e_points,\r
+ e_faceA,\r
+ e_faceB\r
+ };\r
+\r
+ // TODO_ERIN might not need to return the separation\r
+\r
+ float32 Initialize(const b2SimplexCache* cache,\r
+ const b2DistanceProxy* proxyA, const b2Sweep& sweepA,\r
+ const b2DistanceProxy* proxyB, const b2Sweep& sweepB)\r
+ {\r
+ m_proxyA = proxyA;\r
+ m_proxyB = proxyB;\r
+ int32 count = cache->count;\r
+ b2Assert(0 < count && count < 3);\r
+\r
+ m_sweepA = sweepA;\r
+ m_sweepB = sweepB;\r
+\r
+ b2Transform xfA, xfB;\r
+ m_sweepA.GetTransform(&xfA, 0.0f);\r
+ m_sweepB.GetTransform(&xfB, 0.0f);\r
+\r
+ if (count == 1)\r
+ {\r
+ m_type = e_points;\r
+ b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]);\r
+ b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);\r
+ b2Vec2 pointA = b2Mul(xfA, localPointA);\r
+ b2Vec2 pointB = b2Mul(xfB, localPointB);\r
+ m_axis = pointB - pointA;\r
+ float32 s = m_axis.Normalize();\r
+ return s;\r
+ }\r
+ else if (cache->indexA[0] == cache->indexA[1])\r
+ {\r
+ // Two points on B and one on A.\r
+ m_type = e_faceB;\r
+ b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]);\r
+ b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]);\r
+\r
+ m_axis = b2Cross(localPointB2 - localPointB1, 1.0f);\r
+ m_axis.Normalize();\r
+ b2Vec2 normal = b2Mul(xfB.R, m_axis);\r
+\r
+ m_localPoint = 0.5f * (localPointB1 + localPointB2);\r
+ b2Vec2 pointB = b2Mul(xfB, m_localPoint);\r
+\r
+ b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]);\r
+ b2Vec2 pointA = b2Mul(xfA, localPointA);\r
+\r
+ float32 s = b2Dot(pointA - pointB, normal);\r
+ if (s < 0.0f)\r
+ {\r
+ m_axis = -m_axis;\r
+ s = -s;\r
+ }\r
+ return s;\r
+ }\r
+ else\r
+ {\r
+ // Two points on A and one or two points on B.\r
+ m_type = e_faceA;\r
+ b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]);\r
+ b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]);\r
+ \r
+ m_axis = b2Cross(localPointA2 - localPointA1, 1.0f);\r
+ m_axis.Normalize();\r
+ b2Vec2 normal = b2Mul(xfA.R, m_axis);\r
+\r
+ m_localPoint = 0.5f * (localPointA1 + localPointA2);\r
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);\r
+\r
+ b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);\r
+ b2Vec2 pointB = b2Mul(xfB, localPointB);\r
+\r
+ float32 s = b2Dot(pointB - pointA, normal);\r
+ if (s < 0.0f)\r
+ {\r
+ m_axis = -m_axis;\r
+ s = -s;\r
+ }\r
+ return s;\r
+ }\r
+ }\r
+\r
+ float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const\r
+ {\r
+ b2Transform xfA, xfB;\r
+ m_sweepA.GetTransform(&xfA, t);\r
+ m_sweepB.GetTransform(&xfB, t);\r
+\r
+ switch (m_type)\r
+ {\r
+ case e_points:\r
+ {\r
+ b2Vec2 axisA = b2MulT(xfA.R, m_axis);\r
+ b2Vec2 axisB = b2MulT(xfB.R, -m_axis);\r
+\r
+ *indexA = m_proxyA->GetSupport(axisA);\r
+ *indexB = m_proxyB->GetSupport(axisB);\r
+\r
+ b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);\r
+ b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);\r
+ \r
+ b2Vec2 pointA = b2Mul(xfA, localPointA);\r
+ b2Vec2 pointB = b2Mul(xfB, localPointB);\r
+\r
+ float32 separation = b2Dot(pointB - pointA, m_axis);\r
+ return separation;\r
+ }\r
+\r
+ case e_faceA:\r
+ {\r
+ b2Vec2 normal = b2Mul(xfA.R, m_axis);\r
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);\r
+\r
+ b2Vec2 axisB = b2MulT(xfB.R, -normal);\r
+ \r
+ *indexA = -1;\r
+ *indexB = m_proxyB->GetSupport(axisB);\r
+\r
+ b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);\r
+ b2Vec2 pointB = b2Mul(xfB, localPointB);\r
+\r
+ float32 separation = b2Dot(pointB - pointA, normal);\r
+ return separation;\r
+ }\r
+\r
+ case e_faceB:\r
+ {\r
+ b2Vec2 normal = b2Mul(xfB.R, m_axis);\r
+ b2Vec2 pointB = b2Mul(xfB, m_localPoint);\r
+\r
+ b2Vec2 axisA = b2MulT(xfA.R, -normal);\r
+\r
+ *indexB = -1;\r
+ *indexA = m_proxyA->GetSupport(axisA);\r
+\r
+ b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);\r
+ b2Vec2 pointA = b2Mul(xfA, localPointA);\r
+\r
+ float32 separation = b2Dot(pointA - pointB, normal);\r
+ return separation;\r
+ }\r
+\r
+ default:\r
+ b2Assert(false);\r
+ *indexA = -1;\r
+ *indexB = -1;\r
+ return 0.0f;\r
+ }\r
+ }\r
+\r
+ float32 Evaluate(int32 indexA, int32 indexB, float32 t) const\r
+ {\r
+ b2Transform xfA, xfB;\r
+ m_sweepA.GetTransform(&xfA, t);\r
+ m_sweepB.GetTransform(&xfB, t);\r
+\r
+ switch (m_type)\r
+ {\r
+ case e_points:\r
+ {\r
+ b2Vec2 axisA = b2MulT(xfA.R, m_axis);\r
+ b2Vec2 axisB = b2MulT(xfB.R, -m_axis);\r
+\r
+ b2Vec2 localPointA = m_proxyA->GetVertex(indexA);\r
+ b2Vec2 localPointB = m_proxyB->GetVertex(indexB);\r
+\r
+ b2Vec2 pointA = b2Mul(xfA, localPointA);\r
+ b2Vec2 pointB = b2Mul(xfB, localPointB);\r
+ float32 separation = b2Dot(pointB - pointA, m_axis);\r
+\r
+ return separation;\r
+ }\r
+\r
+ case e_faceA:\r
+ {\r
+ b2Vec2 normal = b2Mul(xfA.R, m_axis);\r
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);\r
+\r
+ b2Vec2 axisB = b2MulT(xfB.R, -normal);\r
+\r
+ b2Vec2 localPointB = m_proxyB->GetVertex(indexB);\r
+ b2Vec2 pointB = b2Mul(xfB, localPointB);\r
+\r
+ float32 separation = b2Dot(pointB - pointA, normal);\r
+ return separation;\r
+ }\r
+\r
+ case e_faceB:\r
+ {\r
+ b2Vec2 normal = b2Mul(xfB.R, m_axis);\r
+ b2Vec2 pointB = b2Mul(xfB, m_localPoint);\r
+\r
+ b2Vec2 axisA = b2MulT(xfA.R, -normal);\r
+\r
+ b2Vec2 localPointA = m_proxyA->GetVertex(indexA);\r
+ b2Vec2 pointA = b2Mul(xfA, localPointA);\r
+\r
+ float32 separation = b2Dot(pointA - pointB, normal);\r
+ return separation;\r
+ }\r
+\r
+ default:\r
+ b2Assert(false);\r
+ return 0.0f;\r
+ }\r
+ }\r
+\r
+ const b2DistanceProxy* m_proxyA;\r
+ const b2DistanceProxy* m_proxyB;\r
+ b2Sweep m_sweepA, m_sweepB;\r
+ Type m_type;\r
+ b2Vec2 m_localPoint;\r
+ b2Vec2 m_axis;\r
+};\r
+\r
+// CCD via the local separating axis method. This seeks progression\r
+// by computing the largest time at which separation is maintained.\r
+void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input)\r
+{\r
+ ++b2_toiCalls;\r
+\r
+ output->state = b2TOIOutput::e_unknown;\r
+ output->t = input->tMax;\r
+\r
+ const b2DistanceProxy* proxyA = &input->proxyA;\r
+ const b2DistanceProxy* proxyB = &input->proxyB;\r
+\r
+ b2Sweep sweepA = input->sweepA;\r
+ b2Sweep sweepB = input->sweepB;\r
+\r
+ // Large rotations can make the root finder fail, so we normalize the\r
+ // sweep angles.\r
+ sweepA.Normalize();\r
+ sweepB.Normalize();\r
+\r
+ float32 tMax = input->tMax;\r
+\r
+ float32 totalRadius = proxyA->m_radius + proxyB->m_radius;\r
+ float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop);\r
+ float32 tolerance = 0.25f * b2_linearSlop;\r
+ b2Assert(target > tolerance);\r
+\r
+ float32 t1 = 0.0f;\r
+ const int32 k_maxIterations = 20; // TODO_ERIN b2Settings\r
+ int32 iter = 0;\r
+\r
+ // Prepare input for distance query.\r
+ b2SimplexCache cache;\r
+ cache.count = 0;\r
+ b2DistanceInput distanceInput;\r
+ distanceInput.proxyA = input->proxyA;\r
+ distanceInput.proxyB = input->proxyB;\r
+ distanceInput.useRadii = false;\r
+\r
+ // The outer loop progressively attempts to compute new separating axes.\r
+ // This loop terminates when an axis is repeated (no progress is made).\r
+ for(;;)\r
+ {\r
+ b2Transform xfA, xfB;\r
+ sweepA.GetTransform(&xfA, t1);\r
+ sweepB.GetTransform(&xfB, t1);\r
+\r
+ // Get the distance between shapes. We can also use the results\r
+ // to get a separating axis.\r
+ distanceInput.transformA = xfA;\r
+ distanceInput.transformB = xfB;\r
+ b2DistanceOutput distanceOutput;\r
+ b2Distance(&distanceOutput, &cache, &distanceInput);\r
+\r
+ // If the shapes are overlapped, we give up on continuous collision.\r
+ if (distanceOutput.distance <= 0.0f)\r
+ {\r
+ // Failure!\r
+ output->state = b2TOIOutput::e_overlapped;\r
+ output->t = 0.0f;\r
+ break;\r
+ }\r
+\r
+ if (distanceOutput.distance < target + tolerance)\r
+ {\r
+ // Victory!\r
+ output->state = b2TOIOutput::e_touching;\r
+ output->t = t1;\r
+ break;\r
+ }\r
+\r
+ // Initialize the separating axis.\r
+ b2SeparationFunction fcn;\r
+ fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB);\r
+#if 0\r
+ // Dump the curve seen by the root finder\r
+ {\r
+ const int32 N = 100;\r
+ float32 dx = 1.0f / N;\r
+ float32 xs[N+1];\r
+ float32 fs[N+1];\r
+\r
+ float32 x = 0.0f;\r
+\r
+ for (int32 i = 0; i <= N; ++i)\r
+ {\r
+ sweepA.GetTransform(&xfA, x);\r
+ sweepB.GetTransform(&xfB, x);\r
+ float32 f = fcn.Evaluate(xfA, xfB) - target;\r
+\r
+ printf("%g %g\n", x, f);\r
+\r
+ xs[i] = x;\r
+ fs[i] = f;\r
+\r
+ x += dx;\r
+ }\r
+ }\r
+#endif\r
+\r
+ // Compute the TOI on the separating axis. We do this by successively\r
+ // resolving the deepest point. This loop is bounded by the number of vertices.\r
+ bool done = false;\r
+ float32 t2 = tMax;\r
+ int32 pushBackIter = 0;\r
+ for (;;)\r
+ {\r
+ // Find the deepest point at t2. Store the witness point indices.\r
+ int32 indexA, indexB;\r
+ float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2);\r
+\r
+ // Is the final configuration separated?\r
+ if (s2 > target + tolerance)\r
+ {\r
+ // Victory!\r
+ output->state = b2TOIOutput::e_separated;\r
+ output->t = tMax;\r
+ done = true;\r
+ break;\r
+ }\r
+\r
+ // Has the separation reached tolerance?\r
+ if (s2 > target - tolerance)\r
+ {\r
+ // Advance the sweeps\r
+ t1 = t2;\r
+ break;\r
+ }\r
+\r
+ // Compute the initial separation of the witness points.\r
+ float32 s1 = fcn.Evaluate(indexA, indexB, t1);\r
+\r
+ // Check for initial overlap. This might happen if the root finder\r
+ // runs out of iterations.\r
+ if (s1 < target - tolerance)\r
+ {\r
+ output->state = b2TOIOutput::e_failed;\r
+ output->t = t1;\r
+ done = true;\r
+ break;\r
+ }\r
+\r
+ // Check for touching\r
+ if (s1 <= target + tolerance)\r
+ {\r
+ // Victory! t1 should hold the TOI (could be 0.0).\r
+ output->state = b2TOIOutput::e_touching;\r
+ output->t = t1;\r
+ done = true;\r
+ break;\r
+ }\r
+\r
+ // Compute 1D root of: f(x) - target = 0\r
+ int32 rootIterCount = 0;\r
+ float32 a1 = t1, a2 = t2;\r
+ for (;;)\r
+ {\r
+ // Use a mix of the secant rule and bisection.\r
+ float32 t;\r
+ if (rootIterCount & 1)\r
+ {\r
+ // Secant rule to improve convergence.\r
+ t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);\r
+ }\r
+ else\r
+ {\r
+ // Bisection to guarantee progress.\r
+ t = 0.5f * (a1 + a2);\r
+ }\r
+\r
+ float32 s = fcn.Evaluate(indexA, indexB, t);\r
+\r
+ if (b2Abs(s - target) < tolerance)\r
+ {\r
+ // t2 holds a tentative value for t1\r
+ t2 = t;\r
+ break;\r
+ }\r
+\r
+ // Ensure we continue to bracket the root.\r
+ if (s > target)\r
+ {\r
+ a1 = t;\r
+ s1 = s;\r
+ }\r
+ else\r
+ {\r
+ a2 = t;\r
+ s2 = s;\r
+ }\r
+\r
+ ++rootIterCount;\r
+ ++b2_toiRootIters;\r
+\r
+ if (rootIterCount == 50)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);\r
+\r
+ ++pushBackIter;\r
+\r
+ if (pushBackIter == b2_maxPolygonVertices)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ++iter;\r
+ ++b2_toiIters;\r
+\r
+ if (done)\r
+ {\r
+ break;\r
+ }\r
+\r
+ if (iter == k_maxIterations)\r
+ {\r
+ // Root finder got stuck. Semi-victory.\r
+ output->state = b2TOIOutput::e_failed;\r
+ output->t = t1;\r
+ break;\r
+ }\r
+ }\r
+\r
+ b2_toiMaxIters = b2Max(b2_toiMaxIters, iter);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_TIME_OF_IMPACT_H\r
+#define B2_TIME_OF_IMPACT_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <Box2D/Collision/b2Distance.h>\r
+#include <climits>\r
+\r
+/// Input parameters for b2TimeOfImpact\r
+struct b2TOIInput\r
+{\r
+ b2DistanceProxy proxyA;\r
+ b2DistanceProxy proxyB;\r
+ b2Sweep sweepA;\r
+ b2Sweep sweepB;\r
+ float32 tMax; // defines sweep interval [0, tMax]\r
+};\r
+\r
+// Output parameters for b2TimeOfImpact.\r
+struct b2TOIOutput\r
+{\r
+ enum State\r
+ {\r
+ e_unknown,\r
+ e_failed,\r
+ e_overlapped,\r
+ e_touching,\r
+ e_separated\r
+ };\r
+\r
+ State state;\r
+ float32 t;\r
+};\r
+\r
+/// Compute the upper bound on time before two shapes penetrate. Time is represented as\r
+/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,\r
+/// non-tunneling collision. If you change the time interval, you should call this function\r
+/// again.\r
+/// Note: use b2Distance to compute the contact point and normal at the time of impact.\r
+void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+#include <cstdlib>\r
+#include <climits>\r
+#include <cstring>\r
+#include <memory>\r
+\r
+int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = \r
+{\r
+ 16, // 0\r
+ 32, // 1\r
+ 64, // 2\r
+ 96, // 3\r
+ 128, // 4\r
+ 160, // 5\r
+ 192, // 6\r
+ 224, // 7\r
+ 256, // 8\r
+ 320, // 9\r
+ 384, // 10\r
+ 448, // 11\r
+ 512, // 12\r
+ 640, // 13\r
+};\r
+uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];\r
+bool b2BlockAllocator::s_blockSizeLookupInitialized;\r
+\r
+struct b2Chunk\r
+{\r
+ int32 blockSize;\r
+ b2Block* blocks;\r
+};\r
+\r
+struct b2Block\r
+{\r
+ b2Block* next;\r
+};\r
+\r
+b2BlockAllocator::b2BlockAllocator()\r
+{\r
+ b2Assert(b2_blockSizes < UCHAR_MAX);\r
+\r
+ m_chunkSpace = b2_chunkArrayIncrement;\r
+ m_chunkCount = 0;\r
+ m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));\r
+ \r
+ memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));\r
+ memset(m_freeLists, 0, sizeof(m_freeLists));\r
+\r
+ if (s_blockSizeLookupInitialized == false)\r
+ {\r
+ int32 j = 0;\r
+ for (int32 i = 1; i <= b2_maxBlockSize; ++i)\r
+ {\r
+ b2Assert(j < b2_blockSizes);\r
+ if (i <= s_blockSizes[j])\r
+ {\r
+ s_blockSizeLookup[i] = (uint8)j;\r
+ }\r
+ else\r
+ {\r
+ ++j;\r
+ s_blockSizeLookup[i] = (uint8)j;\r
+ }\r
+ }\r
+\r
+ s_blockSizeLookupInitialized = true;\r
+ }\r
+}\r
+\r
+b2BlockAllocator::~b2BlockAllocator()\r
+{\r
+ for (int32 i = 0; i < m_chunkCount; ++i)\r
+ {\r
+ b2Free(m_chunks[i].blocks);\r
+ }\r
+\r
+ b2Free(m_chunks);\r
+}\r
+\r
+void* b2BlockAllocator::Allocate(int32 size)\r
+{\r
+ if (size == 0)\r
+ return NULL;\r
+\r
+ b2Assert(0 < size && size <= b2_maxBlockSize);\r
+\r
+ int32 index = s_blockSizeLookup[size];\r
+ b2Assert(0 <= index && index < b2_blockSizes);\r
+\r
+ if (m_freeLists[index])\r
+ {\r
+ b2Block* block = m_freeLists[index];\r
+ m_freeLists[index] = block->next;\r
+ return block;\r
+ }\r
+ else\r
+ {\r
+ if (m_chunkCount == m_chunkSpace)\r
+ {\r
+ b2Chunk* oldChunks = m_chunks;\r
+ m_chunkSpace += b2_chunkArrayIncrement;\r
+ m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));\r
+ memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));\r
+ memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));\r
+ b2Free(oldChunks);\r
+ }\r
+\r
+ b2Chunk* chunk = m_chunks + m_chunkCount;\r
+ chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);\r
+#if defined(_DEBUG)\r
+ memset(chunk->blocks, 0xcd, b2_chunkSize);\r
+#endif\r
+ int32 blockSize = s_blockSizes[index];\r
+ chunk->blockSize = blockSize;\r
+ int32 blockCount = b2_chunkSize / blockSize;\r
+ b2Assert(blockCount * blockSize <= b2_chunkSize);\r
+ for (int32 i = 0; i < blockCount - 1; ++i)\r
+ {\r
+ b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);\r
+ b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));\r
+ block->next = next;\r
+ }\r
+ b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));\r
+ last->next = NULL;\r
+\r
+ m_freeLists[index] = chunk->blocks->next;\r
+ ++m_chunkCount;\r
+\r
+ return chunk->blocks;\r
+ }\r
+}\r
+\r
+void b2BlockAllocator::Free(void* p, int32 size)\r
+{\r
+ if (size == 0)\r
+ {\r
+ return;\r
+ }\r
+\r
+ b2Assert(0 < size && size <= b2_maxBlockSize);\r
+\r
+ int32 index = s_blockSizeLookup[size];\r
+ b2Assert(0 <= index && index < b2_blockSizes);\r
+\r
+#ifdef _DEBUG\r
+ // Verify the memory address and size is valid.\r
+ int32 blockSize = s_blockSizes[index];\r
+ bool found = false;\r
+ for (int32 i = 0; i < m_chunkCount; ++i)\r
+ {\r
+ b2Chunk* chunk = m_chunks + i;\r
+ if (chunk->blockSize != blockSize)\r
+ {\r
+ b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||\r
+ (int8*)chunk->blocks + b2_chunkSize <= (int8*)p);\r
+ }\r
+ else\r
+ {\r
+ if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)\r
+ {\r
+ found = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ b2Assert(found);\r
+\r
+ memset(p, 0xfd, blockSize);\r
+#endif\r
+\r
+ b2Block* block = (b2Block*)p;\r
+ block->next = m_freeLists[index];\r
+ m_freeLists[index] = block;\r
+}\r
+\r
+void b2BlockAllocator::Clear()\r
+{\r
+ for (int32 i = 0; i < m_chunkCount; ++i)\r
+ {\r
+ b2Free(m_chunks[i].blocks);\r
+ }\r
+\r
+ m_chunkCount = 0;\r
+ memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));\r
+\r
+ memset(m_freeLists, 0, sizeof(m_freeLists));\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_BLOCK_ALLOCATOR_H\r
+#define B2_BLOCK_ALLOCATOR_H\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+\r
+const int32 b2_chunkSize = 4096;\r
+const int32 b2_maxBlockSize = 640;\r
+const int32 b2_blockSizes = 14;\r
+const int32 b2_chunkArrayIncrement = 128;\r
+\r
+struct b2Block;\r
+struct b2Chunk;\r
+\r
+// This is a small object allocator used for allocating small\r
+// objects that persist for more than one time step.\r
+// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp\r
+class b2BlockAllocator\r
+{\r
+public:\r
+ b2BlockAllocator();\r
+ ~b2BlockAllocator();\r
+\r
+ void* Allocate(int32 size);\r
+ void Free(void* p, int32 size);\r
+\r
+ void Clear();\r
+\r
+private:\r
+\r
+ b2Chunk* m_chunks;\r
+ int32 m_chunkCount;\r
+ int32 m_chunkSpace;\r
+\r
+ b2Block* m_freeLists[b2_blockSizes];\r
+\r
+ static int32 s_blockSizes[b2_blockSizes];\r
+ static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];\r
+ static bool s_blockSizeLookupInitialized;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+\r
+const b2Vec2 b2Vec2_zero(0.0f, 0.0f);\r
+const b2Mat22 b2Mat22_identity(1.0f, 0.0f, 0.0f, 1.0f);\r
+const b2Transform b2Transform_identity(b2Vec2_zero, b2Mat22_identity);\r
+\r
+/// Solve A * x = b, where b is a column vector. This is more efficient\r
+/// than computing the inverse in one-shot cases.\r
+b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const\r
+{\r
+ float32 det = b2Dot(col1, b2Cross(col2, col3));\r
+ if (det != 0.0f)\r
+ {\r
+ det = 1.0f / det;\r
+ }\r
+ b2Vec3 x;\r
+ x.x = det * b2Dot(b, b2Cross(col2, col3));\r
+ x.y = det * b2Dot(col1, b2Cross(b, col3));\r
+ x.z = det * b2Dot(col1, b2Cross(col2, b));\r
+ return x;\r
+}\r
+\r
+/// Solve A * x = b, where b is a column vector. This is more efficient\r
+/// than computing the inverse in one-shot cases.\r
+b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const\r
+{\r
+ float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;\r
+ float32 det = a11 * a22 - a12 * a21;\r
+ if (det != 0.0f)\r
+ {\r
+ det = 1.0f / det;\r
+ }\r
+ b2Vec2 x;\r
+ x.x = det * (a22 * b.x - a12 * b.y);\r
+ x.y = det * (a11 * b.y - a21 * b.x);\r
+ return x;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_MATH_H\r
+#define B2_MATH_H\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+\r
+#include <cmath>\r
+#include <cfloat>\r
+#include <cstddef>\r
+#include <limits>\r
+\r
+/// This function is used to ensure that a floating point number is\r
+/// not a NaN or infinity.\r
+inline bool b2IsValid(float32 x)\r
+{\r
+ if (x != x)\r
+ {\r
+ // NaN.\r
+ return false;\r
+ }\r
+\r
+ float32 infinity = std::numeric_limits<float32>::infinity();\r
+ return -infinity < x && x < infinity;\r
+}\r
+\r
+/// This is a approximate yet fast inverse square-root.\r
+inline float32 b2InvSqrt(float32 x)\r
+{\r
+ union\r
+ {\r
+ float32 x;\r
+ int32 i;\r
+ } convert;\r
+\r
+ convert.x = x;\r
+ float32 xhalf = 0.5f * x;\r
+ convert.i = 0x5f3759df - (convert.i >> 1);\r
+ x = convert.x;\r
+ x = x * (1.5f - xhalf * x * x);\r
+ return x;\r
+}\r
+\r
+#define b2Sqrt(x) sqrtf(x)\r
+#define b2Atan2(y, x) atan2f(y, x)\r
+\r
+inline float32 b2Abs(float32 a)\r
+{\r
+ return a > 0.0f ? a : -a;\r
+}\r
+\r
+/// A 2D column vector.\r
+struct b2Vec2\r
+{\r
+ /// Default constructor does nothing (for performance).\r
+ b2Vec2() {}\r
+\r
+ /// Construct using coordinates.\r
+ b2Vec2(float32 x, float32 y) : x(x), y(y) {}\r
+\r
+ /// Set this vector to all zeros.\r
+ void SetZero() { x = 0.0f; y = 0.0f; }\r
+\r
+ /// Set this vector to some specified coordinates.\r
+ void Set(float32 x_, float32 y_) { x = x_; y = y_; }\r
+\r
+ /// Negate this vector.\r
+ b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }\r
+ \r
+ /// Read from and indexed element.\r
+ float32 operator () (int32 i) const\r
+ {\r
+ return (&x)[i];\r
+ }\r
+\r
+ /// Write to an indexed element.\r
+ float32& operator () (int32 i)\r
+ {\r
+ return (&x)[i];\r
+ }\r
+\r
+ /// Add a vector to this vector.\r
+ void operator += (const b2Vec2& v)\r
+ {\r
+ x += v.x; y += v.y;\r
+ }\r
+ \r
+ /// Subtract a vector from this vector.\r
+ void operator -= (const b2Vec2& v)\r
+ {\r
+ x -= v.x; y -= v.y;\r
+ }\r
+\r
+ /// Multiply this vector by a scalar.\r
+ void operator *= (float32 a)\r
+ {\r
+ x *= a; y *= a;\r
+ }\r
+\r
+ /// Get the length of this vector (the norm).\r
+ float32 Length() const\r
+ {\r
+ return b2Sqrt(x * x + y * y);\r
+ }\r
+\r
+ /// Get the length squared. For performance, use this instead of\r
+ /// b2Vec2::Length (if possible).\r
+ float32 LengthSquared() const\r
+ {\r
+ return x * x + y * y;\r
+ }\r
+\r
+ /// Convert this vector into a unit vector. Returns the length.\r
+ float32 Normalize()\r
+ {\r
+ float32 length = Length();\r
+ if (length < b2_epsilon)\r
+ {\r
+ return 0.0f;\r
+ }\r
+ float32 invLength = 1.0f / length;\r
+ x *= invLength;\r
+ y *= invLength;\r
+\r
+ return length;\r
+ }\r
+\r
+ /// Does this vector contain finite coordinates?\r
+ bool IsValid() const\r
+ {\r
+ return b2IsValid(x) && b2IsValid(y);\r
+ }\r
+\r
+ float32 x, y;\r
+};\r
+\r
+/// A 2D column vector with 3 elements.\r
+struct b2Vec3\r
+{\r
+ /// Default constructor does nothing (for performance).\r
+ b2Vec3() {}\r
+\r
+ /// Construct using coordinates.\r
+ b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}\r
+\r
+ /// Set this vector to all zeros.\r
+ void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }\r
+\r
+ /// Set this vector to some specified coordinates.\r
+ void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }\r
+\r
+ /// Negate this vector.\r
+ b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }\r
+\r
+ /// Add a vector to this vector.\r
+ void operator += (const b2Vec3& v)\r
+ {\r
+ x += v.x; y += v.y; z += v.z;\r
+ }\r
+\r
+ /// Subtract a vector from this vector.\r
+ void operator -= (const b2Vec3& v)\r
+ {\r
+ x -= v.x; y -= v.y; z -= v.z;\r
+ }\r
+\r
+ /// Multiply this vector by a scalar.\r
+ void operator *= (float32 s)\r
+ {\r
+ x *= s; y *= s; z *= s;\r
+ }\r
+\r
+ float32 x, y, z;\r
+};\r
+\r
+/// A 2-by-2 matrix. Stored in column-major order.\r
+struct b2Mat22\r
+{\r
+ /// The default constructor does nothing (for performance).\r
+ b2Mat22() {}\r
+\r
+ /// Construct this matrix using columns.\r
+ b2Mat22(const b2Vec2& c1, const b2Vec2& c2)\r
+ {\r
+ col1 = c1;\r
+ col2 = c2;\r
+ }\r
+\r
+ /// Construct this matrix using scalars.\r
+ b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)\r
+ {\r
+ col1.x = a11; col1.y = a21;\r
+ col2.x = a12; col2.y = a22;\r
+ }\r
+\r
+ /// Construct this matrix using an angle. This matrix becomes\r
+ /// an orthonormal rotation matrix.\r
+ explicit b2Mat22(float32 angle)\r
+ {\r
+ // TODO_ERIN compute sin+cos together.\r
+ float32 c = cosf(angle), s = sinf(angle);\r
+ col1.x = c; col2.x = -s;\r
+ col1.y = s; col2.y = c;\r
+ }\r
+\r
+ /// Initialize this matrix using columns.\r
+ void Set(const b2Vec2& c1, const b2Vec2& c2)\r
+ {\r
+ col1 = c1;\r
+ col2 = c2;\r
+ }\r
+\r
+ /// Initialize this matrix using an angle. This matrix becomes\r
+ /// an orthonormal rotation matrix.\r
+ void Set(float32 angle)\r
+ {\r
+ float32 c = cosf(angle), s = sinf(angle);\r
+ col1.x = c; col2.x = -s;\r
+ col1.y = s; col2.y = c;\r
+ }\r
+\r
+ /// Set this to the identity matrix.\r
+ void SetIdentity()\r
+ {\r
+ col1.x = 1.0f; col2.x = 0.0f;\r
+ col1.y = 0.0f; col2.y = 1.0f;\r
+ }\r
+\r
+ /// Set this matrix to all zeros.\r
+ void SetZero()\r
+ {\r
+ col1.x = 0.0f; col2.x = 0.0f;\r
+ col1.y = 0.0f; col2.y = 0.0f;\r
+ }\r
+\r
+ /// Extract the angle from this matrix (assumed to be\r
+ /// a rotation matrix).\r
+ float32 GetAngle() const\r
+ {\r
+ return b2Atan2(col1.y, col1.x);\r
+ }\r
+\r
+ b2Mat22 GetInverse() const\r
+ {\r
+ float32 a = col1.x, b = col2.x, c = col1.y, d = col2.y;\r
+ b2Mat22 B;\r
+ float32 det = a * d - b * c;\r
+ if (det != 0.0f)\r
+ {\r
+ det = 1.0f / det;\r
+ }\r
+ B.col1.x = det * d; B.col2.x = -det * b;\r
+ B.col1.y = -det * c; B.col2.y = det * a;\r
+ return B;\r
+ }\r
+\r
+ /// Solve A * x = b, where b is a column vector. This is more efficient\r
+ /// than computing the inverse in one-shot cases.\r
+ b2Vec2 Solve(const b2Vec2& b) const\r
+ {\r
+ float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;\r
+ float32 det = a11 * a22 - a12 * a21;\r
+ if (det != 0.0f)\r
+ {\r
+ det = 1.0f / det;\r
+ }\r
+ b2Vec2 x;\r
+ x.x = det * (a22 * b.x - a12 * b.y);\r
+ x.y = det * (a11 * b.y - a21 * b.x);\r
+ return x;\r
+ }\r
+\r
+ b2Vec2 col1, col2;\r
+};\r
+\r
+/// A 3-by-3 matrix. Stored in column-major order.\r
+struct b2Mat33\r
+{\r
+ /// The default constructor does nothing (for performance).\r
+ b2Mat33() {}\r
+\r
+ /// Construct this matrix using columns.\r
+ b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)\r
+ {\r
+ col1 = c1;\r
+ col2 = c2;\r
+ col3 = c3;\r
+ }\r
+\r
+ /// Set this matrix to all zeros.\r
+ void SetZero()\r
+ {\r
+ col1.SetZero();\r
+ col2.SetZero();\r
+ col3.SetZero();\r
+ }\r
+\r
+ /// Solve A * x = b, where b is a column vector. This is more efficient\r
+ /// than computing the inverse in one-shot cases.\r
+ b2Vec3 Solve33(const b2Vec3& b) const;\r
+\r
+ /// Solve A * x = b, where b is a column vector. This is more efficient\r
+ /// than computing the inverse in one-shot cases. Solve only the upper\r
+ /// 2-by-2 matrix equation.\r
+ b2Vec2 Solve22(const b2Vec2& b) const;\r
+\r
+ b2Vec3 col1, col2, col3;\r
+};\r
+\r
+/// A transform contains translation and rotation. It is used to represent\r
+/// the position and orientation of rigid frames.\r
+struct b2Transform\r
+{\r
+ /// The default constructor does nothing (for performance).\r
+ b2Transform() {}\r
+\r
+ /// Initialize using a position vector and a rotation matrix.\r
+ b2Transform(const b2Vec2& position, const b2Mat22& R) : position(position), R(R) {}\r
+\r
+ /// Set this to the identity transform.\r
+ void SetIdentity()\r
+ {\r
+ position.SetZero();\r
+ R.SetIdentity();\r
+ }\r
+\r
+ /// Set this based on the position and angle.\r
+ void Set(const b2Vec2& p, float32 angle)\r
+ {\r
+ position = p;\r
+ R.Set(angle);\r
+ }\r
+\r
+ /// Calculate the angle that the rotation matrix represents.\r
+ float32 GetAngle() const\r
+ {\r
+ return b2Atan2(R.col1.y, R.col1.x);\r
+ }\r
+\r
+ b2Vec2 position;\r
+ b2Mat22 R;\r
+};\r
+\r
+/// This describes the motion of a body/shape for TOI computation.\r
+/// Shapes are defined with respect to the body origin, which may\r
+/// no coincide with the center of mass. However, to support dynamics\r
+/// we must interpolate the center of mass position.\r
+struct b2Sweep\r
+{\r
+ /// Get the interpolated transform at a specific time.\r
+ /// @param alpha is a factor in [0,1], where 0 indicates t0.\r
+ void GetTransform(b2Transform* xf, float32 alpha) const;\r
+\r
+ /// Advance the sweep forward, yielding a new initial state.\r
+ /// @param t the new initial time.\r
+ void Advance(float32 t);\r
+\r
+ /// Normalize the angles.\r
+ void Normalize();\r
+\r
+ b2Vec2 localCenter; ///< local center of mass position\r
+ b2Vec2 c0, c; ///< center world positions\r
+ float32 a0, a; ///< world angles\r
+};\r
+\r
+\r
+extern const b2Vec2 b2Vec2_zero;\r
+extern const b2Mat22 b2Mat22_identity;\r
+extern const b2Transform b2Transform_identity;\r
+\r
+/// Perform the dot product on two vectors.\r
+inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return a.x * b.x + a.y * b.y;\r
+}\r
+\r
+/// Perform the cross product on two vectors. In 2D this produces a scalar.\r
+inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return a.x * b.y - a.y * b.x;\r
+}\r
+\r
+/// Perform the cross product on a vector and a scalar. In 2D this produces\r
+/// a vector.\r
+inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)\r
+{\r
+ return b2Vec2(s * a.y, -s * a.x);\r
+}\r
+\r
+/// Perform the cross product on a scalar and a vector. In 2D this produces\r
+/// a vector.\r
+inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)\r
+{\r
+ return b2Vec2(-s * a.y, s * a.x);\r
+}\r
+\r
+/// Multiply a matrix times a vector. If a rotation matrix is provided,\r
+/// then this transforms the vector from one frame to another.\r
+inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)\r
+{\r
+ return b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y);\r
+}\r
+\r
+/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,\r
+/// then this transforms the vector from one frame to another (inverse transform).\r
+inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)\r
+{\r
+ return b2Vec2(b2Dot(v, A.col1), b2Dot(v, A.col2));\r
+}\r
+\r
+/// Add two vectors component-wise.\r
+inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return b2Vec2(a.x + b.x, a.y + b.y);\r
+}\r
+\r
+/// Subtract two vectors component-wise.\r
+inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return b2Vec2(a.x - b.x, a.y - b.y);\r
+}\r
+\r
+inline b2Vec2 operator * (float32 s, const b2Vec2& a)\r
+{\r
+ return b2Vec2(s * a.x, s * a.y);\r
+}\r
+\r
+inline bool operator == (const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return a.x == b.x && a.y == b.y;\r
+}\r
+\r
+inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ b2Vec2 c = a - b;\r
+ return c.Length();\r
+}\r
+\r
+inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ b2Vec2 c = a - b;\r
+ return b2Dot(c, c);\r
+}\r
+\r
+inline b2Vec3 operator * (float32 s, const b2Vec3& a)\r
+{\r
+ return b2Vec3(s * a.x, s * a.y, s * a.z);\r
+}\r
+\r
+/// Add two vectors component-wise.\r
+inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b)\r
+{\r
+ return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z);\r
+}\r
+\r
+/// Subtract two vectors component-wise.\r
+inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)\r
+{\r
+ return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z);\r
+}\r
+\r
+/// Perform the dot product on two vectors.\r
+inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b)\r
+{\r
+ return a.x * b.x + a.y * b.y + a.z * b.z;\r
+}\r
+\r
+/// Perform the cross product on two vectors.\r
+inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b)\r
+{\r
+ return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);\r
+}\r
+\r
+inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)\r
+{\r
+ return b2Mat22(A.col1 + B.col1, A.col2 + B.col2);\r
+}\r
+\r
+// A * B\r
+inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)\r
+{\r
+ return b2Mat22(b2Mul(A, B.col1), b2Mul(A, B.col2));\r
+}\r
+\r
+// A^T * B\r
+inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)\r
+{\r
+ b2Vec2 c1(b2Dot(A.col1, B.col1), b2Dot(A.col2, B.col1));\r
+ b2Vec2 c2(b2Dot(A.col1, B.col2), b2Dot(A.col2, B.col2));\r
+ return b2Mat22(c1, c2);\r
+}\r
+\r
+/// Multiply a matrix times a vector.\r
+inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v)\r
+{\r
+ return v.x * A.col1 + v.y * A.col2 + v.z * A.col3;\r
+}\r
+\r
+inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v)\r
+{\r
+ float32 x = T.position.x + T.R.col1.x * v.x + T.R.col2.x * v.y;\r
+ float32 y = T.position.y + T.R.col1.y * v.x + T.R.col2.y * v.y;\r
+\r
+ return b2Vec2(x, y);\r
+}\r
+\r
+inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v)\r
+{\r
+ return b2MulT(T.R, v - T.position);\r
+}\r
+\r
+inline b2Vec2 b2Abs(const b2Vec2& a)\r
+{\r
+ return b2Vec2(b2Abs(a.x), b2Abs(a.y));\r
+}\r
+\r
+inline b2Mat22 b2Abs(const b2Mat22& A)\r
+{\r
+ return b2Mat22(b2Abs(A.col1), b2Abs(A.col2));\r
+}\r
+\r
+template <typename T>\r
+inline T b2Min(T a, T b)\r
+{\r
+ return a < b ? a : b;\r
+}\r
+\r
+inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y));\r
+}\r
+\r
+template <typename T>\r
+inline T b2Max(T a, T b)\r
+{\r
+ return a > b ? a : b;\r
+}\r
+\r
+inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b)\r
+{\r
+ return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y));\r
+}\r
+\r
+template <typename T>\r
+inline T b2Clamp(T a, T low, T high)\r
+{\r
+ return b2Max(low, b2Min(a, high));\r
+}\r
+\r
+inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high)\r
+{\r
+ return b2Max(low, b2Min(a, high));\r
+}\r
+\r
+template<typename T> inline void b2Swap(T& a, T& b)\r
+{\r
+ T tmp = a;\r
+ a = b;\r
+ b = tmp;\r
+}\r
+\r
+/// "Next Largest Power of 2\r
+/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm\r
+/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with\r
+/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next\r
+/// largest power of 2. For a 32-bit value:"\r
+inline uint32 b2NextPowerOfTwo(uint32 x)\r
+{\r
+ x |= (x >> 1);\r
+ x |= (x >> 2);\r
+ x |= (x >> 4);\r
+ x |= (x >> 8);\r
+ x |= (x >> 16);\r
+ return x + 1;\r
+}\r
+\r
+inline bool b2IsPowerOfTwo(uint32 x)\r
+{\r
+ bool result = x > 0 && (x & (x - 1)) == 0;\r
+ return result;\r
+}\r
+\r
+inline void b2Sweep::GetTransform(b2Transform* xf, float32 alpha) const\r
+{\r
+ xf->position = (1.0f - alpha) * c0 + alpha * c;\r
+ float32 angle = (1.0f - alpha) * a0 + alpha * a;\r
+ xf->R.Set(angle);\r
+\r
+ // Shift to origin\r
+ xf->position -= b2Mul(xf->R, localCenter);\r
+}\r
+\r
+inline void b2Sweep::Advance(float32 t)\r
+{\r
+ c0 = (1.0f - t) * c0 + t * c;\r
+ a0 = (1.0f - t) * a0 + t * a;\r
+}\r
+\r
+/// Normalize an angle in radians to be between -pi and pi\r
+inline void b2Sweep::Normalize()\r
+{\r
+ float32 twoPi = 2.0f * b2_pi;\r
+ float32 d = twoPi * floorf(a0 / twoPi);\r
+ a0 -= d;\r
+ a -= d;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+#include <cstdlib>\r
+\r
+b2Version b2_version = {2, 1, 2};\r
+\r
+// Memory allocators. Modify these to use your own allocator.\r
+void* b2Alloc(int32 size)\r
+{\r
+ return malloc(size);\r
+}\r
+\r
+void b2Free(void* mem)\r
+{\r
+ free(mem);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_SETTINGS_H\r
+#define B2_SETTINGS_H\r
+\r
+#include <cassert>\r
+#include <cmath>\r
+\r
+#define B2_NOT_USED(x) ((void)(x))\r
+#define b2Assert(A) assert(A)\r
+\r
+typedef signed char int8;\r
+typedef signed short int16;\r
+typedef signed int int32;\r
+typedef unsigned char uint8;\r
+typedef unsigned short uint16;\r
+typedef unsigned int uint32;\r
+typedef float float32;\r
+\r
+#define b2_maxFloat FLT_MAX\r
+#define b2_epsilon FLT_EPSILON\r
+#define b2_pi 3.14159265359f\r
+\r
+/// @file\r
+/// Global tuning constants based on meters-kilograms-seconds (MKS) units.\r
+///\r
+\r
+// Collision\r
+\r
+/// The maximum number of contact points between two convex shapes.\r
+#define b2_maxManifoldPoints 2\r
+\r
+/// The maximum number of vertices on a convex polygon.\r
+#define b2_maxPolygonVertices 8\r
+\r
+/// This is used to fatten AABBs in the dynamic tree. This allows proxies\r
+/// to move by a small amount without triggering a tree adjustment.\r
+/// This is in meters.\r
+#define b2_aabbExtension 0.1f\r
+\r
+/// This is used to fatten AABBs in the dynamic tree. This is used to predict\r
+/// the future position based on the current displacement.\r
+/// This is a dimensionless multiplier.\r
+#define b2_aabbMultiplier 2.0f\r
+\r
+/// A small length used as a collision and constraint tolerance. Usually it is\r
+/// chosen to be numerically significant, but visually insignificant.\r
+#define b2_linearSlop 0.005f\r
+\r
+/// A small angle used as a collision and constraint tolerance. Usually it is\r
+/// chosen to be numerically significant, but visually insignificant.\r
+#define b2_angularSlop (2.0f / 180.0f * b2_pi)\r
+\r
+/// The radius of the polygon/edge shape skin. This should not be modified. Making\r
+/// this smaller means polygons will have an insufficient buffer for continuous collision.\r
+/// Making it larger may create artifacts for vertex collision.\r
+#define b2_polygonRadius (2.0f * b2_linearSlop)\r
+\r
+\r
+// Dynamics\r
+\r
+/// Maximum number of contacts to be handled to solve a TOI impact.\r
+#define b2_maxTOIContacts 32\r
+\r
+/// A velocity threshold for elastic collisions. Any collision with a relative linear\r
+/// velocity below this threshold will be treated as inelastic.\r
+#define b2_velocityThreshold 1.0f\r
+\r
+/// The maximum linear position correction used when solving constraints. This helps to\r
+/// prevent overshoot.\r
+#define b2_maxLinearCorrection 0.2f\r
+\r
+/// The maximum angular position correction used when solving constraints. This helps to\r
+/// prevent overshoot.\r
+#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi)\r
+\r
+/// The maximum linear velocity of a body. This limit is very large and is used\r
+/// to prevent numerical problems. You shouldn't need to adjust this.\r
+#define b2_maxTranslation 2.0f\r
+#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation)\r
+\r
+/// The maximum angular velocity of a body. This limit is very large and is used\r
+/// to prevent numerical problems. You shouldn't need to adjust this.\r
+#define b2_maxRotation (0.5f * b2_pi)\r
+#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation)\r
+\r
+/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so\r
+/// that overlap is removed in one time step. However using values close to 1 often lead\r
+/// to overshoot.\r
+#define b2_contactBaumgarte 0.2f\r
+\r
+// Sleep\r
+\r
+/// The time that a body must be still before it will go to sleep.\r
+#define b2_timeToSleep 0.5f\r
+\r
+/// A body cannot sleep if its linear velocity is above this tolerance.\r
+#define b2_linearSleepTolerance 0.01f\r
+\r
+/// A body cannot sleep if its angular velocity is above this tolerance.\r
+#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)\r
+\r
+// Memory Allocation\r
+\r
+/// Implement this function to use your own memory allocator.\r
+void* b2Alloc(int32 size);\r
+\r
+/// If you implement b2Alloc, you should also implement this function.\r
+void b2Free(void* mem);\r
+\r
+/// Version numbering scheme.\r
+/// See http://en.wikipedia.org/wiki/Software_versioning\r
+struct b2Version\r
+{\r
+ int32 major; ///< significant changes\r
+ int32 minor; ///< incremental changes\r
+ int32 revision; ///< bug fixes\r
+};\r
+\r
+/// Current version.\r
+extern b2Version b2_version;\r
+\r
+/// Friction mixing law. Feel free to customize this.\r
+inline float32 b2MixFriction(float32 friction1, float32 friction2)\r
+{\r
+ return sqrtf(friction1 * friction2);\r
+}\r
+\r
+/// Restitution mixing law. Feel free to customize this.\r
+inline float32 b2MixRestitution(float32 restitution1, float32 restitution2)\r
+{\r
+ return restitution1 > restitution2 ? restitution1 : restitution2;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Common/b2StackAllocator.h>\r
+#include <Box2D/Common/b2Math.h>\r
+\r
+b2StackAllocator::b2StackAllocator()\r
+{\r
+ m_index = 0;\r
+ m_allocation = 0;\r
+ m_maxAllocation = 0;\r
+ m_entryCount = 0;\r
+}\r
+\r
+b2StackAllocator::~b2StackAllocator()\r
+{\r
+ b2Assert(m_index == 0);\r
+ b2Assert(m_entryCount == 0);\r
+}\r
+\r
+void* b2StackAllocator::Allocate(int32 size)\r
+{\r
+ b2Assert(m_entryCount < b2_maxStackEntries);\r
+\r
+ b2StackEntry* entry = m_entries + m_entryCount;\r
+ entry->size = size;\r
+ if (m_index + size > b2_stackSize)\r
+ {\r
+ entry->data = (char*)b2Alloc(size);\r
+ entry->usedMalloc = true;\r
+ }\r
+ else\r
+ {\r
+ entry->data = m_data + m_index;\r
+ entry->usedMalloc = false;\r
+ m_index += size;\r
+ }\r
+\r
+ m_allocation += size;\r
+ m_maxAllocation = b2Max(m_maxAllocation, m_allocation);\r
+ ++m_entryCount;\r
+\r
+ return entry->data;\r
+}\r
+\r
+void b2StackAllocator::Free(void* p)\r
+{\r
+ b2Assert(m_entryCount > 0);\r
+ b2StackEntry* entry = m_entries + m_entryCount - 1;\r
+ b2Assert(p == entry->data);\r
+ if (entry->usedMalloc)\r
+ {\r
+ b2Free(p);\r
+ }\r
+ else\r
+ {\r
+ m_index -= entry->size;\r
+ }\r
+ m_allocation -= entry->size;\r
+ --m_entryCount;\r
+\r
+ p = NULL;\r
+}\r
+\r
+int32 b2StackAllocator::GetMaxAllocation() const\r
+{\r
+ return m_maxAllocation;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_STACK_ALLOCATOR_H\r
+#define B2_STACK_ALLOCATOR_H\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+\r
+const int32 b2_stackSize = 100 * 1024; // 100k\r
+const int32 b2_maxStackEntries = 32;\r
+\r
+struct b2StackEntry\r
+{\r
+ char* data;\r
+ int32 size;\r
+ bool usedMalloc;\r
+};\r
+\r
+// This is a stack allocator used for fast per step allocations.\r
+// You must nest allocate/free pairs. The code will assert\r
+// if you try to interleave multiple allocate/free pairs.\r
+class b2StackAllocator\r
+{\r
+public:\r
+ b2StackAllocator();\r
+ ~b2StackAllocator();\r
+\r
+ void* Allocate(int32 size);\r
+ void Free(void* p);\r
+\r
+ int32 GetMaxAllocation() const;\r
+\r
+private:\r
+\r
+ char m_data[b2_stackSize];\r
+ int32 m_index;\r
+\r
+ int32 m_allocation;\r
+ int32 m_maxAllocation;\r
+\r
+ b2StackEntry m_entries[b2_maxStackEntries];\r
+ int32 m_entryCount;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Contacts/b2CircleContact.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2WorldCallbacks.h>\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+\r
+#include <new>\r
+\r
+b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)\r
+{\r
+ void* mem = allocator->Allocate(sizeof(b2CircleContact));\r
+ return new (mem) b2CircleContact(fixtureA, fixtureB);\r
+}\r
+\r
+void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)\r
+{\r
+ ((b2CircleContact*)contact)->~b2CircleContact();\r
+ allocator->Free(contact, sizeof(b2CircleContact));\r
+}\r
+\r
+b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)\r
+ : b2Contact(fixtureA, fixtureB)\r
+{\r
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_circle);\r
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);\r
+}\r
+\r
+void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)\r
+{\r
+ b2CollideCircles(manifold,\r
+ (b2CircleShape*)m_fixtureA->GetShape(), xfA,\r
+ (b2CircleShape*)m_fixtureB->GetShape(), xfB);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_CIRCLE_CONTACT_H\r
+#define B2_CIRCLE_CONTACT_H\r
+\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+\r
+class b2BlockAllocator;\r
+\r
+class b2CircleContact : public b2Contact\r
+{\r
+public:\r
+ static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);\r
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);\r
+\r
+ b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);\r
+ ~b2CircleContact() {}\r
+\r
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/Contacts/b2CircleContact.h>\r
+#include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>\r
+#include <Box2D/Dynamics/Contacts/b2PolygonContact.h>\r
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>\r
+\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+#include <Box2D/Collision/Shapes/b2Shape.h>\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2World.h>\r
+\r
+b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];\r
+bool b2Contact::s_initialized = false;\r
+\r
+void b2Contact::InitializeRegisters()\r
+{\r
+ AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle);\r
+ AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle);\r
+ AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon);\r
+}\r
+\r
+void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,\r
+ b2Shape::Type type1, b2Shape::Type type2)\r
+{\r
+ b2Assert(b2Shape::e_unknown < type1 && type1 < b2Shape::e_typeCount);\r
+ b2Assert(b2Shape::e_unknown < type2 && type2 < b2Shape::e_typeCount);\r
+ \r
+ s_registers[type1][type2].createFcn = createFcn;\r
+ s_registers[type1][type2].destroyFcn = destoryFcn;\r
+ s_registers[type1][type2].primary = true;\r
+\r
+ if (type1 != type2)\r
+ {\r
+ s_registers[type2][type1].createFcn = createFcn;\r
+ s_registers[type2][type1].destroyFcn = destoryFcn;\r
+ s_registers[type2][type1].primary = false;\r
+ }\r
+}\r
+\r
+b2Contact* b2Contact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)\r
+{\r
+ if (s_initialized == false)\r
+ {\r
+ InitializeRegisters();\r
+ s_initialized = true;\r
+ }\r
+\r
+ b2Shape::Type type1 = fixtureA->GetType();\r
+ b2Shape::Type type2 = fixtureB->GetType();\r
+\r
+ b2Assert(b2Shape::e_unknown < type1 && type1 < b2Shape::e_typeCount);\r
+ b2Assert(b2Shape::e_unknown < type2 && type2 < b2Shape::e_typeCount);\r
+ \r
+ b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;\r
+ if (createFcn)\r
+ {\r
+ if (s_registers[type1][type2].primary)\r
+ {\r
+ return createFcn(fixtureA, fixtureB, allocator);\r
+ }\r
+ else\r
+ {\r
+ return createFcn(fixtureB, fixtureA, allocator);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ return NULL;\r
+ }\r
+}\r
+\r
+void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)\r
+{\r
+ b2Assert(s_initialized == true);\r
+\r
+ if (contact->m_manifold.pointCount > 0)\r
+ {\r
+ contact->GetFixtureA()->GetBody()->SetAwake(true);\r
+ contact->GetFixtureB()->GetBody()->SetAwake(true);\r
+ }\r
+\r
+ b2Shape::Type typeA = contact->GetFixtureA()->GetType();\r
+ b2Shape::Type typeB = contact->GetFixtureB()->GetType();\r
+\r
+ b2Assert(b2Shape::e_unknown < typeA && typeB < b2Shape::e_typeCount);\r
+ b2Assert(b2Shape::e_unknown < typeA && typeB < b2Shape::e_typeCount);\r
+\r
+ b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn;\r
+ destroyFcn(contact, allocator);\r
+}\r
+\r
+b2Contact::b2Contact(b2Fixture* fA, b2Fixture* fB)\r
+{\r
+ m_flags = e_enabledFlag;\r
+\r
+ m_fixtureA = fA;\r
+ m_fixtureB = fB;\r
+\r
+ m_manifold.pointCount = 0;\r
+\r
+ m_prev = NULL;\r
+ m_next = NULL;\r
+\r
+ m_nodeA.contact = NULL;\r
+ m_nodeA.prev = NULL;\r
+ m_nodeA.next = NULL;\r
+ m_nodeA.other = NULL;\r
+\r
+ m_nodeB.contact = NULL;\r
+ m_nodeB.prev = NULL;\r
+ m_nodeB.next = NULL;\r
+ m_nodeB.other = NULL;\r
+\r
+ m_toiCount = 0;\r
+}\r
+\r
+// Update the contact manifold and touching status.\r
+// Note: do not assume the fixture AABBs are overlapping or are valid.\r
+void b2Contact::Update(b2ContactListener* listener)\r
+{\r
+ b2Manifold oldManifold = m_manifold;\r
+\r
+ // Re-enable this contact.\r
+ m_flags |= e_enabledFlag;\r
+\r
+ bool touching = false;\r
+ bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag;\r
+\r
+ bool sensorA = m_fixtureA->IsSensor();\r
+ bool sensorB = m_fixtureB->IsSensor();\r
+ bool sensor = sensorA || sensorB;\r
+\r
+ b2Body* bodyA = m_fixtureA->GetBody();\r
+ b2Body* bodyB = m_fixtureB->GetBody();\r
+ const b2Transform& xfA = bodyA->GetTransform();\r
+ const b2Transform& xfB = bodyB->GetTransform();\r
+\r
+ // Is this contact a sensor?\r
+ if (sensor)\r
+ {\r
+ const b2Shape* shapeA = m_fixtureA->GetShape();\r
+ const b2Shape* shapeB = m_fixtureB->GetShape();\r
+ touching = b2TestOverlap(shapeA, shapeB, xfA, xfB);\r
+\r
+ // Sensors don't generate manifolds.\r
+ m_manifold.pointCount = 0;\r
+ }\r
+ else\r
+ {\r
+ Evaluate(&m_manifold, xfA, xfB);\r
+ touching = m_manifold.pointCount > 0;\r
+\r
+ // Match old contact ids to new contact ids and copy the\r
+ // stored impulses to warm start the solver.\r
+ for (int32 i = 0; i < m_manifold.pointCount; ++i)\r
+ {\r
+ b2ManifoldPoint* mp2 = m_manifold.points + i;\r
+ mp2->normalImpulse = 0.0f;\r
+ mp2->tangentImpulse = 0.0f;\r
+ b2ContactID id2 = mp2->id;\r
+\r
+ for (int32 j = 0; j < oldManifold.pointCount; ++j)\r
+ {\r
+ b2ManifoldPoint* mp1 = oldManifold.points + j;\r
+\r
+ if (mp1->id.key == id2.key)\r
+ {\r
+ mp2->normalImpulse = mp1->normalImpulse;\r
+ mp2->tangentImpulse = mp1->tangentImpulse;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (touching != wasTouching)\r
+ {\r
+ bodyA->SetAwake(true);\r
+ bodyB->SetAwake(true);\r
+ }\r
+ }\r
+\r
+ if (touching)\r
+ {\r
+ m_flags |= e_touchingFlag;\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_touchingFlag;\r
+ }\r
+\r
+ if (wasTouching == false && touching == true && listener)\r
+ {\r
+ listener->BeginContact(this);\r
+ }\r
+\r
+ if (wasTouching == true && touching == false && listener)\r
+ {\r
+ listener->EndContact(this);\r
+ }\r
+\r
+ if (sensor == false && touching && listener)\r
+ {\r
+ listener->PreSolve(this, &oldManifold);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_CONTACT_H\r
+#define B2_CONTACT_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/Shapes/b2Shape.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+\r
+class b2Body;\r
+class b2Contact;\r
+class b2Fixture;\r
+class b2World;\r
+class b2BlockAllocator;\r
+class b2StackAllocator;\r
+class b2ContactListener;\r
+\r
+typedef b2Contact* b2ContactCreateFcn(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);\r
+typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator);\r
+\r
+struct b2ContactRegister\r
+{\r
+ b2ContactCreateFcn* createFcn;\r
+ b2ContactDestroyFcn* destroyFcn;\r
+ bool primary;\r
+};\r
+\r
+/// A contact edge is used to connect bodies and contacts together\r
+/// in a contact graph where each body is a node and each contact\r
+/// is an edge. A contact edge belongs to a doubly linked list\r
+/// maintained in each attached body. Each contact has two contact\r
+/// nodes, one for each attached body.\r
+struct b2ContactEdge\r
+{\r
+ b2Body* other; ///< provides quick access to the other body attached.\r
+ b2Contact* contact; ///< the contact\r
+ b2ContactEdge* prev; ///< the previous contact edge in the body's contact list\r
+ b2ContactEdge* next; ///< the next contact edge in the body's contact list\r
+};\r
+\r
+/// The class manages contact between two shapes. A contact exists for each overlapping\r
+/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist\r
+/// that has no contact points.\r
+class b2Contact\r
+{\r
+public:\r
+\r
+ /// Get the contact manifold. Do not modify the manifold unless you understand the\r
+ /// internals of Box2D.\r
+ b2Manifold* GetManifold();\r
+ const b2Manifold* GetManifold() const;\r
+\r
+ /// Get the world manifold.\r
+ void GetWorldManifold(b2WorldManifold* worldManifold) const;\r
+\r
+ /// Is this contact touching?\r
+ bool IsTouching() const;\r
+\r
+ /// Enable/disable this contact. This can be used inside the pre-solve\r
+ /// contact listener. The contact is only disabled for the current\r
+ /// time step (or sub-step in continuous collisions).\r
+ void SetEnabled(bool flag);\r
+\r
+ /// Has this contact been disabled?\r
+ bool IsEnabled() const;\r
+\r
+ /// Get the next contact in the world's contact list.\r
+ b2Contact* GetNext();\r
+ const b2Contact* GetNext() const;\r
+\r
+ /// Get the first fixture in this contact.\r
+ b2Fixture* GetFixtureA();\r
+ const b2Fixture* GetFixtureA() const;\r
+\r
+ /// Get the second fixture in this contact.\r
+ b2Fixture* GetFixtureB();\r
+ const b2Fixture* GetFixtureB() const;\r
+\r
+ /// Evaluate this contact with your own manifold and transforms.\r
+ virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0;\r
+\r
+protected:\r
+ friend class b2ContactManager;\r
+ friend class b2World;\r
+ friend class b2ContactSolver;\r
+ friend class b2Body;\r
+ friend class b2Fixture;\r
+\r
+ // Flags stored in m_flags\r
+ enum\r
+ {\r
+ // Used when crawling contact graph when forming islands.\r
+ e_islandFlag = 0x0001,\r
+\r
+ // Set when the shapes are touching.\r
+ e_touchingFlag = 0x0002,\r
+\r
+ // This contact can be disabled (by user)\r
+ e_enabledFlag = 0x0004,\r
+\r
+ // This contact needs filtering because a fixture filter was changed.\r
+ e_filterFlag = 0x0008,\r
+\r
+ // This bullet contact had a TOI event\r
+ e_bulletHitFlag = 0x0010,\r
+\r
+ };\r
+\r
+ /// Flag this contact for filtering. Filtering will occur the next time step.\r
+ void FlagForFiltering();\r
+\r
+ static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn,\r
+ b2Shape::Type typeA, b2Shape::Type typeB);\r
+ static void InitializeRegisters();\r
+ static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);\r
+ static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator);\r
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);\r
+\r
+ b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {}\r
+ b2Contact(b2Fixture* fixtureA, b2Fixture* fixtureB);\r
+ virtual ~b2Contact() {}\r
+\r
+ void Update(b2ContactListener* listener);\r
+\r
+ static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];\r
+ static bool s_initialized;\r
+\r
+ uint32 m_flags;\r
+\r
+ // World pool and list pointers.\r
+ b2Contact* m_prev;\r
+ b2Contact* m_next;\r
+\r
+ // Nodes for connecting bodies.\r
+ b2ContactEdge m_nodeA;\r
+ b2ContactEdge m_nodeB;\r
+\r
+ b2Fixture* m_fixtureA;\r
+ b2Fixture* m_fixtureB;\r
+\r
+ b2Manifold m_manifold;\r
+\r
+ int32 m_toiCount;\r
+// float32 m_toi;\r
+};\r
+\r
+inline b2Manifold* b2Contact::GetManifold()\r
+{\r
+ return &m_manifold;\r
+}\r
+\r
+inline const b2Manifold* b2Contact::GetManifold() const\r
+{\r
+ return &m_manifold;\r
+}\r
+\r
+inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const\r
+{\r
+ const b2Body* bodyA = m_fixtureA->GetBody();\r
+ const b2Body* bodyB = m_fixtureB->GetBody();\r
+ const b2Shape* shapeA = m_fixtureA->GetShape();\r
+ const b2Shape* shapeB = m_fixtureB->GetShape();\r
+\r
+ worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius);\r
+}\r
+\r
+inline void b2Contact::SetEnabled(bool flag)\r
+{\r
+ if (flag)\r
+ {\r
+ m_flags |= e_enabledFlag;\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_enabledFlag;\r
+ }\r
+}\r
+\r
+inline bool b2Contact::IsEnabled() const\r
+{\r
+ return (m_flags & e_enabledFlag) == e_enabledFlag;\r
+}\r
+\r
+inline bool b2Contact::IsTouching() const\r
+{\r
+ return (m_flags & e_touchingFlag) == e_touchingFlag;\r
+}\r
+\r
+inline b2Contact* b2Contact::GetNext()\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline const b2Contact* b2Contact::GetNext() const\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline b2Fixture* b2Contact::GetFixtureA()\r
+{\r
+ return m_fixtureA;\r
+}\r
+\r
+inline const b2Fixture* b2Contact::GetFixtureA() const\r
+{\r
+ return m_fixtureA;\r
+}\r
+\r
+inline b2Fixture* b2Contact::GetFixtureB()\r
+{\r
+ return m_fixtureB;\r
+}\r
+\r
+inline const b2Fixture* b2Contact::GetFixtureB() const\r
+{\r
+ return m_fixtureB;\r
+}\r
+\r
+inline void b2Contact::FlagForFiltering()\r
+{\r
+ m_flags |= e_filterFlag;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2World.h>\r
+#include <Box2D/Common/b2StackAllocator.h>\r
+\r
+#define B2_DEBUG_SOLVER 0\r
+\r
+b2ContactSolver::b2ContactSolver(b2Contact** contacts, int32 contactCount,\r
+ b2StackAllocator* allocator, float32 impulseRatio)\r
+{\r
+ m_allocator = allocator;\r
+\r
+ m_constraintCount = contactCount;\r
+ m_constraints = (b2ContactConstraint*)m_allocator->Allocate(m_constraintCount * sizeof(b2ContactConstraint));\r
+\r
+ for (int32 i = 0; i < m_constraintCount; ++i)\r
+ {\r
+ b2Contact* contact = contacts[i];\r
+\r
+ b2Fixture* fixtureA = contact->m_fixtureA;\r
+ b2Fixture* fixtureB = contact->m_fixtureB;\r
+ b2Shape* shapeA = fixtureA->GetShape();\r
+ b2Shape* shapeB = fixtureB->GetShape();\r
+ float32 radiusA = shapeA->m_radius;\r
+ float32 radiusB = shapeB->m_radius;\r
+ b2Body* bodyA = fixtureA->GetBody();\r
+ b2Body* bodyB = fixtureB->GetBody();\r
+ b2Manifold* manifold = contact->GetManifold();\r
+\r
+ float32 friction = b2MixFriction(fixtureA->GetFriction(), fixtureB->GetFriction());\r
+ float32 restitution = b2MixRestitution(fixtureA->GetRestitution(), fixtureB->GetRestitution());\r
+\r
+ b2Vec2 vA = bodyA->m_linearVelocity;\r
+ b2Vec2 vB = bodyB->m_linearVelocity;\r
+ float32 wA = bodyA->m_angularVelocity;\r
+ float32 wB = bodyB->m_angularVelocity;\r
+\r
+ b2Assert(manifold->pointCount > 0);\r
+\r
+ b2WorldManifold worldManifold;\r
+ worldManifold.Initialize(manifold, bodyA->m_xf, radiusA, bodyB->m_xf, radiusB);\r
+\r
+ b2ContactConstraint* cc = m_constraints + i;\r
+ cc->bodyA = bodyA;\r
+ cc->bodyB = bodyB;\r
+ cc->manifold = manifold;\r
+ cc->normal = worldManifold.normal;\r
+ cc->pointCount = manifold->pointCount;\r
+ cc->friction = friction;\r
+\r
+ cc->localNormal = manifold->localNormal;\r
+ cc->localPoint = manifold->localPoint;\r
+ cc->radius = radiusA + radiusB;\r
+ cc->type = manifold->type;\r
+\r
+ for (int32 j = 0; j < cc->pointCount; ++j)\r
+ {\r
+ b2ManifoldPoint* cp = manifold->points + j;\r
+ b2ContactConstraintPoint* ccp = cc->points + j;\r
+\r
+ ccp->normalImpulse = impulseRatio * cp->normalImpulse;\r
+ ccp->tangentImpulse = impulseRatio * cp->tangentImpulse;\r
+\r
+ ccp->localPoint = cp->localPoint;\r
+\r
+ ccp->rA = worldManifold.points[j] - bodyA->m_sweep.c;\r
+ ccp->rB = worldManifold.points[j] - bodyB->m_sweep.c;\r
+\r
+ float32 rnA = b2Cross(ccp->rA, cc->normal);\r
+ float32 rnB = b2Cross(ccp->rB, cc->normal);\r
+ rnA *= rnA;\r
+ rnB *= rnB;\r
+\r
+ float32 kNormal = bodyA->m_invMass + bodyB->m_invMass + bodyA->m_invI * rnA + bodyB->m_invI * rnB;\r
+\r
+ b2Assert(kNormal > b2_epsilon);\r
+ ccp->normalMass = 1.0f / kNormal;\r
+\r
+ b2Vec2 tangent = b2Cross(cc->normal, 1.0f);\r
+\r
+ float32 rtA = b2Cross(ccp->rA, tangent);\r
+ float32 rtB = b2Cross(ccp->rB, tangent);\r
+ rtA *= rtA;\r
+ rtB *= rtB;\r
+\r
+ float32 kTangent = bodyA->m_invMass + bodyB->m_invMass + bodyA->m_invI * rtA + bodyB->m_invI * rtB;\r
+\r
+ b2Assert(kTangent > b2_epsilon);\r
+ ccp->tangentMass = 1.0f / kTangent;\r
+\r
+ // Setup a velocity bias for restitution.\r
+ ccp->velocityBias = 0.0f;\r
+ float32 vRel = b2Dot(cc->normal, vB + b2Cross(wB, ccp->rB) - vA - b2Cross(wA, ccp->rA));\r
+ if (vRel < -b2_velocityThreshold)\r
+ {\r
+ ccp->velocityBias = -restitution * vRel;\r
+ }\r
+ }\r
+\r
+ // If we have two points, then prepare the block solver.\r
+ if (cc->pointCount == 2)\r
+ {\r
+ b2ContactConstraintPoint* ccp1 = cc->points + 0;\r
+ b2ContactConstraintPoint* ccp2 = cc->points + 1;\r
+ \r
+ float32 invMassA = bodyA->m_invMass;\r
+ float32 invIA = bodyA->m_invI;\r
+ float32 invMassB = bodyB->m_invMass;\r
+ float32 invIB = bodyB->m_invI;\r
+\r
+ float32 rn1A = b2Cross(ccp1->rA, cc->normal);\r
+ float32 rn1B = b2Cross(ccp1->rB, cc->normal);\r
+ float32 rn2A = b2Cross(ccp2->rA, cc->normal);\r
+ float32 rn2B = b2Cross(ccp2->rB, cc->normal);\r
+\r
+ float32 k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B;\r
+ float32 k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B;\r
+ float32 k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B;\r
+\r
+ // Ensure a reasonable condition number.\r
+ const float32 k_maxConditionNumber = 100.0f;\r
+ if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))\r
+ {\r
+ // K is safe to invert.\r
+ cc->K.col1.Set(k11, k12);\r
+ cc->K.col2.Set(k12, k22);\r
+ cc->normalMass = cc->K.GetInverse();\r
+ }\r
+ else\r
+ {\r
+ // The constraints are redundant, just use one.\r
+ // TODO_ERIN use deepest?\r
+ cc->pointCount = 1;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+b2ContactSolver::~b2ContactSolver()\r
+{\r
+ m_allocator->Free(m_constraints);\r
+}\r
+\r
+void b2ContactSolver::WarmStart()\r
+{\r
+ // Warm start.\r
+ for (int32 i = 0; i < m_constraintCount; ++i)\r
+ {\r
+ b2ContactConstraint* c = m_constraints + i;\r
+\r
+ b2Body* bodyA = c->bodyA;\r
+ b2Body* bodyB = c->bodyB;\r
+ float32 invMassA = bodyA->m_invMass;\r
+ float32 invIA = bodyA->m_invI;\r
+ float32 invMassB = bodyB->m_invMass;\r
+ float32 invIB = bodyB->m_invI;\r
+ b2Vec2 normal = c->normal;\r
+ b2Vec2 tangent = b2Cross(normal, 1.0f);\r
+\r
+ for (int32 j = 0; j < c->pointCount; ++j)\r
+ {\r
+ b2ContactConstraintPoint* ccp = c->points + j;\r
+ b2Vec2 P = ccp->normalImpulse * normal + ccp->tangentImpulse * tangent;\r
+ bodyA->m_angularVelocity -= invIA * b2Cross(ccp->rA, P);\r
+ bodyA->m_linearVelocity -= invMassA * P;\r
+ bodyB->m_angularVelocity += invIB * b2Cross(ccp->rB, P);\r
+ bodyB->m_linearVelocity += invMassB * P;\r
+ }\r
+ }\r
+}\r
+\r
+void b2ContactSolver::SolveVelocityConstraints()\r
+{\r
+ for (int32 i = 0; i < m_constraintCount; ++i)\r
+ {\r
+ b2ContactConstraint* c = m_constraints + i;\r
+ b2Body* bodyA = c->bodyA;\r
+ b2Body* bodyB = c->bodyB;\r
+ float32 wA = bodyA->m_angularVelocity;\r
+ float32 wB = bodyB->m_angularVelocity;\r
+ b2Vec2 vA = bodyA->m_linearVelocity;\r
+ b2Vec2 vB = bodyB->m_linearVelocity;\r
+ float32 invMassA = bodyA->m_invMass;\r
+ float32 invIA = bodyA->m_invI;\r
+ float32 invMassB = bodyB->m_invMass;\r
+ float32 invIB = bodyB->m_invI;\r
+ b2Vec2 normal = c->normal;\r
+ b2Vec2 tangent = b2Cross(normal, 1.0f);\r
+ float32 friction = c->friction;\r
+\r
+ b2Assert(c->pointCount == 1 || c->pointCount == 2);\r
+\r
+ // Solve tangent constraints\r
+ for (int32 j = 0; j < c->pointCount; ++j)\r
+ {\r
+ b2ContactConstraintPoint* ccp = c->points + j;\r
+\r
+ // Relative velocity at contact\r
+ b2Vec2 dv = vB + b2Cross(wB, ccp->rB) - vA - b2Cross(wA, ccp->rA);\r
+\r
+ // Compute tangent force\r
+ float32 vt = b2Dot(dv, tangent);\r
+ float32 lambda = ccp->tangentMass * (-vt);\r
+\r
+ // b2Clamp the accumulated force\r
+ float32 maxFriction = friction * ccp->normalImpulse;\r
+ float32 newImpulse = b2Clamp(ccp->tangentImpulse + lambda, -maxFriction, maxFriction);\r
+ lambda = newImpulse - ccp->tangentImpulse;\r
+\r
+ // Apply contact impulse\r
+ b2Vec2 P = lambda * tangent;\r
+\r
+ vA -= invMassA * P;\r
+ wA -= invIA * b2Cross(ccp->rA, P);\r
+\r
+ vB += invMassB * P;\r
+ wB += invIB * b2Cross(ccp->rB, P);\r
+\r
+ ccp->tangentImpulse = newImpulse;\r
+ }\r
+\r
+ // Solve normal constraints\r
+ if (c->pointCount == 1)\r
+ {\r
+ b2ContactConstraintPoint* ccp = c->points + 0;\r
+\r
+ // Relative velocity at contact\r
+ b2Vec2 dv = vB + b2Cross(wB, ccp->rB) - vA - b2Cross(wA, ccp->rA);\r
+\r
+ // Compute normal impulse\r
+ float32 vn = b2Dot(dv, normal);\r
+ float32 lambda = -ccp->normalMass * (vn - ccp->velocityBias);\r
+\r
+ // b2Clamp the accumulated impulse\r
+ float32 newImpulse = b2Max(ccp->normalImpulse + lambda, 0.0f);\r
+ lambda = newImpulse - ccp->normalImpulse;\r
+\r
+ // Apply contact impulse\r
+ b2Vec2 P = lambda * normal;\r
+ vA -= invMassA * P;\r
+ wA -= invIA * b2Cross(ccp->rA, P);\r
+\r
+ vB += invMassB * P;\r
+ wB += invIB * b2Cross(ccp->rB, P);\r
+ ccp->normalImpulse = newImpulse;\r
+ }\r
+ else\r
+ {\r
+ // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).\r
+ // Build the mini LCP for this contact patch\r
+ //\r
+ // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2\r
+ //\r
+ // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )\r
+ // b = vn_0 - velocityBias\r
+ //\r
+ // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i\r
+ // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases\r
+ // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid\r
+ // solution that satisfies the problem is chosen.\r
+ // \r
+ // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires\r
+ // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).\r
+ //\r
+ // Substitute:\r
+ // \r
+ // x = x' - a\r
+ // \r
+ // Plug into above equation:\r
+ //\r
+ // vn = A * x + b\r
+ // = A * (x' - a) + b\r
+ // = A * x' + b - A * a\r
+ // = A * x' + b'\r
+ // b' = b - A * a;\r
+\r
+ b2ContactConstraintPoint* cp1 = c->points + 0;\r
+ b2ContactConstraintPoint* cp2 = c->points + 1;\r
+\r
+ b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse);\r
+ b2Assert(a.x >= 0.0f && a.y >= 0.0f);\r
+\r
+ // Relative velocity at contact\r
+ b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);\r
+ b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);\r
+\r
+ // Compute normal velocity\r
+ float32 vn1 = b2Dot(dv1, normal);\r
+ float32 vn2 = b2Dot(dv2, normal);\r
+\r
+ b2Vec2 b;\r
+ b.x = vn1 - cp1->velocityBias;\r
+ b.y = vn2 - cp2->velocityBias;\r
+ b -= b2Mul(c->K, a);\r
+\r
+ const float32 k_errorTol = 1e-3f;\r
+ B2_NOT_USED(k_errorTol);\r
+\r
+ for (;;)\r
+ {\r
+ //\r
+ // Case 1: vn = 0\r
+ //\r
+ // 0 = A * x' + b'\r
+ //\r
+ // Solve for x':\r
+ //\r
+ // x' = - inv(A) * b'\r
+ //\r
+ b2Vec2 x = - b2Mul(c->normalMass, b);\r
+\r
+ if (x.x >= 0.0f && x.y >= 0.0f)\r
+ {\r
+ // Resubstitute for the incremental impulse\r
+ b2Vec2 d = x - a;\r
+\r
+ // Apply incremental impulse\r
+ b2Vec2 P1 = d.x * normal;\r
+ b2Vec2 P2 = d.y * normal;\r
+ vA -= invMassA * (P1 + P2);\r
+ wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));\r
+\r
+ vB += invMassB * (P1 + P2);\r
+ wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));\r
+\r
+ // Accumulate\r
+ cp1->normalImpulse = x.x;\r
+ cp2->normalImpulse = x.y;\r
+\r
+#if B2_DEBUG_SOLVER == 1\r
+ // Postconditions\r
+ dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);\r
+ dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);\r
+\r
+ // Compute normal velocity\r
+ vn1 = b2Dot(dv1, normal);\r
+ vn2 = b2Dot(dv2, normal);\r
+\r
+ b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);\r
+ b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);\r
+#endif\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Case 2: vn1 = 0 and x2 = 0\r
+ //\r
+ // 0 = a11 * x1' + a12 * 0 + b1' \r
+ // vn2 = a21 * x1' + a22 * 0 + b2'\r
+ //\r
+ x.x = - cp1->normalMass * b.x;\r
+ x.y = 0.0f;\r
+ vn1 = 0.0f;\r
+ vn2 = c->K.col1.y * x.x + b.y;\r
+\r
+ if (x.x >= 0.0f && vn2 >= 0.0f)\r
+ {\r
+ // Resubstitute for the incremental impulse\r
+ b2Vec2 d = x - a;\r
+\r
+ // Apply incremental impulse\r
+ b2Vec2 P1 = d.x * normal;\r
+ b2Vec2 P2 = d.y * normal;\r
+ vA -= invMassA * (P1 + P2);\r
+ wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));\r
+\r
+ vB += invMassB * (P1 + P2);\r
+ wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));\r
+\r
+ // Accumulate\r
+ cp1->normalImpulse = x.x;\r
+ cp2->normalImpulse = x.y;\r
+\r
+#if B2_DEBUG_SOLVER == 1\r
+ // Postconditions\r
+ dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);\r
+\r
+ // Compute normal velocity\r
+ vn1 = b2Dot(dv1, normal);\r
+\r
+ b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);\r
+#endif\r
+ break;\r
+ }\r
+\r
+\r
+ //\r
+ // Case 3: vn2 = 0 and x1 = 0\r
+ //\r
+ // vn1 = a11 * 0 + a12 * x2' + b1' \r
+ // 0 = a21 * 0 + a22 * x2' + b2'\r
+ //\r
+ x.x = 0.0f;\r
+ x.y = - cp2->normalMass * b.y;\r
+ vn1 = c->K.col2.x * x.y + b.x;\r
+ vn2 = 0.0f;\r
+\r
+ if (x.y >= 0.0f && vn1 >= 0.0f)\r
+ {\r
+ // Resubstitute for the incremental impulse\r
+ b2Vec2 d = x - a;\r
+\r
+ // Apply incremental impulse\r
+ b2Vec2 P1 = d.x * normal;\r
+ b2Vec2 P2 = d.y * normal;\r
+ vA -= invMassA * (P1 + P2);\r
+ wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));\r
+\r
+ vB += invMassB * (P1 + P2);\r
+ wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));\r
+\r
+ // Accumulate\r
+ cp1->normalImpulse = x.x;\r
+ cp2->normalImpulse = x.y;\r
+\r
+#if B2_DEBUG_SOLVER == 1\r
+ // Postconditions\r
+ dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);\r
+\r
+ // Compute normal velocity\r
+ vn2 = b2Dot(dv2, normal);\r
+\r
+ b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);\r
+#endif\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Case 4: x1 = 0 and x2 = 0\r
+ // \r
+ // vn1 = b1\r
+ // vn2 = b2;\r
+ x.x = 0.0f;\r
+ x.y = 0.0f;\r
+ vn1 = b.x;\r
+ vn2 = b.y;\r
+\r
+ if (vn1 >= 0.0f && vn2 >= 0.0f )\r
+ {\r
+ // Resubstitute for the incremental impulse\r
+ b2Vec2 d = x - a;\r
+\r
+ // Apply incremental impulse\r
+ b2Vec2 P1 = d.x * normal;\r
+ b2Vec2 P2 = d.y * normal;\r
+ vA -= invMassA * (P1 + P2);\r
+ wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));\r
+\r
+ vB += invMassB * (P1 + P2);\r
+ wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));\r
+\r
+ // Accumulate\r
+ cp1->normalImpulse = x.x;\r
+ cp2->normalImpulse = x.y;\r
+\r
+ break;\r
+ }\r
+\r
+ // No solution, give up. This is hit sometimes, but it doesn't seem to matter.\r
+ break;\r
+ }\r
+ }\r
+\r
+ bodyA->m_linearVelocity = vA;\r
+ bodyA->m_angularVelocity = wA;\r
+ bodyB->m_linearVelocity = vB;\r
+ bodyB->m_angularVelocity = wB;\r
+ }\r
+}\r
+\r
+void b2ContactSolver::StoreImpulses()\r
+{\r
+ for (int32 i = 0; i < m_constraintCount; ++i)\r
+ {\r
+ b2ContactConstraint* c = m_constraints + i;\r
+ b2Manifold* m = c->manifold;\r
+\r
+ for (int32 j = 0; j < c->pointCount; ++j)\r
+ {\r
+ m->points[j].normalImpulse = c->points[j].normalImpulse;\r
+ m->points[j].tangentImpulse = c->points[j].tangentImpulse;\r
+ }\r
+ }\r
+}\r
+\r
+struct b2PositionSolverManifold\r
+{\r
+ void Initialize(b2ContactConstraint* cc, int32 index)\r
+ {\r
+ b2Assert(cc->pointCount > 0);\r
+\r
+ switch (cc->type)\r
+ {\r
+ case b2Manifold::e_circles:\r
+ {\r
+ b2Vec2 pointA = cc->bodyA->GetWorldPoint(cc->localPoint);\r
+ b2Vec2 pointB = cc->bodyB->GetWorldPoint(cc->points[0].localPoint);\r
+ if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)\r
+ {\r
+ normal = pointB - pointA;\r
+ normal.Normalize();\r
+ }\r
+ else\r
+ {\r
+ normal.Set(1.0f, 0.0f);\r
+ }\r
+\r
+ point = 0.5f * (pointA + pointB);\r
+ separation = b2Dot(pointB - pointA, normal) - cc->radius;\r
+ }\r
+ break;\r
+\r
+ case b2Manifold::e_faceA:\r
+ {\r
+ normal = cc->bodyA->GetWorldVector(cc->localNormal);\r
+ b2Vec2 planePoint = cc->bodyA->GetWorldPoint(cc->localPoint);\r
+\r
+ b2Vec2 clipPoint = cc->bodyB->GetWorldPoint(cc->points[index].localPoint);\r
+ separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;\r
+ point = clipPoint;\r
+ }\r
+ break;\r
+\r
+ case b2Manifold::e_faceB:\r
+ {\r
+ normal = cc->bodyB->GetWorldVector(cc->localNormal);\r
+ b2Vec2 planePoint = cc->bodyB->GetWorldPoint(cc->localPoint);\r
+\r
+ b2Vec2 clipPoint = cc->bodyA->GetWorldPoint(cc->points[index].localPoint);\r
+ separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;\r
+ point = clipPoint;\r
+\r
+ // Ensure normal points from A to B\r
+ normal = -normal;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ b2Vec2 normal;\r
+ b2Vec2 point;\r
+ float32 separation;\r
+};\r
+\r
+// Sequential solver.\r
+bool b2ContactSolver::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ float32 minSeparation = 0.0f;\r
+\r
+ for (int32 i = 0; i < m_constraintCount; ++i)\r
+ {\r
+ b2ContactConstraint* c = m_constraints + i;\r
+ b2Body* bodyA = c->bodyA;\r
+ b2Body* bodyB = c->bodyB;\r
+\r
+ float32 invMassA = bodyA->m_mass * bodyA->m_invMass;\r
+ float32 invIA = bodyA->m_mass * bodyA->m_invI;\r
+ float32 invMassB = bodyB->m_mass * bodyB->m_invMass;\r
+ float32 invIB = bodyB->m_mass * bodyB->m_invI;\r
+\r
+ // Solve normal constraints\r
+ for (int32 j = 0; j < c->pointCount; ++j)\r
+ {\r
+ b2PositionSolverManifold psm;\r
+ psm.Initialize(c, j);\r
+ b2Vec2 normal = psm.normal;\r
+\r
+ b2Vec2 point = psm.point;\r
+ float32 separation = psm.separation;\r
+\r
+ b2Vec2 rA = point - bodyA->m_sweep.c;\r
+ b2Vec2 rB = point - bodyB->m_sweep.c;\r
+\r
+ // Track max constraint error.\r
+ minSeparation = b2Min(minSeparation, separation);\r
+\r
+ // Prevent large corrections and allow slop.\r
+ float32 C = b2Clamp(baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);\r
+\r
+ // Compute the effective mass.\r
+ float32 rnA = b2Cross(rA, normal);\r
+ float32 rnB = b2Cross(rB, normal);\r
+ float32 K = invMassA + invMassB + invIA * rnA * rnA + invIB * rnB * rnB;\r
+\r
+ // Compute normal impulse\r
+ float32 impulse = K > 0.0f ? - C / K : 0.0f;\r
+\r
+ b2Vec2 P = impulse * normal;\r
+\r
+ bodyA->m_sweep.c -= invMassA * P;\r
+ bodyA->m_sweep.a -= invIA * b2Cross(rA, P);\r
+ bodyA->SynchronizeTransform();\r
+\r
+ bodyB->m_sweep.c += invMassB * P;\r
+ bodyB->m_sweep.a += invIB * b2Cross(rB, P);\r
+ bodyB->SynchronizeTransform();\r
+ }\r
+ }\r
+\r
+ // We can't expect minSpeparation >= -b2_linearSlop because we don't\r
+ // push the separation above -b2_linearSlop.\r
+ return minSeparation >= -1.5f * b2_linearSlop;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_CONTACT_SOLVER_H\r
+#define B2_CONTACT_SOLVER_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Dynamics/b2Island.h>\r
+\r
+class b2Contact;\r
+class b2Body;\r
+class b2StackAllocator;\r
+\r
+struct b2ContactConstraintPoint\r
+{\r
+ b2Vec2 localPoint;\r
+ b2Vec2 rA;\r
+ b2Vec2 rB;\r
+ float32 normalImpulse;\r
+ float32 tangentImpulse;\r
+ float32 normalMass;\r
+ float32 tangentMass;\r
+ float32 velocityBias;\r
+};\r
+\r
+struct b2ContactConstraint\r
+{\r
+ b2ContactConstraintPoint points[b2_maxManifoldPoints];\r
+ b2Vec2 localNormal;\r
+ b2Vec2 localPoint;\r
+ b2Vec2 normal;\r
+ b2Mat22 normalMass;\r
+ b2Mat22 K;\r
+ b2Body* bodyA;\r
+ b2Body* bodyB;\r
+ b2Manifold::Type type;\r
+ float32 radius;\r
+ float32 friction;\r
+ int32 pointCount;\r
+ b2Manifold* manifold;\r
+};\r
+\r
+class b2ContactSolver\r
+{\r
+public:\r
+ b2ContactSolver(b2Contact** contacts, int32 contactCount,\r
+ b2StackAllocator* allocator, float32 impulseRatio);\r
+\r
+ ~b2ContactSolver();\r
+\r
+ void WarmStart();\r
+ void SolveVelocityConstraints();\r
+ void StoreImpulses();\r
+\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2StackAllocator* m_allocator;\r
+ b2ContactConstraint* m_constraints;\r
+ int m_constraintCount;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2WorldCallbacks.h>\r
+\r
+#include <new>\r
+\r
+b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)\r
+{\r
+ void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact));\r
+ return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB);\r
+}\r
+\r
+void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)\r
+{\r
+ ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact();\r
+ allocator->Free(contact, sizeof(b2PolygonAndCircleContact));\r
+}\r
+\r
+b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)\r
+: b2Contact(fixtureA, fixtureB)\r
+{\r
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);\r
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);\r
+}\r
+\r
+void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)\r
+{\r
+ b2CollidePolygonAndCircle( manifold,\r
+ (b2PolygonShape*)m_fixtureA->GetShape(), xfA,\r
+ (b2CircleShape*)m_fixtureB->GetShape(), xfB);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H\r
+#define B2_POLYGON_AND_CIRCLE_CONTACT_H\r
+\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+\r
+class b2BlockAllocator;\r
+\r
+class b2PolygonAndCircleContact : public b2Contact\r
+{\r
+public:\r
+ static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);\r
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);\r
+\r
+ b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);\r
+ ~b2PolygonAndCircleContact() {}\r
+\r
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Contacts/b2PolygonContact.h>\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2WorldCallbacks.h>\r
+\r
+#include <new>\r
+\r
+b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)\r
+{\r
+ void* mem = allocator->Allocate(sizeof(b2PolygonContact));\r
+ return new (mem) b2PolygonContact(fixtureA, fixtureB);\r
+}\r
+\r
+void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)\r
+{\r
+ ((b2PolygonContact*)contact)->~b2PolygonContact();\r
+ allocator->Free(contact, sizeof(b2PolygonContact));\r
+}\r
+\r
+b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)\r
+ : b2Contact(fixtureA, fixtureB)\r
+{\r
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);\r
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);\r
+}\r
+\r
+void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)\r
+{\r
+ b2CollidePolygons( manifold,\r
+ (b2PolygonShape*)m_fixtureA->GetShape(), xfA,\r
+ (b2PolygonShape*)m_fixtureB->GetShape(), xfB);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_POLYGON_CONTACT_H\r
+#define B2_POLYGON_CONTACT_H\r
+\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+\r
+class b2BlockAllocator;\r
+\r
+class b2PolygonContact : public b2Contact\r
+{\r
+public:\r
+ static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);\r
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);\r
+\r
+ b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);\r
+ ~b2PolygonContact() {}\r
+\r
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Contacts/b2TOISolver.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Common/b2StackAllocator.h>\r
+\r
+struct b2TOIConstraint\r
+{\r
+ b2Vec2 localPoints[b2_maxManifoldPoints];\r
+ b2Vec2 localNormal;\r
+ b2Vec2 localPoint;\r
+ b2Manifold::Type type;\r
+ float32 radius;\r
+ int32 pointCount;\r
+ b2Body* bodyA;\r
+ b2Body* bodyB;\r
+};\r
+\r
+b2TOISolver::b2TOISolver(b2StackAllocator* allocator)\r
+{\r
+ m_allocator = allocator;\r
+ m_constraints = NULL;\r
+ m_count = NULL;\r
+ m_toiBody = NULL;\r
+}\r
+\r
+b2TOISolver::~b2TOISolver()\r
+{\r
+ Clear();\r
+}\r
+\r
+void b2TOISolver::Clear()\r
+{\r
+ if (m_allocator && m_constraints)\r
+ {\r
+ m_allocator->Free(m_constraints);\r
+ m_constraints = NULL;\r
+ }\r
+}\r
+\r
+void b2TOISolver::Initialize(b2Contact** contacts, int32 count, b2Body* toiBody)\r
+{\r
+ Clear();\r
+\r
+ m_count = count;\r
+ m_toiBody = toiBody;\r
+\r
+ m_constraints = (b2TOIConstraint*) m_allocator->Allocate(m_count * sizeof(b2TOIConstraint));\r
+\r
+ for (int32 i = 0; i < m_count; ++i)\r
+ {\r
+ b2Contact* contact = contacts[i];\r
+\r
+ b2Fixture* fixtureA = contact->GetFixtureA();\r
+ b2Fixture* fixtureB = contact->GetFixtureB();\r
+ b2Shape* shapeA = fixtureA->GetShape();\r
+ b2Shape* shapeB = fixtureB->GetShape();\r
+ float32 radiusA = shapeA->m_radius;\r
+ float32 radiusB = shapeB->m_radius;\r
+ b2Body* bodyA = fixtureA->GetBody();\r
+ b2Body* bodyB = fixtureB->GetBody();\r
+ b2Manifold* manifold = contact->GetManifold();\r
+\r
+ b2Assert(manifold->pointCount > 0);\r
+\r
+ b2TOIConstraint* constraint = m_constraints + i;\r
+ constraint->bodyA = bodyA;\r
+ constraint->bodyB = bodyB;\r
+ constraint->localNormal = manifold->localNormal;\r
+ constraint->localPoint = manifold->localPoint;\r
+ constraint->type = manifold->type;\r
+ constraint->pointCount = manifold->pointCount;\r
+ constraint->radius = radiusA + radiusB;\r
+\r
+ for (int32 j = 0; j < constraint->pointCount; ++j)\r
+ {\r
+ b2ManifoldPoint* cp = manifold->points + j;\r
+ constraint->localPoints[j] = cp->localPoint;\r
+ }\r
+ }\r
+}\r
+\r
+struct b2TOISolverManifold\r
+{\r
+ void Initialize(b2TOIConstraint* cc, int32 index)\r
+ {\r
+ b2Assert(cc->pointCount > 0);\r
+\r
+ switch (cc->type)\r
+ {\r
+ case b2Manifold::e_circles:\r
+ {\r
+ b2Vec2 pointA = cc->bodyA->GetWorldPoint(cc->localPoint);\r
+ b2Vec2 pointB = cc->bodyB->GetWorldPoint(cc->localPoints[0]);\r
+ if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)\r
+ {\r
+ normal = pointB - pointA;\r
+ normal.Normalize();\r
+ }\r
+ else\r
+ {\r
+ normal.Set(1.0f, 0.0f);\r
+ }\r
+\r
+ point = 0.5f * (pointA + pointB);\r
+ separation = b2Dot(pointB - pointA, normal) - cc->radius;\r
+ }\r
+ break;\r
+\r
+ case b2Manifold::e_faceA:\r
+ {\r
+ normal = cc->bodyA->GetWorldVector(cc->localNormal);\r
+ b2Vec2 planePoint = cc->bodyA->GetWorldPoint(cc->localPoint);\r
+\r
+ b2Vec2 clipPoint = cc->bodyB->GetWorldPoint(cc->localPoints[index]);\r
+ separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;\r
+ point = clipPoint;\r
+ }\r
+ break;\r
+\r
+ case b2Manifold::e_faceB:\r
+ {\r
+ normal = cc->bodyB->GetWorldVector(cc->localNormal);\r
+ b2Vec2 planePoint = cc->bodyB->GetWorldPoint(cc->localPoint);\r
+\r
+ b2Vec2 clipPoint = cc->bodyA->GetWorldPoint(cc->localPoints[index]);\r
+ separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;\r
+ point = clipPoint;\r
+\r
+ // Ensure normal points from A to B\r
+ normal = -normal;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ b2Vec2 normal;\r
+ b2Vec2 point;\r
+ float32 separation;\r
+};\r
+\r
+// Push out the toi body to provide clearance for further simulation.\r
+bool b2TOISolver::Solve(float32 baumgarte)\r
+{\r
+ float32 minSeparation = 0.0f;\r
+\r
+ for (int32 i = 0; i < m_count; ++i)\r
+ {\r
+ b2TOIConstraint* c = m_constraints + i;\r
+ b2Body* bodyA = c->bodyA;\r
+ b2Body* bodyB = c->bodyB;\r
+\r
+ float32 massA = bodyA->m_mass;\r
+ float32 massB = bodyB->m_mass;\r
+\r
+ // Only the TOI body should move.\r
+ if (bodyA == m_toiBody)\r
+ {\r
+ massB = 0.0f;\r
+ }\r
+ else\r
+ {\r
+ massA = 0.0f;\r
+ }\r
+\r
+ float32 invMassA = massA * bodyA->m_invMass;\r
+ float32 invIA = massA * bodyA->m_invI;\r
+ float32 invMassB = massB * bodyB->m_invMass;\r
+ float32 invIB = massB * bodyB->m_invI;\r
+\r
+ // Solve normal constraints\r
+ for (int32 j = 0; j < c->pointCount; ++j)\r
+ {\r
+ b2TOISolverManifold psm;\r
+ psm.Initialize(c, j);\r
+ b2Vec2 normal = psm.normal;\r
+\r
+ b2Vec2 point = psm.point;\r
+ float32 separation = psm.separation;\r
+\r
+ b2Vec2 rA = point - bodyA->m_sweep.c;\r
+ b2Vec2 rB = point - bodyB->m_sweep.c;\r
+\r
+ // Track max constraint error.\r
+ minSeparation = b2Min(minSeparation, separation);\r
+\r
+ // Prevent large corrections and allow slop.\r
+ float32 C = b2Clamp(baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);\r
+\r
+ // Compute the effective mass.\r
+ float32 rnA = b2Cross(rA, normal);\r
+ float32 rnB = b2Cross(rB, normal);\r
+ float32 K = invMassA + invMassB + invIA * rnA * rnA + invIB * rnB * rnB;\r
+\r
+ // Compute normal impulse\r
+ float32 impulse = K > 0.0f ? - C / K : 0.0f;\r
+\r
+ b2Vec2 P = impulse * normal;\r
+\r
+ bodyA->m_sweep.c -= invMassA * P;\r
+ bodyA->m_sweep.a -= invIA * b2Cross(rA, P);\r
+ bodyA->SynchronizeTransform();\r
+\r
+ bodyB->m_sweep.c += invMassB * P;\r
+ bodyB->m_sweep.a += invIB * b2Cross(rB, P);\r
+ bodyB->SynchronizeTransform();\r
+ }\r
+ }\r
+\r
+ // We can't expect minSpeparation >= -b2_linearSlop because we don't\r
+ // push the separation above -b2_linearSlop.\r
+ return minSeparation >= -1.5f * b2_linearSlop;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_TOI_SOLVER_H\r
+#define B2_TOI_SOLVER_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+\r
+class b2Contact;\r
+class b2Body;\r
+struct b2TOIConstraint;\r
+class b2StackAllocator;\r
+\r
+/// This is a pure position solver for a single movable body in contact with\r
+/// multiple non-moving bodies.\r
+class b2TOISolver\r
+{\r
+public:\r
+ b2TOISolver(b2StackAllocator* allocator);\r
+ ~b2TOISolver();\r
+\r
+ void Initialize(b2Contact** contacts, int32 contactCount, b2Body* toiBody);\r
+ void Clear();\r
+\r
+ // Perform one solver iteration. Returns true if converged.\r
+ bool Solve(float32 baumgarte);\r
+\r
+private:\r
+\r
+ b2TOIConstraint* m_constraints;\r
+ int32 m_count;\r
+ b2Body* m_toiBody;\r
+ b2StackAllocator* m_allocator;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// 1-D constrained system\r
+// m (v2 - v1) = lambda\r
+// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.\r
+// x2 = x1 + h * v2\r
+\r
+// 1-D mass-damper-spring system\r
+// m (v2 - v1) + h * d * v2 + h * k * \r
+\r
+// C = norm(p2 - p1) - L\r
+// u = (p2 - p1) / norm(p2 - p1)\r
+// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))\r
+// J = [-u -cross(r1, u) u cross(r2, u)]\r
+// K = J * invM * JT\r
+// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2\r
+\r
+void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,\r
+ const b2Vec2& anchor1, const b2Vec2& anchor2)\r
+{\r
+ bodyA = b1;\r
+ bodyB = b2;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor1);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor2);\r
+ b2Vec2 d = anchor2 - anchor1;\r
+ length = d.Length();\r
+}\r
+\r
+\r
+b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_localAnchor1 = def->localAnchorA;\r
+ m_localAnchor2 = def->localAnchorB;\r
+ m_length = def->length;\r
+ m_frequencyHz = def->frequencyHz;\r
+ m_dampingRatio = def->dampingRatio;\r
+ m_impulse = 0.0f;\r
+ m_gamma = 0.0f;\r
+ m_bias = 0.0f;\r
+}\r
+\r
+void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ // Compute the effective mass matrix.\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+ m_u = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;\r
+\r
+ // Handle singularity.\r
+ float32 length = m_u.Length();\r
+ if (length > b2_linearSlop)\r
+ {\r
+ m_u *= 1.0f / length;\r
+ }\r
+ else\r
+ {\r
+ m_u.Set(0.0f, 0.0f);\r
+ }\r
+\r
+ float32 cr1u = b2Cross(r1, m_u);\r
+ float32 cr2u = b2Cross(r2, m_u);\r
+ float32 invMass = b1->m_invMass + b1->m_invI * cr1u * cr1u + b2->m_invMass + b2->m_invI * cr2u * cr2u;\r
+\r
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;\r
+\r
+ if (m_frequencyHz > 0.0f)\r
+ {\r
+ float32 C = length - m_length;\r
+\r
+ // Frequency\r
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;\r
+\r
+ // Damping coefficient\r
+ float32 d = 2.0f * m_mass * m_dampingRatio * omega;\r
+\r
+ // Spring stiffness\r
+ float32 k = m_mass * omega * omega;\r
+\r
+ // magic formulas\r
+ m_gamma = step.dt * (d + step.dt * k);\r
+ m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;\r
+ m_bias = C * step.dt * k * m_gamma;\r
+\r
+ m_mass = invMass + m_gamma;\r
+ m_mass = m_mass != 0.0f ? 1.0f / m_mass : 0.0f;\r
+ }\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Scale the impulse to support a variable time step.\r
+ m_impulse *= step.dtRatio;\r
+\r
+ b2Vec2 P = m_impulse * m_u;\r
+ b1->m_linearVelocity -= b1->m_invMass * P;\r
+ b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);\r
+ b2->m_linearVelocity += b2->m_invMass * P;\r
+ b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);\r
+ }\r
+ else\r
+ {\r
+ m_impulse = 0.0f;\r
+ }\r
+}\r
+\r
+void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ B2_NOT_USED(step);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ // Cdot = dot(u, v + cross(w, r))\r
+ b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);\r
+ b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);\r
+ float32 Cdot = b2Dot(m_u, v2 - v1);\r
+\r
+ float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);\r
+ m_impulse += impulse;\r
+\r
+ b2Vec2 P = impulse * m_u;\r
+ b1->m_linearVelocity -= b1->m_invMass * P;\r
+ b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);\r
+ b2->m_linearVelocity += b2->m_invMass * P;\r
+ b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);\r
+}\r
+\r
+bool b2DistanceJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ if (m_frequencyHz > 0.0f)\r
+ {\r
+ // There is no position correction for soft distance constraints.\r
+ return true;\r
+ }\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;\r
+\r
+ float32 length = d.Normalize();\r
+ float32 C = length - m_length;\r
+ C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);\r
+\r
+ float32 impulse = -m_mass * C;\r
+ m_u = d;\r
+ b2Vec2 P = impulse * m_u;\r
+\r
+ b1->m_sweep.c -= b1->m_invMass * P;\r
+ b1->m_sweep.a -= b1->m_invI * b2Cross(r1, P);\r
+ b2->m_sweep.c += b2->m_invMass * P;\r
+ b2->m_sweep.a += b2->m_invI * b2Cross(r2, P);\r
+\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+\r
+ return b2Abs(C) < b2_linearSlop;\r
+}\r
+\r
+b2Vec2 b2DistanceJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchor1);\r
+}\r
+\r
+b2Vec2 b2DistanceJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor2);\r
+}\r
+\r
+b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ b2Vec2 F = (inv_dt * m_impulse) * m_u;\r
+ return F;\r
+}\r
+\r
+float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ B2_NOT_USED(inv_dt);\r
+ return 0.0f;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_DISTANCE_JOINT_H\r
+#define B2_DISTANCE_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Distance joint definition. This requires defining an\r
+/// anchor point on both bodies and the non-zero length of the\r
+/// distance joint. The definition uses local anchor points\r
+/// so that the initial configuration can violate the constraint\r
+/// slightly. This helps when saving and loading a game.\r
+/// @warning Do not use a zero or short length.\r
+struct b2DistanceJointDef : public b2JointDef\r
+{\r
+ b2DistanceJointDef()\r
+ {\r
+ type = e_distanceJoint;\r
+ localAnchorA.Set(0.0f, 0.0f);\r
+ localAnchorB.Set(0.0f, 0.0f);\r
+ length = 1.0f;\r
+ frequencyHz = 0.0f;\r
+ dampingRatio = 0.0f;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, and length using the world\r
+ /// anchors.\r
+ void Initialize(b2Body* bodyA, b2Body* bodyB,\r
+ const b2Vec2& anchorA, const b2Vec2& anchorB);\r
+\r
+ /// The local anchor point relative to body1's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to body2's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The natural length between the anchor points.\r
+ float32 length;\r
+\r
+ /// The mass-spring-damper frequency in Hertz.\r
+ float32 frequencyHz;\r
+\r
+ /// The damping ratio. 0 = no damping, 1 = critical damping.\r
+ float32 dampingRatio;\r
+};\r
+\r
+/// A distance joint constrains two points on two bodies\r
+/// to remain at a fixed distance from each other. You can view\r
+/// this as a massless, rigid rod.\r
+class b2DistanceJoint : public b2Joint\r
+{\r
+public:\r
+\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Set/get the natural length.\r
+ /// Manipulating the length can lead to non-physical behavior when the frequency is zero.\r
+ void SetLength(float32 length);\r
+ float32 GetLength() const;\r
+\r
+ // Set/get frequency in Hz.\r
+ void SetFrequency(float32 hz);\r
+ float32 GetFrequency() const;\r
+\r
+ // Set/get damping ratio.\r
+ void SetDampingRatio(float32 ratio);\r
+ float32 GetDampingRatio() const;\r
+\r
+protected:\r
+\r
+ friend class b2Joint;\r
+ b2DistanceJoint(const b2DistanceJointDef* data);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_localAnchor1;\r
+ b2Vec2 m_localAnchor2;\r
+ b2Vec2 m_u;\r
+ float32 m_frequencyHz;\r
+ float32 m_dampingRatio;\r
+ float32 m_gamma;\r
+ float32 m_bias;\r
+ float32 m_impulse;\r
+ float32 m_mass;\r
+ float32 m_length;\r
+};\r
+\r
+inline void b2DistanceJoint::SetLength(float32 length)\r
+{\r
+ m_length = length;\r
+}\r
+\r
+inline float32 b2DistanceJoint::GetLength() const\r
+{\r
+ return m_length;\r
+}\r
+\r
+inline void b2DistanceJoint::SetFrequency(float32 hz)\r
+{\r
+ m_frequencyHz = hz;\r
+}\r
+\r
+inline float32 b2DistanceJoint::GetFrequency() const\r
+{\r
+ return m_frequencyHz;\r
+}\r
+\r
+inline void b2DistanceJoint::SetDampingRatio(float32 ratio)\r
+{\r
+ m_dampingRatio = ratio;\r
+}\r
+\r
+inline float32 b2DistanceJoint::GetDampingRatio() const\r
+{\r
+ return m_dampingRatio;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Point-to-point constraint\r
+// Cdot = v2 - v1\r
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)\r
+// J = [-I -r1_skew I r2_skew ]\r
+// Identity used:\r
+// w k % (rx i + ry j) = w * (-ry i + rx j)\r
+\r
+// Angle constraint\r
+// Cdot = w2 - w1\r
+// J = [0 0 -1 0 0 1]\r
+// K = invI1 + invI2\r
+\r
+void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)\r
+{\r
+ bodyA = bA;\r
+ bodyB = bB;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor);\r
+}\r
+\r
+b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_localAnchorA = def->localAnchorA;\r
+ m_localAnchorB = def->localAnchorB;\r
+\r
+ m_linearImpulse.SetZero();\r
+ m_angularImpulse = 0.0f;\r
+\r
+ m_maxForce = def->maxForce;\r
+ m_maxTorque = def->maxTorque;\r
+}\r
+\r
+void b2FrictionJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* bA = m_bodyA;\r
+ b2Body* bB = m_bodyB;\r
+\r
+ // Compute the effective mass matrix.\r
+ b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());\r
+ b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());\r
+\r
+ // J = [-I -r1_skew I r2_skew]\r
+ // [ 0 -1 0 1]\r
+ // r_skew = [-ry; rx]\r
+\r
+ // Matlab\r
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]\r
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]\r
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]\r
+\r
+ float32 mA = bA->m_invMass, mB = bB->m_invMass;\r
+ float32 iA = bA->m_invI, iB = bB->m_invI;\r
+\r
+ b2Mat22 K1;\r
+ K1.col1.x = mA + mB; K1.col2.x = 0.0f;\r
+ K1.col1.y = 0.0f; K1.col2.y = mA + mB;\r
+\r
+ b2Mat22 K2;\r
+ K2.col1.x = iA * rA.y * rA.y; K2.col2.x = -iA * rA.x * rA.y;\r
+ K2.col1.y = -iA * rA.x * rA.y; K2.col2.y = iA * rA.x * rA.x;\r
+\r
+ b2Mat22 K3;\r
+ K3.col1.x = iB * rB.y * rB.y; K3.col2.x = -iB * rB.x * rB.y;\r
+ K3.col1.y = -iB * rB.x * rB.y; K3.col2.y = iB * rB.x * rB.x;\r
+\r
+ b2Mat22 K = K1 + K2 + K3;\r
+ m_linearMass = K.GetInverse();\r
+\r
+ m_angularMass = iA + iB;\r
+ if (m_angularMass > 0.0f)\r
+ {\r
+ m_angularMass = 1.0f / m_angularMass;\r
+ }\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Scale impulses to support a variable time step.\r
+ m_linearImpulse *= step.dtRatio;\r
+ m_angularImpulse *= step.dtRatio;\r
+\r
+ b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);\r
+\r
+ bA->m_linearVelocity -= mA * P;\r
+ bA->m_angularVelocity -= iA * (b2Cross(rA, P) + m_angularImpulse);\r
+\r
+ bB->m_linearVelocity += mB * P;\r
+ bB->m_angularVelocity += iB * (b2Cross(rB, P) + m_angularImpulse);\r
+ }\r
+ else\r
+ {\r
+ m_linearImpulse.SetZero();\r
+ m_angularImpulse = 0.0f;\r
+ }\r
+}\r
+\r
+void b2FrictionJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ B2_NOT_USED(step);\r
+\r
+ b2Body* bA = m_bodyA;\r
+ b2Body* bB = m_bodyB;\r
+\r
+ b2Vec2 vA = bA->m_linearVelocity;\r
+ float32 wA = bA->m_angularVelocity;\r
+ b2Vec2 vB = bB->m_linearVelocity;\r
+ float32 wB = bB->m_angularVelocity;\r
+\r
+ float32 mA = bA->m_invMass, mB = bB->m_invMass;\r
+ float32 iA = bA->m_invI, iB = bB->m_invI;\r
+\r
+ b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());\r
+ b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());\r
+\r
+ // Solve angular friction\r
+ {\r
+ float32 Cdot = wB - wA;\r
+ float32 impulse = -m_angularMass * Cdot;\r
+\r
+ float32 oldImpulse = m_angularImpulse;\r
+ float32 maxImpulse = step.dt * m_maxTorque;\r
+ m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);\r
+ impulse = m_angularImpulse - oldImpulse;\r
+\r
+ wA -= iA * impulse;\r
+ wB += iB * impulse;\r
+ }\r
+\r
+ // Solve linear friction\r
+ {\r
+ b2Vec2 Cdot = vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA);\r
+\r
+ b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);\r
+ b2Vec2 oldImpulse = m_linearImpulse;\r
+ m_linearImpulse += impulse;\r
+\r
+ float32 maxImpulse = step.dt * m_maxForce;\r
+\r
+ if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)\r
+ {\r
+ m_linearImpulse.Normalize();\r
+ m_linearImpulse *= maxImpulse;\r
+ }\r
+\r
+ impulse = m_linearImpulse - oldImpulse;\r
+\r
+ vA -= mA * impulse;\r
+ wA -= iA * b2Cross(rA, impulse);\r
+\r
+ vB += mB * impulse;\r
+ wB += iB * b2Cross(rB, impulse);\r
+ }\r
+\r
+ bA->m_linearVelocity = vA;\r
+ bA->m_angularVelocity = wA;\r
+ bB->m_linearVelocity = vB;\r
+ bB->m_angularVelocity = wB;\r
+}\r
+\r
+bool b2FrictionJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ return true;\r
+}\r
+\r
+b2Vec2 b2FrictionJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchorA);\r
+}\r
+\r
+b2Vec2 b2FrictionJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchorB);\r
+}\r
+\r
+b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ return inv_dt * m_linearImpulse;\r
+}\r
+\r
+float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ return inv_dt * m_angularImpulse;\r
+}\r
+\r
+void b2FrictionJoint::SetMaxForce(float32 force)\r
+{\r
+ b2Assert(b2IsValid(force) && force >= 0.0f);\r
+ m_maxForce = force;\r
+}\r
+\r
+float32 b2FrictionJoint::GetMaxForce() const\r
+{\r
+ return m_maxForce;\r
+}\r
+\r
+void b2FrictionJoint::SetMaxTorque(float32 torque)\r
+{\r
+ b2Assert(b2IsValid(torque) && torque >= 0.0f);\r
+ m_maxTorque = torque;\r
+}\r
+\r
+float32 b2FrictionJoint::GetMaxTorque() const\r
+{\r
+ return m_maxTorque;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_FRICTION_JOINT_H\r
+#define B2_FRICTION_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Friction joint definition.\r
+struct b2FrictionJointDef : public b2JointDef\r
+{\r
+ b2FrictionJointDef()\r
+ {\r
+ type = e_frictionJoint;\r
+ localAnchorA.SetZero();\r
+ localAnchorB.SetZero();\r
+ maxForce = 0.0f;\r
+ maxTorque = 0.0f;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, axis, and reference angle using the world\r
+ /// anchor and world axis.\r
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);\r
+\r
+ /// The local anchor point relative to bodyA's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to bodyB's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The maximum friction force in N.\r
+ float32 maxForce;\r
+\r
+ /// The maximum friction torque in N-m.\r
+ float32 maxTorque;\r
+};\r
+\r
+/// Friction joint. This is used for top-down friction.\r
+/// It provides 2D translational friction and angular friction.\r
+class b2FrictionJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Set the maximum friction force in N.\r
+ void SetMaxForce(float32 force);\r
+\r
+ /// Get the maximum friction force in N.\r
+ float32 GetMaxForce() const;\r
+\r
+ /// Set the maximum friction torque in N*m.\r
+ void SetMaxTorque(float32 torque);\r
+\r
+ /// Get the maximum friction torque in N*m.\r
+ float32 GetMaxTorque() const;\r
+\r
+protected:\r
+\r
+ friend class b2Joint;\r
+\r
+ b2FrictionJoint(const b2FrictionJointDef* def);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_localAnchorA;\r
+ b2Vec2 m_localAnchorB;\r
+\r
+ b2Mat22 m_linearMass;\r
+ float32 m_angularMass;\r
+\r
+ b2Vec2 m_linearImpulse;\r
+ float32 m_angularImpulse;\r
+\r
+ float32 m_maxForce;\r
+ float32 m_maxTorque;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Gear Joint:\r
+// C0 = (coordinate1 + ratio * coordinate2)_initial\r
+// C = C0 - (cordinate1 + ratio * coordinate2) = 0\r
+// Cdot = -(Cdot1 + ratio * Cdot2)\r
+// J = -[J1 ratio * J2]\r
+// K = J * invM * JT\r
+// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T\r
+//\r
+// Revolute:\r
+// coordinate = rotation\r
+// Cdot = angularVelocity\r
+// J = [0 0 1]\r
+// K = J * invM * JT = invI\r
+//\r
+// Prismatic:\r
+// coordinate = dot(p - pg, ug)\r
+// Cdot = dot(v + cross(w, r), ug)\r
+// J = [ug cross(r, ug)]\r
+// K = J * invM * JT = invMass + invI * cross(r, ug)^2\r
+\r
+b2GearJoint::b2GearJoint(const b2GearJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ b2JointType type1 = def->joint1->GetType();\r
+ b2JointType type2 = def->joint2->GetType();\r
+\r
+ b2Assert(type1 == e_revoluteJoint || type1 == e_prismaticJoint);\r
+ b2Assert(type2 == e_revoluteJoint || type2 == e_prismaticJoint);\r
+ b2Assert(def->joint1->GetBodyA()->GetType() == b2_staticBody);\r
+ b2Assert(def->joint2->GetBodyA()->GetType() == b2_staticBody);\r
+\r
+ m_revolute1 = NULL;\r
+ m_prismatic1 = NULL;\r
+ m_revolute2 = NULL;\r
+ m_prismatic2 = NULL;\r
+\r
+ float32 coordinate1, coordinate2;\r
+\r
+ m_ground1 = def->joint1->GetBodyA();\r
+ m_bodyA = def->joint1->GetBodyB();\r
+ if (type1 == e_revoluteJoint)\r
+ {\r
+ m_revolute1 = (b2RevoluteJoint*)def->joint1;\r
+ m_groundAnchor1 = m_revolute1->m_localAnchor1;\r
+ m_localAnchor1 = m_revolute1->m_localAnchor2;\r
+ coordinate1 = m_revolute1->GetJointAngle();\r
+ }\r
+ else\r
+ {\r
+ m_prismatic1 = (b2PrismaticJoint*)def->joint1;\r
+ m_groundAnchor1 = m_prismatic1->m_localAnchor1;\r
+ m_localAnchor1 = m_prismatic1->m_localAnchor2;\r
+ coordinate1 = m_prismatic1->GetJointTranslation();\r
+ }\r
+\r
+ m_ground2 = def->joint2->GetBodyA();\r
+ m_bodyB = def->joint2->GetBodyB();\r
+ if (type2 == e_revoluteJoint)\r
+ {\r
+ m_revolute2 = (b2RevoluteJoint*)def->joint2;\r
+ m_groundAnchor2 = m_revolute2->m_localAnchor1;\r
+ m_localAnchor2 = m_revolute2->m_localAnchor2;\r
+ coordinate2 = m_revolute2->GetJointAngle();\r
+ }\r
+ else\r
+ {\r
+ m_prismatic2 = (b2PrismaticJoint*)def->joint2;\r
+ m_groundAnchor2 = m_prismatic2->m_localAnchor1;\r
+ m_localAnchor2 = m_prismatic2->m_localAnchor2;\r
+ coordinate2 = m_prismatic2->GetJointTranslation();\r
+ }\r
+\r
+ m_ratio = def->ratio;\r
+\r
+ m_constant = coordinate1 + m_ratio * coordinate2;\r
+\r
+ m_impulse = 0.0f;\r
+}\r
+\r
+void b2GearJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* g1 = m_ground1;\r
+ b2Body* g2 = m_ground2;\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ float32 K = 0.0f;\r
+ m_J.SetZero();\r
+\r
+ if (m_revolute1)\r
+ {\r
+ m_J.angularA = -1.0f;\r
+ K += b1->m_invI;\r
+ }\r
+ else\r
+ {\r
+ b2Vec2 ug = b2Mul(g1->GetTransform().R, m_prismatic1->m_localXAxis1);\r
+ b2Vec2 r = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ float32 crug = b2Cross(r, ug);\r
+ m_J.linearA = -ug;\r
+ m_J.angularA = -crug;\r
+ K += b1->m_invMass + b1->m_invI * crug * crug;\r
+ }\r
+\r
+ if (m_revolute2)\r
+ {\r
+ m_J.angularB = -m_ratio;\r
+ K += m_ratio * m_ratio * b2->m_invI;\r
+ }\r
+ else\r
+ {\r
+ b2Vec2 ug = b2Mul(g2->GetTransform().R, m_prismatic2->m_localXAxis1);\r
+ b2Vec2 r = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+ float32 crug = b2Cross(r, ug);\r
+ m_J.linearB = -m_ratio * ug;\r
+ m_J.angularB = -m_ratio * crug;\r
+ K += m_ratio * m_ratio * (b2->m_invMass + b2->m_invI * crug * crug);\r
+ }\r
+\r
+ // Compute effective mass.\r
+ m_mass = K > 0.0f ? 1.0f / K : 0.0f;\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Warm starting.\r
+ b1->m_linearVelocity += b1->m_invMass * m_impulse * m_J.linearA;\r
+ b1->m_angularVelocity += b1->m_invI * m_impulse * m_J.angularA;\r
+ b2->m_linearVelocity += b2->m_invMass * m_impulse * m_J.linearB;\r
+ b2->m_angularVelocity += b2->m_invI * m_impulse * m_J.angularB;\r
+ }\r
+ else\r
+ {\r
+ m_impulse = 0.0f;\r
+ }\r
+}\r
+\r
+void b2GearJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ B2_NOT_USED(step);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ float32 Cdot = m_J.Compute( b1->m_linearVelocity, b1->m_angularVelocity,\r
+ b2->m_linearVelocity, b2->m_angularVelocity);\r
+\r
+ float32 impulse = m_mass * (-Cdot);\r
+ m_impulse += impulse;\r
+\r
+ b1->m_linearVelocity += b1->m_invMass * impulse * m_J.linearA;\r
+ b1->m_angularVelocity += b1->m_invI * impulse * m_J.angularA;\r
+ b2->m_linearVelocity += b2->m_invMass * impulse * m_J.linearB;\r
+ b2->m_angularVelocity += b2->m_invI * impulse * m_J.angularB;\r
+}\r
+\r
+bool b2GearJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+ \r
+ float32 linearError = 0.0f;\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ float32 coordinate1, coordinate2;\r
+ if (m_revolute1)\r
+ {\r
+ coordinate1 = m_revolute1->GetJointAngle();\r
+ }\r
+ else\r
+ {\r
+ coordinate1 = m_prismatic1->GetJointTranslation();\r
+ }\r
+\r
+ if (m_revolute2)\r
+ {\r
+ coordinate2 = m_revolute2->GetJointAngle();\r
+ }\r
+ else\r
+ {\r
+ coordinate2 = m_prismatic2->GetJointTranslation();\r
+ }\r
+\r
+ float32 C = m_constant - (coordinate1 + m_ratio * coordinate2);\r
+\r
+ float32 impulse = m_mass * (-C);\r
+\r
+ b1->m_sweep.c += b1->m_invMass * impulse * m_J.linearA;\r
+ b1->m_sweep.a += b1->m_invI * impulse * m_J.angularA;\r
+ b2->m_sweep.c += b2->m_invMass * impulse * m_J.linearB;\r
+ b2->m_sweep.a += b2->m_invI * impulse * m_J.angularB;\r
+\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+\r
+ // TODO_ERIN not implemented\r
+ return linearError < b2_linearSlop;\r
+}\r
+\r
+b2Vec2 b2GearJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchor1);\r
+}\r
+\r
+b2Vec2 b2GearJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor2);\r
+}\r
+\r
+b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ // TODO_ERIN not tested\r
+ b2Vec2 P = m_impulse * m_J.linearB;\r
+ return inv_dt * P;\r
+}\r
+\r
+float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ // TODO_ERIN not tested\r
+ b2Vec2 r = b2Mul(m_bodyB->GetTransform().R, m_localAnchor2 - m_bodyB->GetLocalCenter());\r
+ b2Vec2 P = m_impulse * m_J.linearB;\r
+ float32 L = m_impulse * m_J.angularB - b2Cross(r, P);\r
+ return inv_dt * L;\r
+}\r
+\r
+void b2GearJoint::SetRatio(float32 ratio)\r
+{\r
+ b2Assert(b2IsValid(ratio));\r
+ m_ratio = ratio;\r
+}\r
+\r
+float32 b2GearJoint::GetRatio() const\r
+{\r
+ return m_ratio;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_GEAR_JOINT_H\r
+#define B2_GEAR_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+class b2RevoluteJoint;\r
+class b2PrismaticJoint;\r
+\r
+/// Gear joint definition. This definition requires two existing\r
+/// revolute or prismatic joints (any combination will work).\r
+/// The provided joints must attach a dynamic body to a static body.\r
+struct b2GearJointDef : public b2JointDef\r
+{\r
+ b2GearJointDef()\r
+ {\r
+ type = e_gearJoint;\r
+ joint1 = NULL;\r
+ joint2 = NULL;\r
+ ratio = 1.0f;\r
+ }\r
+\r
+ /// The first revolute/prismatic joint attached to the gear joint.\r
+ b2Joint* joint1;\r
+\r
+ /// The second revolute/prismatic joint attached to the gear joint.\r
+ b2Joint* joint2;\r
+\r
+ /// The gear ratio.\r
+ /// @see b2GearJoint for explanation.\r
+ float32 ratio;\r
+};\r
+\r
+/// A gear joint is used to connect two joints together. Either joint\r
+/// can be a revolute or prismatic joint. You specify a gear ratio\r
+/// to bind the motions together:\r
+/// coordinate1 + ratio * coordinate2 = constant\r
+/// The ratio can be negative or positive. If one joint is a revolute joint\r
+/// and the other joint is a prismatic joint, then the ratio will have units\r
+/// of length or units of 1/length.\r
+/// @warning The revolute and prismatic joints must be attached to\r
+/// fixed bodies (which must be body1 on those joints).\r
+class b2GearJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Set/Get the gear ratio.\r
+ void SetRatio(float32 ratio);\r
+ float32 GetRatio() const;\r
+\r
+protected:\r
+\r
+ friend class b2Joint;\r
+ b2GearJoint(const b2GearJointDef* data);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Body* m_ground1;\r
+ b2Body* m_ground2;\r
+\r
+ // One of these is NULL.\r
+ b2RevoluteJoint* m_revolute1;\r
+ b2PrismaticJoint* m_prismatic1;\r
+\r
+ // One of these is NULL.\r
+ b2RevoluteJoint* m_revolute2;\r
+ b2PrismaticJoint* m_prismatic2;\r
+\r
+ b2Vec2 m_groundAnchor1;\r
+ b2Vec2 m_groundAnchor2;\r
+\r
+ b2Vec2 m_localAnchor1;\r
+ b2Vec2 m_localAnchor2;\r
+\r
+ b2Jacobian m_J;\r
+\r
+ float32 m_constant;\r
+ float32 m_ratio;\r
+\r
+ // Effective mass\r
+ float32 m_mass;\r
+\r
+ // Impulse for accumulation/warm starting.\r
+ float32 m_impulse;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2LineJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>\r
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2World.h>\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+\r
+#include <new>\r
+\r
+b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)\r
+{\r
+ b2Joint* joint = NULL;\r
+\r
+ switch (def->type)\r
+ {\r
+ case e_distanceJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2DistanceJoint));\r
+ joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_mouseJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2MouseJoint));\r
+ joint = new (mem) b2MouseJoint((b2MouseJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_prismaticJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));\r
+ joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_revoluteJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));\r
+ joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_pulleyJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2PulleyJoint));\r
+ joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_gearJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2GearJoint));\r
+ joint = new (mem) b2GearJoint((b2GearJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_lineJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2LineJoint));\r
+ joint = new (mem) b2LineJoint((b2LineJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ case e_weldJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2WeldJoint));\r
+ joint = new (mem) b2WeldJoint((b2WeldJointDef*)def);\r
+ }\r
+ break;\r
+ \r
+ case e_frictionJoint:\r
+ {\r
+ void* mem = allocator->Allocate(sizeof(b2FrictionJoint));\r
+ joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def);\r
+ }\r
+ break;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ break;\r
+ }\r
+\r
+ return joint;\r
+}\r
+\r
+void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator)\r
+{\r
+ joint->~b2Joint();\r
+ switch (joint->m_type)\r
+ {\r
+ case e_distanceJoint:\r
+ allocator->Free(joint, sizeof(b2DistanceJoint));\r
+ break;\r
+\r
+ case e_mouseJoint:\r
+ allocator->Free(joint, sizeof(b2MouseJoint));\r
+ break;\r
+\r
+ case e_prismaticJoint:\r
+ allocator->Free(joint, sizeof(b2PrismaticJoint));\r
+ break;\r
+\r
+ case e_revoluteJoint:\r
+ allocator->Free(joint, sizeof(b2RevoluteJoint));\r
+ break;\r
+\r
+ case e_pulleyJoint:\r
+ allocator->Free(joint, sizeof(b2PulleyJoint));\r
+ break;\r
+\r
+ case e_gearJoint:\r
+ allocator->Free(joint, sizeof(b2GearJoint));\r
+ break;\r
+\r
+ case e_lineJoint:\r
+ allocator->Free(joint, sizeof(b2LineJoint));\r
+ break;\r
+ \r
+ case e_weldJoint:\r
+ allocator->Free(joint, sizeof(b2WeldJoint));\r
+ break;\r
+\r
+ case e_frictionJoint:\r
+ allocator->Free(joint, sizeof(b2FrictionJoint));\r
+ break;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ break;\r
+ }\r
+}\r
+\r
+b2Joint::b2Joint(const b2JointDef* def)\r
+{\r
+ b2Assert(def->bodyA != def->bodyB);\r
+\r
+ m_type = def->type;\r
+ m_prev = NULL;\r
+ m_next = NULL;\r
+ m_bodyA = def->bodyA;\r
+ m_bodyB = def->bodyB;\r
+ m_collideConnected = def->collideConnected;\r
+ m_islandFlag = false;\r
+ m_userData = def->userData;\r
+\r
+ m_edgeA.joint = NULL;\r
+ m_edgeA.other = NULL;\r
+ m_edgeA.prev = NULL;\r
+ m_edgeA.next = NULL;\r
+\r
+ m_edgeB.joint = NULL;\r
+ m_edgeB.other = NULL;\r
+ m_edgeB.prev = NULL;\r
+ m_edgeB.next = NULL;\r
+}\r
+\r
+bool b2Joint::IsActive() const\r
+{\r
+ return m_bodyA->IsActive() && m_bodyB->IsActive();\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_JOINT_H\r
+#define B2_JOINT_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+\r
+class b2Body;\r
+class b2Joint;\r
+struct b2TimeStep;\r
+class b2BlockAllocator;\r
+\r
+enum b2JointType\r
+{\r
+ e_unknownJoint,\r
+ e_revoluteJoint,\r
+ e_prismaticJoint,\r
+ e_distanceJoint,\r
+ e_pulleyJoint,\r
+ e_mouseJoint,\r
+ e_gearJoint,\r
+ e_lineJoint,\r
+ e_weldJoint,\r
+ e_frictionJoint,\r
+};\r
+\r
+enum b2LimitState\r
+{\r
+ e_inactiveLimit,\r
+ e_atLowerLimit,\r
+ e_atUpperLimit,\r
+ e_equalLimits\r
+};\r
+\r
+struct b2Jacobian\r
+{\r
+ b2Vec2 linearA;\r
+ float32 angularA;\r
+ b2Vec2 linearB;\r
+ float32 angularB;\r
+\r
+ void SetZero();\r
+ void Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2);\r
+ float32 Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2);\r
+};\r
+\r
+/// A joint edge is used to connect bodies and joints together\r
+/// in a joint graph where each body is a node and each joint\r
+/// is an edge. A joint edge belongs to a doubly linked list\r
+/// maintained in each attached body. Each joint has two joint\r
+/// nodes, one for each attached body.\r
+struct b2JointEdge\r
+{\r
+ b2Body* other; ///< provides quick access to the other body attached.\r
+ b2Joint* joint; ///< the joint\r
+ b2JointEdge* prev; ///< the previous joint edge in the body's joint list\r
+ b2JointEdge* next; ///< the next joint edge in the body's joint list\r
+};\r
+\r
+/// Joint definitions are used to construct joints.\r
+struct b2JointDef\r
+{\r
+ b2JointDef()\r
+ {\r
+ type = e_unknownJoint;\r
+ userData = NULL;\r
+ bodyA = NULL;\r
+ bodyB = NULL;\r
+ collideConnected = false;\r
+ }\r
+\r
+ /// The joint type is set automatically for concrete joint types.\r
+ b2JointType type;\r
+\r
+ /// Use this to attach application specific data to your joints.\r
+ void* userData;\r
+\r
+ /// The first attached body.\r
+ b2Body* bodyA;\r
+\r
+ /// The second attached body.\r
+ b2Body* bodyB;\r
+\r
+ /// Set this flag to true if the attached bodies should collide.\r
+ bool collideConnected;\r
+};\r
+\r
+/// The base joint class. Joints are used to constraint two bodies together in\r
+/// various fashions. Some joints also feature limits and motors.\r
+class b2Joint\r
+{\r
+public:\r
+\r
+ /// Get the type of the concrete joint.\r
+ b2JointType GetType() const;\r
+\r
+ /// Get the first body attached to this joint.\r
+ b2Body* GetBodyA();\r
+\r
+ /// Get the second body attached to this joint.\r
+ b2Body* GetBodyB();\r
+\r
+ /// Get the anchor point on bodyA in world coordinates.\r
+ virtual b2Vec2 GetAnchorA() const = 0;\r
+\r
+ /// Get the anchor point on bodyB in world coordinates.\r
+ virtual b2Vec2 GetAnchorB() const = 0;\r
+\r
+ /// Get the reaction force on body2 at the joint anchor in Newtons.\r
+ virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0;\r
+\r
+ /// Get the reaction torque on body2 in N*m.\r
+ virtual float32 GetReactionTorque(float32 inv_dt) const = 0;\r
+\r
+ /// Get the next joint the world joint list.\r
+ b2Joint* GetNext();\r
+\r
+ /// Get the user data pointer.\r
+ void* GetUserData() const;\r
+\r
+ /// Set the user data pointer.\r
+ void SetUserData(void* data);\r
+\r
+ /// Short-cut function to determine if either body is inactive.\r
+ bool IsActive() const;\r
+\r
+protected:\r
+ friend class b2World;\r
+ friend class b2Body;\r
+ friend class b2Island;\r
+\r
+ static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);\r
+ static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);\r
+\r
+ b2Joint(const b2JointDef* def);\r
+ virtual ~b2Joint() {}\r
+\r
+ virtual void InitVelocityConstraints(const b2TimeStep& step) = 0;\r
+ virtual void SolveVelocityConstraints(const b2TimeStep& step) = 0;\r
+\r
+ // This returns true if the position errors are within tolerance.\r
+ virtual bool SolvePositionConstraints(float32 baumgarte) = 0;\r
+\r
+ b2JointType m_type;\r
+ b2Joint* m_prev;\r
+ b2Joint* m_next;\r
+ b2JointEdge m_edgeA;\r
+ b2JointEdge m_edgeB;\r
+ b2Body* m_bodyA;\r
+ b2Body* m_bodyB;\r
+\r
+ bool m_islandFlag;\r
+ bool m_collideConnected;\r
+\r
+ void* m_userData;\r
+\r
+ // Cache here per time step to reduce cache misses.\r
+ b2Vec2 m_localCenterA, m_localCenterB;\r
+ float32 m_invMassA, m_invIA;\r
+ float32 m_invMassB, m_invIB;\r
+};\r
+\r
+inline void b2Jacobian::SetZero()\r
+{\r
+ linearA.SetZero(); angularA = 0.0f;\r
+ linearB.SetZero(); angularB = 0.0f;\r
+}\r
+\r
+inline void b2Jacobian::Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2)\r
+{\r
+ linearA = x1; angularA = a1;\r
+ linearB = x2; angularB = a2;\r
+}\r
+\r
+inline float32 b2Jacobian::Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2)\r
+{\r
+ return b2Dot(linearA, x1) + angularA * a1 + b2Dot(linearB, x2) + angularB * a2;\r
+}\r
+\r
+inline b2JointType b2Joint::GetType() const\r
+{\r
+ return m_type;\r
+}\r
+\r
+inline b2Body* b2Joint::GetBodyA()\r
+{\r
+ return m_bodyA;\r
+}\r
+\r
+inline b2Body* b2Joint::GetBodyB()\r
+{\r
+ return m_bodyB;\r
+}\r
+\r
+inline b2Joint* b2Joint::GetNext()\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline void* b2Joint::GetUserData() const\r
+{\r
+ return m_userData;\r
+}\r
+\r
+inline void b2Joint::SetUserData(void* data)\r
+{\r
+ m_userData = data;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2LineJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Linear constraint (point-to-line)\r
+// d = p2 - p1 = x2 + r2 - x1 - r1\r
+// C = dot(perp, d)\r
+// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))\r
+// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)\r
+// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]\r
+//\r
+// K = J * invM * JT\r
+//\r
+// J = [-a -s1 a s2]\r
+// a = perp\r
+// s1 = cross(d + r1, a) = cross(p2 - x1, a)\r
+// s2 = cross(r2, a) = cross(p2 - x2, a)\r
+\r
+\r
+// Motor/Limit linear constraint\r
+// C = dot(ax1, d)\r
+// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)\r
+// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]\r
+\r
+// Block Solver\r
+// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even\r
+// when the mass has poor distribution (leading to large torques about the joint anchor points).\r
+//\r
+// The Jacobian has 3 rows:\r
+// J = [-uT -s1 uT s2] // linear\r
+// [-vT -a1 vT a2] // limit\r
+//\r
+// u = perp\r
+// v = axis\r
+// s1 = cross(d + r1, u), s2 = cross(r2, u)\r
+// a1 = cross(d + r1, v), a2 = cross(r2, v)\r
+\r
+// M * (v2 - v1) = JT * df\r
+// J * v2 = bias\r
+//\r
+// v2 = v1 + invM * JT * df\r
+// J * (v1 + invM * JT * df) = bias\r
+// K * df = bias - J * v1 = -Cdot\r
+// K = J * invM * JT\r
+// Cdot = J * v1 - bias\r
+//\r
+// Now solve for f2.\r
+// df = f2 - f1\r
+// K * (f2 - f1) = -Cdot\r
+// f2 = invK * (-Cdot) + f1\r
+//\r
+// Clamp accumulated limit impulse.\r
+// lower: f2(2) = max(f2(2), 0)\r
+// upper: f2(2) = min(f2(2), 0)\r
+//\r
+// Solve for correct f2(1)\r
+// K(1,1) * f2(1) = -Cdot(1) - K(1,2) * f2(2) + K(1,1:2) * f1\r
+// = -Cdot(1) - K(1,2) * f2(2) + K(1,1) * f1(1) + K(1,2) * f1(2)\r
+// K(1,1) * f2(1) = -Cdot(1) - K(1,2) * (f2(2) - f1(2)) + K(1,1) * f1(1)\r
+// f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)\r
+//\r
+// Now compute impulse to be applied:\r
+// df = f2 - f1\r
+\r
+void b2LineJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis)\r
+{\r
+ bodyA = b1;\r
+ bodyB = b2;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor);\r
+ localAxisA = bodyA->GetLocalVector(axis);\r
+}\r
+\r
+b2LineJoint::b2LineJoint(const b2LineJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_localAnchor1 = def->localAnchorA;\r
+ m_localAnchor2 = def->localAnchorB;\r
+ m_localXAxis1 = def->localAxisA;\r
+ m_localYAxis1 = b2Cross(1.0f, m_localXAxis1);\r
+\r
+ m_impulse.SetZero();\r
+ m_motorMass = 0.0;\r
+ m_motorImpulse = 0.0f;\r
+\r
+ m_lowerTranslation = def->lowerTranslation;\r
+ m_upperTranslation = def->upperTranslation;\r
+ m_maxMotorForce = def->maxMotorForce;\r
+ m_motorSpeed = def->motorSpeed;\r
+ m_enableLimit = def->enableLimit;\r
+ m_enableMotor = def->enableMotor;\r
+ m_limitState = e_inactiveLimit;\r
+\r
+ m_axis.SetZero();\r
+ m_perp.SetZero();\r
+}\r
+\r
+void b2LineJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ m_localCenterA = b1->GetLocalCenter();\r
+ m_localCenterB = b2->GetLocalCenter();\r
+\r
+ b2Transform xf1 = b1->GetTransform();\r
+ b2Transform xf2 = b2->GetTransform();\r
+\r
+ // Compute the effective masses.\r
+ b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenterA);\r
+ b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenterB);\r
+ b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;\r
+\r
+ m_invMassA = b1->m_invMass;\r
+ m_invIA = b1->m_invI;\r
+ m_invMassB = b2->m_invMass;\r
+ m_invIB = b2->m_invI;\r
+\r
+ // Compute motor Jacobian and effective mass.\r
+ {\r
+ m_axis = b2Mul(xf1.R, m_localXAxis1);\r
+ m_a1 = b2Cross(d + r1, m_axis);\r
+ m_a2 = b2Cross(r2, m_axis);\r
+\r
+ m_motorMass = m_invMassA + m_invMassB + m_invIA * m_a1 * m_a1 + m_invIB * m_a2 * m_a2;\r
+ if (m_motorMass > b2_epsilon)\r
+ {\r
+ m_motorMass = 1.0f / m_motorMass;\r
+ }\r
+ else\r
+ {\r
+ m_motorMass = 0.0f;\r
+ }\r
+ }\r
+\r
+ // Prismatic constraint.\r
+ {\r
+ m_perp = b2Mul(xf1.R, m_localYAxis1);\r
+\r
+ m_s1 = b2Cross(d + r1, m_perp);\r
+ m_s2 = b2Cross(r2, m_perp);\r
+\r
+ float32 m1 = m_invMassA, m2 = m_invMassB;\r
+ float32 i1 = m_invIA, i2 = m_invIB;\r
+\r
+ float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;\r
+ float32 k12 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;\r
+ float32 k22 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;\r
+\r
+ m_K.col1.Set(k11, k12);\r
+ m_K.col2.Set(k12, k22);\r
+ }\r
+\r
+ // Compute motor and limit terms.\r
+ if (m_enableLimit)\r
+ {\r
+ float32 jointTranslation = b2Dot(m_axis, d);\r
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)\r
+ {\r
+ m_limitState = e_equalLimits;\r
+ }\r
+ else if (jointTranslation <= m_lowerTranslation)\r
+ {\r
+ if (m_limitState != e_atLowerLimit)\r
+ {\r
+ m_limitState = e_atLowerLimit;\r
+ m_impulse.y = 0.0f;\r
+ }\r
+ }\r
+ else if (jointTranslation >= m_upperTranslation)\r
+ {\r
+ if (m_limitState != e_atUpperLimit)\r
+ {\r
+ m_limitState = e_atUpperLimit;\r
+ m_impulse.y = 0.0f;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_limitState = e_inactiveLimit;\r
+ m_impulse.y = 0.0f;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_limitState = e_inactiveLimit;\r
+ }\r
+\r
+ if (m_enableMotor == false)\r
+ {\r
+ m_motorImpulse = 0.0f;\r
+ }\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Account for variable time step.\r
+ m_impulse *= step.dtRatio;\r
+ m_motorImpulse *= step.dtRatio;\r
+\r
+ b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.y) * m_axis;\r
+ float32 L1 = m_impulse.x * m_s1 + (m_motorImpulse + m_impulse.y) * m_a1;\r
+ float32 L2 = m_impulse.x * m_s2 + (m_motorImpulse + m_impulse.y) * m_a2;\r
+\r
+ b1->m_linearVelocity -= m_invMassA * P;\r
+ b1->m_angularVelocity -= m_invIA * L1;\r
+\r
+ b2->m_linearVelocity += m_invMassB * P;\r
+ b2->m_angularVelocity += m_invIB * L2;\r
+ }\r
+ else\r
+ {\r
+ m_impulse.SetZero();\r
+ m_motorImpulse = 0.0f;\r
+ }\r
+}\r
+\r
+void b2LineJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 v1 = b1->m_linearVelocity;\r
+ float32 w1 = b1->m_angularVelocity;\r
+ b2Vec2 v2 = b2->m_linearVelocity;\r
+ float32 w2 = b2->m_angularVelocity;\r
+\r
+ // Solve linear motor constraint.\r
+ if (m_enableMotor && m_limitState != e_equalLimits)\r
+ {\r
+ float32 Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;\r
+ float32 impulse = m_motorMass * (m_motorSpeed - Cdot);\r
+ float32 oldImpulse = m_motorImpulse;\r
+ float32 maxImpulse = step.dt * m_maxMotorForce;\r
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);\r
+ impulse = m_motorImpulse - oldImpulse;\r
+\r
+ b2Vec2 P = impulse * m_axis;\r
+ float32 L1 = impulse * m_a1;\r
+ float32 L2 = impulse * m_a2;\r
+\r
+ v1 -= m_invMassA * P;\r
+ w1 -= m_invIA * L1;\r
+\r
+ v2 += m_invMassB * P;\r
+ w2 += m_invIB * L2;\r
+ }\r
+\r
+ float32 Cdot1 = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1;\r
+\r
+ if (m_enableLimit && m_limitState != e_inactiveLimit)\r
+ {\r
+ // Solve prismatic and limit constraint in block form.\r
+ float32 Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;\r
+ b2Vec2 Cdot(Cdot1, Cdot2);\r
+\r
+ b2Vec2 f1 = m_impulse;\r
+ b2Vec2 df = m_K.Solve(-Cdot);\r
+ m_impulse += df;\r
+\r
+ if (m_limitState == e_atLowerLimit)\r
+ {\r
+ m_impulse.y = b2Max(m_impulse.y, 0.0f);\r
+ }\r
+ else if (m_limitState == e_atUpperLimit)\r
+ {\r
+ m_impulse.y = b2Min(m_impulse.y, 0.0f);\r
+ }\r
+\r
+ // f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)\r
+ float32 b = -Cdot1 - (m_impulse.y - f1.y) * m_K.col2.x;\r
+ float32 f2r;\r
+ if (m_K.col1.x != 0.0f)\r
+ {\r
+ f2r = b / m_K.col1.x + f1.x;\r
+ }\r
+ else\r
+ {\r
+ f2r = f1.x; \r
+ }\r
+\r
+ m_impulse.x = f2r;\r
+\r
+ df = m_impulse - f1;\r
+\r
+ b2Vec2 P = df.x * m_perp + df.y * m_axis;\r
+ float32 L1 = df.x * m_s1 + df.y * m_a1;\r
+ float32 L2 = df.x * m_s2 + df.y * m_a2;\r
+\r
+ v1 -= m_invMassA * P;\r
+ w1 -= m_invIA * L1;\r
+\r
+ v2 += m_invMassB * P;\r
+ w2 += m_invIB * L2;\r
+ }\r
+ else\r
+ {\r
+ // Limit is inactive, just solve the prismatic constraint in block form.\r
+ float32 df;\r
+ if (m_K.col1.x != 0.0f)\r
+ {\r
+ df = - Cdot1 / m_K.col1.x;\r
+ }\r
+ else\r
+ {\r
+ df = 0.0f;\r
+ }\r
+ m_impulse.x += df;\r
+\r
+ b2Vec2 P = df * m_perp;\r
+ float32 L1 = df * m_s1;\r
+ float32 L2 = df * m_s2;\r
+\r
+ v1 -= m_invMassA * P;\r
+ w1 -= m_invIA * L1;\r
+\r
+ v2 += m_invMassB * P;\r
+ w2 += m_invIB * L2;\r
+ }\r
+\r
+ b1->m_linearVelocity = v1;\r
+ b1->m_angularVelocity = w1;\r
+ b2->m_linearVelocity = v2;\r
+ b2->m_angularVelocity = w2;\r
+}\r
+\r
+bool b2LineJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 c1 = b1->m_sweep.c;\r
+ float32 a1 = b1->m_sweep.a;\r
+\r
+ b2Vec2 c2 = b2->m_sweep.c;\r
+ float32 a2 = b2->m_sweep.a;\r
+\r
+ // Solve linear limit constraint.\r
+ float32 linearError = 0.0f, angularError = 0.0f;\r
+ bool active = false;\r
+ float32 C2 = 0.0f;\r
+\r
+ b2Mat22 R1(a1), R2(a2);\r
+\r
+ b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenterA);\r
+ b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenterB);\r
+ b2Vec2 d = c2 + r2 - c1 - r1;\r
+\r
+ if (m_enableLimit)\r
+ {\r
+ m_axis = b2Mul(R1, m_localXAxis1);\r
+\r
+ m_a1 = b2Cross(d + r1, m_axis);\r
+ m_a2 = b2Cross(r2, m_axis);\r
+\r
+ float32 translation = b2Dot(m_axis, d);\r
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)\r
+ {\r
+ // Prevent large angular corrections\r
+ C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);\r
+ linearError = b2Abs(translation);\r
+ active = true;\r
+ }\r
+ else if (translation <= m_lowerTranslation)\r
+ {\r
+ // Prevent large linear corrections and allow some slop.\r
+ C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);\r
+ linearError = m_lowerTranslation - translation;\r
+ active = true;\r
+ }\r
+ else if (translation >= m_upperTranslation)\r
+ {\r
+ // Prevent large linear corrections and allow some slop.\r
+ C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);\r
+ linearError = translation - m_upperTranslation;\r
+ active = true;\r
+ }\r
+ }\r
+\r
+ m_perp = b2Mul(R1, m_localYAxis1);\r
+\r
+ m_s1 = b2Cross(d + r1, m_perp);\r
+ m_s2 = b2Cross(r2, m_perp);\r
+\r
+ b2Vec2 impulse;\r
+ float32 C1;\r
+ C1 = b2Dot(m_perp, d);\r
+\r
+ linearError = b2Max(linearError, b2Abs(C1));\r
+ angularError = 0.0f;\r
+\r
+ if (active)\r
+ {\r
+ float32 m1 = m_invMassA, m2 = m_invMassB;\r
+ float32 i1 = m_invIA, i2 = m_invIB;\r
+\r
+ float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;\r
+ float32 k12 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;\r
+ float32 k22 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;\r
+\r
+ m_K.col1.Set(k11, k12);\r
+ m_K.col2.Set(k12, k22);\r
+\r
+ b2Vec2 C;\r
+ C.x = C1;\r
+ C.y = C2;\r
+\r
+ impulse = m_K.Solve(-C);\r
+ }\r
+ else\r
+ {\r
+ float32 m1 = m_invMassA, m2 = m_invMassB;\r
+ float32 i1 = m_invIA, i2 = m_invIB;\r
+\r
+ float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;\r
+\r
+ float32 impulse1;\r
+ if (k11 != 0.0f)\r
+ {\r
+ impulse1 = - C1 / k11;\r
+ }\r
+ else\r
+ {\r
+ impulse1 = 0.0f;\r
+ }\r
+\r
+ impulse.x = impulse1;\r
+ impulse.y = 0.0f;\r
+ }\r
+\r
+ b2Vec2 P = impulse.x * m_perp + impulse.y * m_axis;\r
+ float32 L1 = impulse.x * m_s1 + impulse.y * m_a1;\r
+ float32 L2 = impulse.x * m_s2 + impulse.y * m_a2;\r
+\r
+ c1 -= m_invMassA * P;\r
+ a1 -= m_invIA * L1;\r
+ c2 += m_invMassB * P;\r
+ a2 += m_invIB * L2;\r
+\r
+ // TODO_ERIN remove need for this.\r
+ b1->m_sweep.c = c1;\r
+ b1->m_sweep.a = a1;\r
+ b2->m_sweep.c = c2;\r
+ b2->m_sweep.a = a2;\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+\r
+ return linearError <= b2_linearSlop && angularError <= b2_angularSlop;\r
+}\r
+\r
+b2Vec2 b2LineJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchor1);\r
+}\r
+\r
+b2Vec2 b2LineJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor2);\r
+}\r
+\r
+b2Vec2 b2LineJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.y) * m_axis);\r
+}\r
+\r
+float32 b2LineJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ B2_NOT_USED(inv_dt);\r
+ return 0.0f;\r
+}\r
+\r
+float32 b2LineJoint::GetJointTranslation() const\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1);\r
+ b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2);\r
+ b2Vec2 d = p2 - p1;\r
+ b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);\r
+\r
+ float32 translation = b2Dot(d, axis);\r
+ return translation;\r
+}\r
+\r
+float32 b2LineJoint::GetJointSpeed() const\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+ b2Vec2 p1 = b1->m_sweep.c + r1;\r
+ b2Vec2 p2 = b2->m_sweep.c + r2;\r
+ b2Vec2 d = p2 - p1;\r
+ b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);\r
+\r
+ b2Vec2 v1 = b1->m_linearVelocity;\r
+ b2Vec2 v2 = b2->m_linearVelocity;\r
+ float32 w1 = b1->m_angularVelocity;\r
+ float32 w2 = b2->m_angularVelocity;\r
+\r
+ float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1));\r
+ return speed;\r
+}\r
+\r
+bool b2LineJoint::IsLimitEnabled() const\r
+{\r
+ return m_enableLimit;\r
+}\r
+\r
+void b2LineJoint::EnableLimit(bool flag)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_enableLimit = flag;\r
+}\r
+\r
+float32 b2LineJoint::GetLowerLimit() const\r
+{\r
+ return m_lowerTranslation;\r
+}\r
+\r
+float32 b2LineJoint::GetUpperLimit() const\r
+{\r
+ return m_upperTranslation;\r
+}\r
+\r
+void b2LineJoint::SetLimits(float32 lower, float32 upper)\r
+{\r
+ b2Assert(lower <= upper);\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_lowerTranslation = lower;\r
+ m_upperTranslation = upper;\r
+}\r
+\r
+bool b2LineJoint::IsMotorEnabled() const\r
+{\r
+ return m_enableMotor;\r
+}\r
+\r
+void b2LineJoint::EnableMotor(bool flag)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_enableMotor = flag;\r
+}\r
+\r
+void b2LineJoint::SetMotorSpeed(float32 speed)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_motorSpeed = speed;\r
+}\r
+\r
+void b2LineJoint::SetMaxMotorForce(float32 force)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_maxMotorForce = force;\r
+}\r
+\r
+float32 b2LineJoint::GetMotorForce() const\r
+{\r
+ return m_motorImpulse;\r
+}\r
+\r
+\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_LINE_JOINT_H\r
+#define B2_LINE_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Line joint definition. This requires defining a line of\r
+/// motion using an axis and an anchor point. The definition uses local\r
+/// anchor points and a local axis so that the initial configuration\r
+/// can violate the constraint slightly. The joint translation is zero\r
+/// when the local anchor points coincide in world space. Using local\r
+/// anchors and a local axis helps when saving and loading a game.\r
+struct b2LineJointDef : public b2JointDef\r
+{\r
+ b2LineJointDef()\r
+ {\r
+ type = e_lineJoint;\r
+ localAnchorA.SetZero();\r
+ localAnchorB.SetZero();\r
+ localAxisA.Set(1.0f, 0.0f);\r
+ enableLimit = false;\r
+ lowerTranslation = 0.0f;\r
+ upperTranslation = 0.0f;\r
+ enableMotor = false;\r
+ maxMotorForce = 0.0f;\r
+ motorSpeed = 0.0f;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, axis, and reference angle using the world\r
+ /// anchor and world axis.\r
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);\r
+\r
+ /// The local anchor point relative to body1's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to body2's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The local translation axis in body1.\r
+ b2Vec2 localAxisA;\r
+\r
+ /// Enable/disable the joint limit.\r
+ bool enableLimit;\r
+\r
+ /// The lower translation limit, usually in meters.\r
+ float32 lowerTranslation;\r
+\r
+ /// The upper translation limit, usually in meters.\r
+ float32 upperTranslation;\r
+\r
+ /// Enable/disable the joint motor.\r
+ bool enableMotor;\r
+\r
+ /// The maximum motor torque, usually in N-m.\r
+ float32 maxMotorForce;\r
+\r
+ /// The desired motor speed in radians per second.\r
+ float32 motorSpeed;\r
+};\r
+\r
+/// A line joint. This joint provides two degrees of freedom: translation\r
+/// along an axis fixed in body1 and rotation in the plane. You can use a\r
+/// joint limit to restrict the range of motion and a joint motor to drive\r
+/// the motion or to model joint friction.\r
+class b2LineJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Get the current joint translation, usually in meters.\r
+ float32 GetJointTranslation() const;\r
+\r
+ /// Get the current joint translation speed, usually in meters per second.\r
+ float32 GetJointSpeed() const;\r
+\r
+ /// Is the joint limit enabled?\r
+ bool IsLimitEnabled() const;\r
+\r
+ /// Enable/disable the joint limit.\r
+ void EnableLimit(bool flag);\r
+\r
+ /// Get the lower joint limit, usually in meters.\r
+ float32 GetLowerLimit() const;\r
+\r
+ /// Get the upper joint limit, usually in meters.\r
+ float32 GetUpperLimit() const;\r
+\r
+ /// Set the joint limits, usually in meters.\r
+ void SetLimits(float32 lower, float32 upper);\r
+\r
+ /// Is the joint motor enabled?\r
+ bool IsMotorEnabled() const;\r
+\r
+ /// Enable/disable the joint motor.\r
+ void EnableMotor(bool flag);\r
+\r
+ /// Set the motor speed, usually in meters per second.\r
+ void SetMotorSpeed(float32 speed);\r
+\r
+ /// Get the motor speed, usually in meters per second.\r
+ float32 GetMotorSpeed() const;\r
+\r
+ /// Set/Get the maximum motor force, usually in N.\r
+ void SetMaxMotorForce(float32 force);\r
+ float32 GetMaxMotorForce() const;\r
+\r
+ /// Get the current motor force, usually in N.\r
+ float32 GetMotorForce() const;\r
+\r
+protected:\r
+\r
+ friend class b2Joint;\r
+ b2LineJoint(const b2LineJointDef* def);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_localAnchor1;\r
+ b2Vec2 m_localAnchor2;\r
+ b2Vec2 m_localXAxis1;\r
+ b2Vec2 m_localYAxis1;\r
+\r
+ b2Vec2 m_axis, m_perp;\r
+ float32 m_s1, m_s2;\r
+ float32 m_a1, m_a2;\r
+\r
+ b2Mat22 m_K;\r
+ b2Vec2 m_impulse;\r
+\r
+ float32 m_motorMass; // effective mass for motor/limit translational constraint.\r
+ float32 m_motorImpulse;\r
+\r
+ float32 m_lowerTranslation;\r
+ float32 m_upperTranslation;\r
+ float32 m_maxMotorForce;\r
+ float32 m_motorSpeed;\r
+\r
+ bool m_enableLimit;\r
+ bool m_enableMotor;\r
+ b2LimitState m_limitState;\r
+};\r
+\r
+inline float32 b2LineJoint::GetMotorSpeed() const\r
+{\r
+ return m_motorSpeed;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// p = attached point, m = mouse point\r
+// C = p - m\r
+// Cdot = v\r
+// = v + cross(w, r)\r
+// J = [I r_skew]\r
+// Identity used:\r
+// w k % (rx i + ry j) = w * (-ry i + rx j)\r
+\r
+b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ b2Assert(def->target.IsValid());\r
+ b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f);\r
+ b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f);\r
+ b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f);\r
+\r
+ m_target = def->target;\r
+ m_localAnchor = b2MulT(m_bodyB->GetTransform(), m_target);\r
+\r
+ m_maxForce = def->maxForce;\r
+ m_impulse.SetZero();\r
+\r
+ m_frequencyHz = def->frequencyHz;\r
+ m_dampingRatio = def->dampingRatio;\r
+\r
+ m_beta = 0.0f;\r
+ m_gamma = 0.0f;\r
+}\r
+\r
+void b2MouseJoint::SetTarget(const b2Vec2& target)\r
+{\r
+ if (m_bodyB->IsAwake() == false)\r
+ {\r
+ m_bodyB->SetAwake(true);\r
+ }\r
+ m_target = target;\r
+}\r
+\r
+const b2Vec2& b2MouseJoint::GetTarget() const\r
+{\r
+ return m_target;\r
+}\r
+\r
+void b2MouseJoint::SetMaxForce(float32 force)\r
+{\r
+ m_maxForce = force;\r
+}\r
+\r
+float32 b2MouseJoint::GetMaxForce() const\r
+{\r
+ return m_maxForce;\r
+}\r
+\r
+void b2MouseJoint::SetFrequency(float32 hz)\r
+{\r
+ m_frequencyHz = hz;\r
+}\r
+\r
+float32 b2MouseJoint::GetFrequency() const\r
+{\r
+ return m_frequencyHz;\r
+}\r
+\r
+void b2MouseJoint::SetDampingRatio(float32 ratio)\r
+{\r
+ m_dampingRatio = ratio;\r
+}\r
+\r
+float32 b2MouseJoint::GetDampingRatio() const\r
+{\r
+ return m_dampingRatio;\r
+}\r
+\r
+void b2MouseJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b = m_bodyB;\r
+\r
+ float32 mass = b->GetMass();\r
+\r
+ // Frequency\r
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;\r
+\r
+ // Damping coefficient\r
+ float32 d = 2.0f * mass * m_dampingRatio * omega;\r
+\r
+ // Spring stiffness\r
+ float32 k = mass * (omega * omega);\r
+\r
+ // magic formulas\r
+ // gamma has units of inverse mass.\r
+ // beta has units of inverse time.\r
+ b2Assert(d + step.dt * k > b2_epsilon);\r
+ m_gamma = step.dt * (d + step.dt * k);\r
+ if (m_gamma != 0.0f)\r
+ {\r
+ m_gamma = 1.0f / m_gamma;\r
+ }\r
+ m_beta = step.dt * k * m_gamma;\r
+\r
+ // Compute the effective mass matrix.\r
+ b2Vec2 r = b2Mul(b->GetTransform().R, m_localAnchor - b->GetLocalCenter());\r
+\r
+ // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]\r
+ // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]\r
+ // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]\r
+ float32 invMass = b->m_invMass;\r
+ float32 invI = b->m_invI;\r
+\r
+ b2Mat22 K1;\r
+ K1.col1.x = invMass; K1.col2.x = 0.0f;\r
+ K1.col1.y = 0.0f; K1.col2.y = invMass;\r
+\r
+ b2Mat22 K2;\r
+ K2.col1.x = invI * r.y * r.y; K2.col2.x = -invI * r.x * r.y;\r
+ K2.col1.y = -invI * r.x * r.y; K2.col2.y = invI * r.x * r.x;\r
+\r
+ b2Mat22 K = K1 + K2;\r
+ K.col1.x += m_gamma;\r
+ K.col2.y += m_gamma;\r
+\r
+ m_mass = K.GetInverse();\r
+\r
+ m_C = b->m_sweep.c + r - m_target;\r
+\r
+ // Cheat with some damping\r
+ b->m_angularVelocity *= 0.98f;\r
+\r
+ // Warm starting.\r
+ m_impulse *= step.dtRatio;\r
+ b->m_linearVelocity += invMass * m_impulse;\r
+ b->m_angularVelocity += invI * b2Cross(r, m_impulse);\r
+}\r
+\r
+void b2MouseJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b = m_bodyB;\r
+\r
+ b2Vec2 r = b2Mul(b->GetTransform().R, m_localAnchor - b->GetLocalCenter());\r
+\r
+ // Cdot = v + cross(w, r)\r
+ b2Vec2 Cdot = b->m_linearVelocity + b2Cross(b->m_angularVelocity, r);\r
+ b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_beta * m_C + m_gamma * m_impulse));\r
+\r
+ b2Vec2 oldImpulse = m_impulse;\r
+ m_impulse += impulse;\r
+ float32 maxImpulse = step.dt * m_maxForce;\r
+ if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)\r
+ {\r
+ m_impulse *= maxImpulse / m_impulse.Length();\r
+ }\r
+ impulse = m_impulse - oldImpulse;\r
+\r
+ b->m_linearVelocity += b->m_invMass * impulse;\r
+ b->m_angularVelocity += b->m_invI * b2Cross(r, impulse);\r
+}\r
+\r
+b2Vec2 b2MouseJoint::GetAnchorA() const\r
+{\r
+ return m_target;\r
+}\r
+\r
+b2Vec2 b2MouseJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor);\r
+}\r
+\r
+b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ return inv_dt * m_impulse;\r
+}\r
+\r
+float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ return inv_dt * 0.0f;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_MOUSE_JOINT_H\r
+#define B2_MOUSE_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Mouse joint definition. This requires a world target point,\r
+/// tuning parameters, and the time step.\r
+struct b2MouseJointDef : public b2JointDef\r
+{\r
+ b2MouseJointDef()\r
+ {\r
+ type = e_mouseJoint;\r
+ target.Set(0.0f, 0.0f);\r
+ maxForce = 0.0f;\r
+ frequencyHz = 5.0f;\r
+ dampingRatio = 0.7f;\r
+ }\r
+\r
+ /// The initial world target point. This is assumed\r
+ /// to coincide with the body anchor initially.\r
+ b2Vec2 target;\r
+\r
+ /// The maximum constraint force that can be exerted\r
+ /// to move the candidate body. Usually you will express\r
+ /// as some multiple of the weight (multiplier * mass * gravity).\r
+ float32 maxForce;\r
+\r
+ /// The response speed.\r
+ float32 frequencyHz;\r
+\r
+ /// The damping ratio. 0 = no damping, 1 = critical damping.\r
+ float32 dampingRatio;\r
+};\r
+\r
+/// A mouse joint is used to make a point on a body track a\r
+/// specified world point. This a soft constraint with a maximum\r
+/// force. This allows the constraint to stretch and without\r
+/// applying huge forces.\r
+/// NOTE: this joint is not documented in the manual because it was\r
+/// developed to be used in the testbed. If you want to learn how to\r
+/// use the mouse joint, look at the testbed.\r
+class b2MouseJoint : public b2Joint\r
+{\r
+public:\r
+\r
+ /// Implements b2Joint.\r
+ b2Vec2 GetAnchorA() const;\r
+\r
+ /// Implements b2Joint.\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ /// Implements b2Joint.\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+\r
+ /// Implements b2Joint.\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Use this to update the target point.\r
+ void SetTarget(const b2Vec2& target);\r
+ const b2Vec2& GetTarget() const;\r
+\r
+ /// Set/get the maximum force in Newtons.\r
+ void SetMaxForce(float32 force);\r
+ float32 GetMaxForce() const;\r
+\r
+ /// Set/get the frequency in Hertz.\r
+ void SetFrequency(float32 hz);\r
+ float32 GetFrequency() const;\r
+\r
+ /// Set/get the damping ratio (dimensionless).\r
+ void SetDampingRatio(float32 ratio);\r
+ float32 GetDampingRatio() const;\r
+\r
+protected:\r
+ friend class b2Joint;\r
+\r
+ b2MouseJoint(const b2MouseJointDef* def);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); return true; }\r
+\r
+ b2Vec2 m_localAnchor;\r
+ b2Vec2 m_target;\r
+ b2Vec2 m_impulse;\r
+\r
+ b2Mat22 m_mass; // effective mass for point-to-point constraint.\r
+ b2Vec2 m_C; // position error\r
+ float32 m_maxForce;\r
+ float32 m_frequencyHz;\r
+ float32 m_dampingRatio;\r
+ float32 m_beta;\r
+ float32 m_gamma;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Linear constraint (point-to-line)\r
+// d = p2 - p1 = x2 + r2 - x1 - r1\r
+// C = dot(perp, d)\r
+// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))\r
+// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)\r
+// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]\r
+//\r
+// Angular constraint\r
+// C = a2 - a1 + a_initial\r
+// Cdot = w2 - w1\r
+// J = [0 0 -1 0 0 1]\r
+//\r
+// K = J * invM * JT\r
+//\r
+// J = [-a -s1 a s2]\r
+// [0 -1 0 1]\r
+// a = perp\r
+// s1 = cross(d + r1, a) = cross(p2 - x1, a)\r
+// s2 = cross(r2, a) = cross(p2 - x2, a)\r
+\r
+\r
+// Motor/Limit linear constraint\r
+// C = dot(ax1, d)\r
+// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)\r
+// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]\r
+\r
+// Block Solver\r
+// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even\r
+// when the mass has poor distribution (leading to large torques about the joint anchor points).\r
+//\r
+// The Jacobian has 3 rows:\r
+// J = [-uT -s1 uT s2] // linear\r
+// [0 -1 0 1] // angular\r
+// [-vT -a1 vT a2] // limit\r
+//\r
+// u = perp\r
+// v = axis\r
+// s1 = cross(d + r1, u), s2 = cross(r2, u)\r
+// a1 = cross(d + r1, v), a2 = cross(r2, v)\r
+\r
+// M * (v2 - v1) = JT * df\r
+// J * v2 = bias\r
+//\r
+// v2 = v1 + invM * JT * df\r
+// J * (v1 + invM * JT * df) = bias\r
+// K * df = bias - J * v1 = -Cdot\r
+// K = J * invM * JT\r
+// Cdot = J * v1 - bias\r
+//\r
+// Now solve for f2.\r
+// df = f2 - f1\r
+// K * (f2 - f1) = -Cdot\r
+// f2 = invK * (-Cdot) + f1\r
+//\r
+// Clamp accumulated limit impulse.\r
+// lower: f2(3) = max(f2(3), 0)\r
+// upper: f2(3) = min(f2(3), 0)\r
+//\r
+// Solve for correct f2(1:2)\r
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1\r
+// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)\r
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)\r
+// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)\r
+//\r
+// Now compute impulse to be applied:\r
+// df = f2 - f1\r
+\r
+void b2PrismaticJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis)\r
+{\r
+ bodyA = b1;\r
+ bodyB = b2;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor);\r
+ localAxis1 = bodyA->GetLocalVector(axis);\r
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();\r
+}\r
+\r
+b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_localAnchor1 = def->localAnchorA;\r
+ m_localAnchor2 = def->localAnchorB;\r
+ m_localXAxis1 = def->localAxis1;\r
+ m_localYAxis1 = b2Cross(1.0f, m_localXAxis1);\r
+ m_refAngle = def->referenceAngle;\r
+\r
+ m_impulse.SetZero();\r
+ m_motorMass = 0.0;\r
+ m_motorImpulse = 0.0f;\r
+\r
+ m_lowerTranslation = def->lowerTranslation;\r
+ m_upperTranslation = def->upperTranslation;\r
+ m_maxMotorForce = def->maxMotorForce;\r
+ m_motorSpeed = def->motorSpeed;\r
+ m_enableLimit = def->enableLimit;\r
+ m_enableMotor = def->enableMotor;\r
+ m_limitState = e_inactiveLimit;\r
+\r
+ m_axis.SetZero();\r
+ m_perp.SetZero();\r
+}\r
+\r
+void b2PrismaticJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ m_localCenterA = b1->GetLocalCenter();\r
+ m_localCenterB = b2->GetLocalCenter();\r
+\r
+ b2Transform xf1 = b1->GetTransform();\r
+ b2Transform xf2 = b2->GetTransform();\r
+\r
+ // Compute the effective masses.\r
+ b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenterA);\r
+ b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenterB);\r
+ b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;\r
+\r
+ m_invMassA = b1->m_invMass;\r
+ m_invIA = b1->m_invI;\r
+ m_invMassB = b2->m_invMass;\r
+ m_invIB = b2->m_invI;\r
+\r
+ // Compute motor Jacobian and effective mass.\r
+ {\r
+ m_axis = b2Mul(xf1.R, m_localXAxis1);\r
+ m_a1 = b2Cross(d + r1, m_axis);\r
+ m_a2 = b2Cross(r2, m_axis);\r
+\r
+ m_motorMass = m_invMassA + m_invMassB + m_invIA * m_a1 * m_a1 + m_invIB * m_a2 * m_a2;\r
+ if (m_motorMass > b2_epsilon)\r
+ {\r
+ m_motorMass = 1.0f / m_motorMass;\r
+ }\r
+ }\r
+\r
+ // Prismatic constraint.\r
+ {\r
+ m_perp = b2Mul(xf1.R, m_localYAxis1);\r
+\r
+ m_s1 = b2Cross(d + r1, m_perp);\r
+ m_s2 = b2Cross(r2, m_perp);\r
+\r
+ float32 m1 = m_invMassA, m2 = m_invMassB;\r
+ float32 i1 = m_invIA, i2 = m_invIB;\r
+\r
+ float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;\r
+ float32 k12 = i1 * m_s1 + i2 * m_s2;\r
+ float32 k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;\r
+ float32 k22 = i1 + i2;\r
+ float32 k23 = i1 * m_a1 + i2 * m_a2;\r
+ float32 k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;\r
+\r
+ m_K.col1.Set(k11, k12, k13);\r
+ m_K.col2.Set(k12, k22, k23);\r
+ m_K.col3.Set(k13, k23, k33);\r
+ }\r
+\r
+ // Compute motor and limit terms.\r
+ if (m_enableLimit)\r
+ {\r
+ float32 jointTranslation = b2Dot(m_axis, d);\r
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)\r
+ {\r
+ m_limitState = e_equalLimits;\r
+ }\r
+ else if (jointTranslation <= m_lowerTranslation)\r
+ {\r
+ if (m_limitState != e_atLowerLimit)\r
+ {\r
+ m_limitState = e_atLowerLimit;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ }\r
+ else if (jointTranslation >= m_upperTranslation)\r
+ {\r
+ if (m_limitState != e_atUpperLimit)\r
+ {\r
+ m_limitState = e_atUpperLimit;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_limitState = e_inactiveLimit;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_limitState = e_inactiveLimit;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+\r
+ if (m_enableMotor == false)\r
+ {\r
+ m_motorImpulse = 0.0f;\r
+ }\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Account for variable time step.\r
+ m_impulse *= step.dtRatio;\r
+ m_motorImpulse *= step.dtRatio;\r
+\r
+ b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;\r
+ float32 L1 = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;\r
+ float32 L2 = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;\r
+\r
+ b1->m_linearVelocity -= m_invMassA * P;\r
+ b1->m_angularVelocity -= m_invIA * L1;\r
+\r
+ b2->m_linearVelocity += m_invMassB * P;\r
+ b2->m_angularVelocity += m_invIB * L2;\r
+ }\r
+ else\r
+ {\r
+ m_impulse.SetZero();\r
+ m_motorImpulse = 0.0f;\r
+ }\r
+}\r
+\r
+void b2PrismaticJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 v1 = b1->m_linearVelocity;\r
+ float32 w1 = b1->m_angularVelocity;\r
+ b2Vec2 v2 = b2->m_linearVelocity;\r
+ float32 w2 = b2->m_angularVelocity;\r
+\r
+ // Solve linear motor constraint.\r
+ if (m_enableMotor && m_limitState != e_equalLimits)\r
+ {\r
+ float32 Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;\r
+ float32 impulse = m_motorMass * (m_motorSpeed - Cdot);\r
+ float32 oldImpulse = m_motorImpulse;\r
+ float32 maxImpulse = step.dt * m_maxMotorForce;\r
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);\r
+ impulse = m_motorImpulse - oldImpulse;\r
+\r
+ b2Vec2 P = impulse * m_axis;\r
+ float32 L1 = impulse * m_a1;\r
+ float32 L2 = impulse * m_a2;\r
+\r
+ v1 -= m_invMassA * P;\r
+ w1 -= m_invIA * L1;\r
+\r
+ v2 += m_invMassB * P;\r
+ w2 += m_invIB * L2;\r
+ }\r
+\r
+ b2Vec2 Cdot1;\r
+ Cdot1.x = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1;\r
+ Cdot1.y = w2 - w1;\r
+\r
+ if (m_enableLimit && m_limitState != e_inactiveLimit)\r
+ {\r
+ // Solve prismatic and limit constraint in block form.\r
+ float32 Cdot2;\r
+ Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;\r
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);\r
+\r
+ b2Vec3 f1 = m_impulse;\r
+ b2Vec3 df = m_K.Solve33(-Cdot);\r
+ m_impulse += df;\r
+\r
+ if (m_limitState == e_atLowerLimit)\r
+ {\r
+ m_impulse.z = b2Max(m_impulse.z, 0.0f);\r
+ }\r
+ else if (m_limitState == e_atUpperLimit)\r
+ {\r
+ m_impulse.z = b2Min(m_impulse.z, 0.0f);\r
+ }\r
+\r
+ // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)\r
+ b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.col3.x, m_K.col3.y);\r
+ b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);\r
+ m_impulse.x = f2r.x;\r
+ m_impulse.y = f2r.y;\r
+\r
+ df = m_impulse - f1;\r
+\r
+ b2Vec2 P = df.x * m_perp + df.z * m_axis;\r
+ float32 L1 = df.x * m_s1 + df.y + df.z * m_a1;\r
+ float32 L2 = df.x * m_s2 + df.y + df.z * m_a2;\r
+\r
+ v1 -= m_invMassA * P;\r
+ w1 -= m_invIA * L1;\r
+\r
+ v2 += m_invMassB * P;\r
+ w2 += m_invIB * L2;\r
+ }\r
+ else\r
+ {\r
+ // Limit is inactive, just solve the prismatic constraint in block form.\r
+ b2Vec2 df = m_K.Solve22(-Cdot1);\r
+ m_impulse.x += df.x;\r
+ m_impulse.y += df.y;\r
+\r
+ b2Vec2 P = df.x * m_perp;\r
+ float32 L1 = df.x * m_s1 + df.y;\r
+ float32 L2 = df.x * m_s2 + df.y;\r
+\r
+ v1 -= m_invMassA * P;\r
+ w1 -= m_invIA * L1;\r
+\r
+ v2 += m_invMassB * P;\r
+ w2 += m_invIB * L2;\r
+ }\r
+\r
+ b1->m_linearVelocity = v1;\r
+ b1->m_angularVelocity = w1;\r
+ b2->m_linearVelocity = v2;\r
+ b2->m_angularVelocity = w2;\r
+}\r
+\r
+bool b2PrismaticJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 c1 = b1->m_sweep.c;\r
+ float32 a1 = b1->m_sweep.a;\r
+\r
+ b2Vec2 c2 = b2->m_sweep.c;\r
+ float32 a2 = b2->m_sweep.a;\r
+\r
+ // Solve linear limit constraint.\r
+ float32 linearError = 0.0f, angularError = 0.0f;\r
+ bool active = false;\r
+ float32 C2 = 0.0f;\r
+\r
+ b2Mat22 R1(a1), R2(a2);\r
+\r
+ b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenterA);\r
+ b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenterB);\r
+ b2Vec2 d = c2 + r2 - c1 - r1;\r
+\r
+ if (m_enableLimit)\r
+ {\r
+ m_axis = b2Mul(R1, m_localXAxis1);\r
+\r
+ m_a1 = b2Cross(d + r1, m_axis);\r
+ m_a2 = b2Cross(r2, m_axis);\r
+\r
+ float32 translation = b2Dot(m_axis, d);\r
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)\r
+ {\r
+ // Prevent large angular corrections\r
+ C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);\r
+ linearError = b2Abs(translation);\r
+ active = true;\r
+ }\r
+ else if (translation <= m_lowerTranslation)\r
+ {\r
+ // Prevent large linear corrections and allow some slop.\r
+ C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);\r
+ linearError = m_lowerTranslation - translation;\r
+ active = true;\r
+ }\r
+ else if (translation >= m_upperTranslation)\r
+ {\r
+ // Prevent large linear corrections and allow some slop.\r
+ C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);\r
+ linearError = translation - m_upperTranslation;\r
+ active = true;\r
+ }\r
+ }\r
+\r
+ m_perp = b2Mul(R1, m_localYAxis1);\r
+\r
+ m_s1 = b2Cross(d + r1, m_perp);\r
+ m_s2 = b2Cross(r2, m_perp);\r
+\r
+ b2Vec3 impulse;\r
+ b2Vec2 C1;\r
+ C1.x = b2Dot(m_perp, d);\r
+ C1.y = a2 - a1 - m_refAngle;\r
+\r
+ linearError = b2Max(linearError, b2Abs(C1.x));\r
+ angularError = b2Abs(C1.y);\r
+\r
+ if (active)\r
+ {\r
+ float32 m1 = m_invMassA, m2 = m_invMassB;\r
+ float32 i1 = m_invIA, i2 = m_invIB;\r
+\r
+ float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;\r
+ float32 k12 = i1 * m_s1 + i2 * m_s2;\r
+ float32 k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;\r
+ float32 k22 = i1 + i2;\r
+ float32 k23 = i1 * m_a1 + i2 * m_a2;\r
+ float32 k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;\r
+\r
+ m_K.col1.Set(k11, k12, k13);\r
+ m_K.col2.Set(k12, k22, k23);\r
+ m_K.col3.Set(k13, k23, k33);\r
+\r
+ b2Vec3 C;\r
+ C.x = C1.x;\r
+ C.y = C1.y;\r
+ C.z = C2;\r
+\r
+ impulse = m_K.Solve33(-C);\r
+ }\r
+ else\r
+ {\r
+ float32 m1 = m_invMassA, m2 = m_invMassB;\r
+ float32 i1 = m_invIA, i2 = m_invIB;\r
+\r
+ float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;\r
+ float32 k12 = i1 * m_s1 + i2 * m_s2;\r
+ float32 k22 = i1 + i2;\r
+\r
+ m_K.col1.Set(k11, k12, 0.0f);\r
+ m_K.col2.Set(k12, k22, 0.0f);\r
+\r
+ b2Vec2 impulse1 = m_K.Solve22(-C1);\r
+ impulse.x = impulse1.x;\r
+ impulse.y = impulse1.y;\r
+ impulse.z = 0.0f;\r
+ }\r
+\r
+ b2Vec2 P = impulse.x * m_perp + impulse.z * m_axis;\r
+ float32 L1 = impulse.x * m_s1 + impulse.y + impulse.z * m_a1;\r
+ float32 L2 = impulse.x * m_s2 + impulse.y + impulse.z * m_a2;\r
+\r
+ c1 -= m_invMassA * P;\r
+ a1 -= m_invIA * L1;\r
+ c2 += m_invMassB * P;\r
+ a2 += m_invIB * L2;\r
+\r
+ // TODO_ERIN remove need for this.\r
+ b1->m_sweep.c = c1;\r
+ b1->m_sweep.a = a1;\r
+ b2->m_sweep.c = c2;\r
+ b2->m_sweep.a = a2;\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+ \r
+ return linearError <= b2_linearSlop && angularError <= b2_angularSlop;\r
+}\r
+\r
+b2Vec2 b2PrismaticJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchor1);\r
+}\r
+\r
+b2Vec2 b2PrismaticJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor2);\r
+}\r
+\r
+b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);\r
+}\r
+\r
+float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ return inv_dt * m_impulse.y;\r
+}\r
+\r
+float32 b2PrismaticJoint::GetJointTranslation() const\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1);\r
+ b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2);\r
+ b2Vec2 d = p2 - p1;\r
+ b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);\r
+\r
+ float32 translation = b2Dot(d, axis);\r
+ return translation;\r
+}\r
+\r
+float32 b2PrismaticJoint::GetJointSpeed() const\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+ b2Vec2 p1 = b1->m_sweep.c + r1;\r
+ b2Vec2 p2 = b2->m_sweep.c + r2;\r
+ b2Vec2 d = p2 - p1;\r
+ b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);\r
+\r
+ b2Vec2 v1 = b1->m_linearVelocity;\r
+ b2Vec2 v2 = b2->m_linearVelocity;\r
+ float32 w1 = b1->m_angularVelocity;\r
+ float32 w2 = b2->m_angularVelocity;\r
+\r
+ float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1));\r
+ return speed;\r
+}\r
+\r
+bool b2PrismaticJoint::IsLimitEnabled() const\r
+{\r
+ return m_enableLimit;\r
+}\r
+\r
+void b2PrismaticJoint::EnableLimit(bool flag)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_enableLimit = flag;\r
+}\r
+\r
+float32 b2PrismaticJoint::GetLowerLimit() const\r
+{\r
+ return m_lowerTranslation;\r
+}\r
+\r
+float32 b2PrismaticJoint::GetUpperLimit() const\r
+{\r
+ return m_upperTranslation;\r
+}\r
+\r
+void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)\r
+{\r
+ b2Assert(lower <= upper);\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_lowerTranslation = lower;\r
+ m_upperTranslation = upper;\r
+}\r
+\r
+bool b2PrismaticJoint::IsMotorEnabled() const\r
+{\r
+ return m_enableMotor;\r
+}\r
+\r
+void b2PrismaticJoint::EnableMotor(bool flag)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_enableMotor = flag;\r
+}\r
+\r
+void b2PrismaticJoint::SetMotorSpeed(float32 speed)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_motorSpeed = speed;\r
+}\r
+\r
+void b2PrismaticJoint::SetMaxMotorForce(float32 force)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_maxMotorForce = force;\r
+}\r
+\r
+float32 b2PrismaticJoint::GetMotorForce() const\r
+{\r
+ return m_motorImpulse;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_PRISMATIC_JOINT_H\r
+#define B2_PRISMATIC_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Prismatic joint definition. This requires defining a line of\r
+/// motion using an axis and an anchor point. The definition uses local\r
+/// anchor points and a local axis so that the initial configuration\r
+/// can violate the constraint slightly. The joint translation is zero\r
+/// when the local anchor points coincide in world space. Using local\r
+/// anchors and a local axis helps when saving and loading a game.\r
+/// @warning at least one body should by dynamic with a non-fixed rotation.\r
+struct b2PrismaticJointDef : public b2JointDef\r
+{\r
+ b2PrismaticJointDef()\r
+ {\r
+ type = e_prismaticJoint;\r
+ localAnchorA.SetZero();\r
+ localAnchorB.SetZero();\r
+ localAxis1.Set(1.0f, 0.0f);\r
+ referenceAngle = 0.0f;\r
+ enableLimit = false;\r
+ lowerTranslation = 0.0f;\r
+ upperTranslation = 0.0f;\r
+ enableMotor = false;\r
+ maxMotorForce = 0.0f;\r
+ motorSpeed = 0.0f;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, axis, and reference angle using the world\r
+ /// anchor and world axis.\r
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);\r
+\r
+ /// The local anchor point relative to body1's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to body2's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The local translation axis in body1.\r
+ b2Vec2 localAxis1;\r
+\r
+ /// The constrained angle between the bodies: body2_angle - body1_angle.\r
+ float32 referenceAngle;\r
+\r
+ /// Enable/disable the joint limit.\r
+ bool enableLimit;\r
+\r
+ /// The lower translation limit, usually in meters.\r
+ float32 lowerTranslation;\r
+\r
+ /// The upper translation limit, usually in meters.\r
+ float32 upperTranslation;\r
+\r
+ /// Enable/disable the joint motor.\r
+ bool enableMotor;\r
+\r
+ /// The maximum motor torque, usually in N-m.\r
+ float32 maxMotorForce;\r
+\r
+ /// The desired motor speed in radians per second.\r
+ float32 motorSpeed;\r
+};\r
+\r
+/// A prismatic joint. This joint provides one degree of freedom: translation\r
+/// along an axis fixed in body1. Relative rotation is prevented. You can\r
+/// use a joint limit to restrict the range of motion and a joint motor to\r
+/// drive the motion or to model joint friction.\r
+class b2PrismaticJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Get the current joint translation, usually in meters.\r
+ float32 GetJointTranslation() const;\r
+\r
+ /// Get the current joint translation speed, usually in meters per second.\r
+ float32 GetJointSpeed() const;\r
+\r
+ /// Is the joint limit enabled?\r
+ bool IsLimitEnabled() const;\r
+\r
+ /// Enable/disable the joint limit.\r
+ void EnableLimit(bool flag);\r
+\r
+ /// Get the lower joint limit, usually in meters.\r
+ float32 GetLowerLimit() const;\r
+\r
+ /// Get the upper joint limit, usually in meters.\r
+ float32 GetUpperLimit() const;\r
+\r
+ /// Set the joint limits, usually in meters.\r
+ void SetLimits(float32 lower, float32 upper);\r
+\r
+ /// Is the joint motor enabled?\r
+ bool IsMotorEnabled() const;\r
+\r
+ /// Enable/disable the joint motor.\r
+ void EnableMotor(bool flag);\r
+\r
+ /// Set the motor speed, usually in meters per second.\r
+ void SetMotorSpeed(float32 speed);\r
+\r
+ /// Get the motor speed, usually in meters per second.\r
+ float32 GetMotorSpeed() const;\r
+\r
+ /// Set the maximum motor force, usually in N.\r
+ void SetMaxMotorForce(float32 force);\r
+\r
+ /// Get the current motor force, usually in N.\r
+ float32 GetMotorForce() const;\r
+\r
+protected:\r
+ friend class b2Joint;\r
+ friend class b2GearJoint;\r
+ b2PrismaticJoint(const b2PrismaticJointDef* def);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_localAnchor1;\r
+ b2Vec2 m_localAnchor2;\r
+ b2Vec2 m_localXAxis1;\r
+ b2Vec2 m_localYAxis1;\r
+ float32 m_refAngle;\r
+\r
+ b2Vec2 m_axis, m_perp;\r
+ float32 m_s1, m_s2;\r
+ float32 m_a1, m_a2;\r
+\r
+ b2Mat33 m_K;\r
+ b2Vec3 m_impulse;\r
+\r
+ float32 m_motorMass; // effective mass for motor/limit translational constraint.\r
+ float32 m_motorImpulse;\r
+\r
+ float32 m_lowerTranslation;\r
+ float32 m_upperTranslation;\r
+ float32 m_maxMotorForce;\r
+ float32 m_motorSpeed;\r
+ \r
+ bool m_enableLimit;\r
+ bool m_enableMotor;\r
+ b2LimitState m_limitState;\r
+};\r
+\r
+inline float32 b2PrismaticJoint::GetMotorSpeed() const\r
+{\r
+ return m_motorSpeed;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Pulley:\r
+// length1 = norm(p1 - s1)\r
+// length2 = norm(p2 - s2)\r
+// C0 = (length1 + ratio * length2)_initial\r
+// C = C0 - (length1 + ratio * length2) >= 0\r
+// u1 = (p1 - s1) / norm(p1 - s1)\r
+// u2 = (p2 - s2) / norm(p2 - s2)\r
+// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))\r
+// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)]\r
+// K = J * invM * JT\r
+// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)\r
+//\r
+// Limit:\r
+// C = maxLength - length\r
+// u = (p - s) / norm(p - s)\r
+// Cdot = -dot(u, v + cross(w, r))\r
+// K = invMass + invI * cross(r, u)^2\r
+// 0 <= impulse\r
+\r
+void b2PulleyJointDef::Initialize(b2Body* b1, b2Body* b2,\r
+ const b2Vec2& ga1, const b2Vec2& ga2,\r
+ const b2Vec2& anchor1, const b2Vec2& anchor2,\r
+ float32 r)\r
+{\r
+ bodyA = b1;\r
+ bodyB = b2;\r
+ groundAnchorA = ga1;\r
+ groundAnchorB = ga2;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor1);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor2);\r
+ b2Vec2 d1 = anchor1 - ga1;\r
+ lengthA = d1.Length();\r
+ b2Vec2 d2 = anchor2 - ga2;\r
+ lengthB = d2.Length();\r
+ ratio = r;\r
+ b2Assert(ratio > b2_epsilon);\r
+ float32 C = lengthA + ratio * lengthB;\r
+ maxLengthA = C - ratio * b2_minPulleyLength;\r
+ maxLengthB = (C - b2_minPulleyLength) / ratio;\r
+}\r
+\r
+b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_groundAnchor1 = def->groundAnchorA;\r
+ m_groundAnchor2 = def->groundAnchorB;\r
+ m_localAnchor1 = def->localAnchorA;\r
+ m_localAnchor2 = def->localAnchorB;\r
+\r
+ b2Assert(def->ratio != 0.0f);\r
+ m_ratio = def->ratio;\r
+\r
+ m_constant = def->lengthA + m_ratio * def->lengthB;\r
+\r
+ m_maxLength1 = b2Min(def->maxLengthA, m_constant - m_ratio * b2_minPulleyLength);\r
+ m_maxLength2 = b2Min(def->maxLengthB, (m_constant - b2_minPulleyLength) / m_ratio);\r
+\r
+ m_impulse = 0.0f;\r
+ m_limitImpulse1 = 0.0f;\r
+ m_limitImpulse2 = 0.0f;\r
+}\r
+\r
+void b2PulleyJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ b2Vec2 p1 = b1->m_sweep.c + r1;\r
+ b2Vec2 p2 = b2->m_sweep.c + r2;\r
+\r
+ b2Vec2 s1 = m_groundAnchor1;\r
+ b2Vec2 s2 = m_groundAnchor2;\r
+\r
+ // Get the pulley axes.\r
+ m_u1 = p1 - s1;\r
+ m_u2 = p2 - s2;\r
+\r
+ float32 length1 = m_u1.Length();\r
+ float32 length2 = m_u2.Length();\r
+\r
+ if (length1 > b2_linearSlop)\r
+ {\r
+ m_u1 *= 1.0f / length1;\r
+ }\r
+ else\r
+ {\r
+ m_u1.SetZero();\r
+ }\r
+\r
+ if (length2 > b2_linearSlop)\r
+ {\r
+ m_u2 *= 1.0f / length2;\r
+ }\r
+ else\r
+ {\r
+ m_u2.SetZero();\r
+ }\r
+\r
+ float32 C = m_constant - length1 - m_ratio * length2;\r
+ if (C > 0.0f)\r
+ {\r
+ m_state = e_inactiveLimit;\r
+ m_impulse = 0.0f;\r
+ }\r
+ else\r
+ {\r
+ m_state = e_atUpperLimit;\r
+ }\r
+\r
+ if (length1 < m_maxLength1)\r
+ {\r
+ m_limitState1 = e_inactiveLimit;\r
+ m_limitImpulse1 = 0.0f;\r
+ }\r
+ else\r
+ {\r
+ m_limitState1 = e_atUpperLimit;\r
+ }\r
+\r
+ if (length2 < m_maxLength2)\r
+ {\r
+ m_limitState2 = e_inactiveLimit;\r
+ m_limitImpulse2 = 0.0f;\r
+ }\r
+ else\r
+ {\r
+ m_limitState2 = e_atUpperLimit;\r
+ }\r
+\r
+ // Compute effective mass.\r
+ float32 cr1u1 = b2Cross(r1, m_u1);\r
+ float32 cr2u2 = b2Cross(r2, m_u2);\r
+\r
+ m_limitMass1 = b1->m_invMass + b1->m_invI * cr1u1 * cr1u1;\r
+ m_limitMass2 = b2->m_invMass + b2->m_invI * cr2u2 * cr2u2;\r
+ m_pulleyMass = m_limitMass1 + m_ratio * m_ratio * m_limitMass2;\r
+ b2Assert(m_limitMass1 > b2_epsilon);\r
+ b2Assert(m_limitMass2 > b2_epsilon);\r
+ b2Assert(m_pulleyMass > b2_epsilon);\r
+ m_limitMass1 = 1.0f / m_limitMass1;\r
+ m_limitMass2 = 1.0f / m_limitMass2;\r
+ m_pulleyMass = 1.0f / m_pulleyMass;\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Scale impulses to support variable time steps.\r
+ m_impulse *= step.dtRatio;\r
+ m_limitImpulse1 *= step.dtRatio;\r
+ m_limitImpulse2 *= step.dtRatio;\r
+\r
+ // Warm starting.\r
+ b2Vec2 P1 = -(m_impulse + m_limitImpulse1) * m_u1;\r
+ b2Vec2 P2 = (-m_ratio * m_impulse - m_limitImpulse2) * m_u2;\r
+ b1->m_linearVelocity += b1->m_invMass * P1;\r
+ b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);\r
+ b2->m_linearVelocity += b2->m_invMass * P2;\r
+ b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);\r
+ }\r
+ else\r
+ {\r
+ m_impulse = 0.0f;\r
+ m_limitImpulse1 = 0.0f;\r
+ m_limitImpulse2 = 0.0f;\r
+ }\r
+}\r
+\r
+void b2PulleyJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ B2_NOT_USED(step);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ if (m_state == e_atUpperLimit)\r
+ {\r
+ b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);\r
+ b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);\r
+\r
+ float32 Cdot = -b2Dot(m_u1, v1) - m_ratio * b2Dot(m_u2, v2);\r
+ float32 impulse = m_pulleyMass * (-Cdot);\r
+ float32 oldImpulse = m_impulse;\r
+ m_impulse = b2Max(0.0f, m_impulse + impulse);\r
+ impulse = m_impulse - oldImpulse;\r
+\r
+ b2Vec2 P1 = -impulse * m_u1;\r
+ b2Vec2 P2 = -m_ratio * impulse * m_u2;\r
+ b1->m_linearVelocity += b1->m_invMass * P1;\r
+ b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);\r
+ b2->m_linearVelocity += b2->m_invMass * P2;\r
+ b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);\r
+ }\r
+\r
+ if (m_limitState1 == e_atUpperLimit)\r
+ {\r
+ b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);\r
+\r
+ float32 Cdot = -b2Dot(m_u1, v1);\r
+ float32 impulse = -m_limitMass1 * Cdot;\r
+ float32 oldImpulse = m_limitImpulse1;\r
+ m_limitImpulse1 = b2Max(0.0f, m_limitImpulse1 + impulse);\r
+ impulse = m_limitImpulse1 - oldImpulse;\r
+\r
+ b2Vec2 P1 = -impulse * m_u1;\r
+ b1->m_linearVelocity += b1->m_invMass * P1;\r
+ b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);\r
+ }\r
+\r
+ if (m_limitState2 == e_atUpperLimit)\r
+ {\r
+ b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);\r
+\r
+ float32 Cdot = -b2Dot(m_u2, v2);\r
+ float32 impulse = -m_limitMass2 * Cdot;\r
+ float32 oldImpulse = m_limitImpulse2;\r
+ m_limitImpulse2 = b2Max(0.0f, m_limitImpulse2 + impulse);\r
+ impulse = m_limitImpulse2 - oldImpulse;\r
+\r
+ b2Vec2 P2 = -impulse * m_u2;\r
+ b2->m_linearVelocity += b2->m_invMass * P2;\r
+ b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);\r
+ }\r
+}\r
+\r
+bool b2PulleyJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 s1 = m_groundAnchor1;\r
+ b2Vec2 s2 = m_groundAnchor2;\r
+\r
+ float32 linearError = 0.0f;\r
+\r
+ if (m_state == e_atUpperLimit)\r
+ {\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ b2Vec2 p1 = b1->m_sweep.c + r1;\r
+ b2Vec2 p2 = b2->m_sweep.c + r2;\r
+\r
+ // Get the pulley axes.\r
+ m_u1 = p1 - s1;\r
+ m_u2 = p2 - s2;\r
+\r
+ float32 length1 = m_u1.Length();\r
+ float32 length2 = m_u2.Length();\r
+\r
+ if (length1 > b2_linearSlop)\r
+ {\r
+ m_u1 *= 1.0f / length1;\r
+ }\r
+ else\r
+ {\r
+ m_u1.SetZero();\r
+ }\r
+\r
+ if (length2 > b2_linearSlop)\r
+ {\r
+ m_u2 *= 1.0f / length2;\r
+ }\r
+ else\r
+ {\r
+ m_u2.SetZero();\r
+ }\r
+\r
+ float32 C = m_constant - length1 - m_ratio * length2;\r
+ linearError = b2Max(linearError, -C);\r
+\r
+ C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);\r
+ float32 impulse = -m_pulleyMass * C;\r
+\r
+ b2Vec2 P1 = -impulse * m_u1;\r
+ b2Vec2 P2 = -m_ratio * impulse * m_u2;\r
+\r
+ b1->m_sweep.c += b1->m_invMass * P1;\r
+ b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);\r
+ b2->m_sweep.c += b2->m_invMass * P2;\r
+ b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);\r
+\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+ }\r
+\r
+ if (m_limitState1 == e_atUpperLimit)\r
+ {\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 p1 = b1->m_sweep.c + r1;\r
+\r
+ m_u1 = p1 - s1;\r
+ float32 length1 = m_u1.Length();\r
+\r
+ if (length1 > b2_linearSlop)\r
+ {\r
+ m_u1 *= 1.0f / length1;\r
+ }\r
+ else\r
+ {\r
+ m_u1.SetZero();\r
+ }\r
+\r
+ float32 C = m_maxLength1 - length1;\r
+ linearError = b2Max(linearError, -C);\r
+ C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);\r
+ float32 impulse = -m_limitMass1 * C;\r
+\r
+ b2Vec2 P1 = -impulse * m_u1;\r
+ b1->m_sweep.c += b1->m_invMass * P1;\r
+ b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);\r
+\r
+ b1->SynchronizeTransform();\r
+ }\r
+\r
+ if (m_limitState2 == e_atUpperLimit)\r
+ {\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+ b2Vec2 p2 = b2->m_sweep.c + r2;\r
+\r
+ m_u2 = p2 - s2;\r
+ float32 length2 = m_u2.Length();\r
+\r
+ if (length2 > b2_linearSlop)\r
+ {\r
+ m_u2 *= 1.0f / length2;\r
+ }\r
+ else\r
+ {\r
+ m_u2.SetZero();\r
+ }\r
+\r
+ float32 C = m_maxLength2 - length2;\r
+ linearError = b2Max(linearError, -C);\r
+ C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);\r
+ float32 impulse = -m_limitMass2 * C;\r
+\r
+ b2Vec2 P2 = -impulse * m_u2;\r
+ b2->m_sweep.c += b2->m_invMass * P2;\r
+ b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);\r
+\r
+ b2->SynchronizeTransform();\r
+ }\r
+\r
+ return linearError < b2_linearSlop;\r
+}\r
+\r
+b2Vec2 b2PulleyJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchor1);\r
+}\r
+\r
+b2Vec2 b2PulleyJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor2);\r
+}\r
+\r
+b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ b2Vec2 P = m_impulse * m_u2;\r
+ return inv_dt * P;\r
+}\r
+\r
+float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ B2_NOT_USED(inv_dt);\r
+ return 0.0f;\r
+}\r
+\r
+b2Vec2 b2PulleyJoint::GetGroundAnchorA() const\r
+{\r
+ return m_groundAnchor1;\r
+}\r
+\r
+b2Vec2 b2PulleyJoint::GetGroundAnchorB() const\r
+{\r
+ return m_groundAnchor2;\r
+}\r
+\r
+float32 b2PulleyJoint::GetLength1() const\r
+{\r
+ b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchor1);\r
+ b2Vec2 s = m_groundAnchor1;\r
+ b2Vec2 d = p - s;\r
+ return d.Length();\r
+}\r
+\r
+float32 b2PulleyJoint::GetLength2() const\r
+{\r
+ b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchor2);\r
+ b2Vec2 s = m_groundAnchor2;\r
+ b2Vec2 d = p - s;\r
+ return d.Length();\r
+}\r
+\r
+float32 b2PulleyJoint::GetRatio() const\r
+{\r
+ return m_ratio;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_PULLEY_JOINT_H\r
+#define B2_PULLEY_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+const float32 b2_minPulleyLength = 2.0f;\r
+\r
+/// Pulley joint definition. This requires two ground anchors,\r
+/// two dynamic body anchor points, max lengths for each side,\r
+/// and a pulley ratio.\r
+struct b2PulleyJointDef : public b2JointDef\r
+{\r
+ b2PulleyJointDef()\r
+ {\r
+ type = e_pulleyJoint;\r
+ groundAnchorA.Set(-1.0f, 1.0f);\r
+ groundAnchorB.Set(1.0f, 1.0f);\r
+ localAnchorA.Set(-1.0f, 0.0f);\r
+ localAnchorB.Set(1.0f, 0.0f);\r
+ lengthA = 0.0f;\r
+ maxLengthA = 0.0f;\r
+ lengthB = 0.0f;\r
+ maxLengthB = 0.0f;\r
+ ratio = 1.0f;\r
+ collideConnected = true;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.\r
+ void Initialize(b2Body* bodyA, b2Body* bodyB,\r
+ const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB,\r
+ const b2Vec2& anchorA, const b2Vec2& anchorB,\r
+ float32 ratio);\r
+\r
+ /// The first ground anchor in world coordinates. This point never moves.\r
+ b2Vec2 groundAnchorA;\r
+\r
+ /// The second ground anchor in world coordinates. This point never moves.\r
+ b2Vec2 groundAnchorB;\r
+\r
+ /// The local anchor point relative to bodyA's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to bodyB's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The a reference length for the segment attached to bodyA.\r
+ float32 lengthA;\r
+\r
+ /// The maximum length of the segment attached to bodyA.\r
+ float32 maxLengthA;\r
+\r
+ /// The a reference length for the segment attached to bodyB.\r
+ float32 lengthB;\r
+\r
+ /// The maximum length of the segment attached to bodyB.\r
+ float32 maxLengthB;\r
+\r
+ /// The pulley ratio, used to simulate a block-and-tackle.\r
+ float32 ratio;\r
+};\r
+\r
+/// The pulley joint is connected to two bodies and two fixed ground points.\r
+/// The pulley supports a ratio such that:\r
+/// length1 + ratio * length2 <= constant\r
+/// Yes, the force transmitted is scaled by the ratio.\r
+/// The pulley also enforces a maximum length limit on both sides. This is\r
+/// useful to prevent one side of the pulley hitting the top.\r
+class b2PulleyJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Get the first ground anchor.\r
+ b2Vec2 GetGroundAnchorA() const;\r
+\r
+ /// Get the second ground anchor.\r
+ b2Vec2 GetGroundAnchorB() const;\r
+\r
+ /// Get the current length of the segment attached to body1.\r
+ float32 GetLength1() const;\r
+\r
+ /// Get the current length of the segment attached to body2.\r
+ float32 GetLength2() const;\r
+\r
+ /// Get the pulley ratio.\r
+ float32 GetRatio() const;\r
+\r
+protected:\r
+\r
+ friend class b2Joint;\r
+ b2PulleyJoint(const b2PulleyJointDef* data);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_groundAnchor1;\r
+ b2Vec2 m_groundAnchor2;\r
+ b2Vec2 m_localAnchor1;\r
+ b2Vec2 m_localAnchor2;\r
+\r
+ b2Vec2 m_u1;\r
+ b2Vec2 m_u2;\r
+ \r
+ float32 m_constant;\r
+ float32 m_ratio;\r
+ \r
+ float32 m_maxLength1;\r
+ float32 m_maxLength2;\r
+\r
+ // Effective masses\r
+ float32 m_pulleyMass;\r
+ float32 m_limitMass1;\r
+ float32 m_limitMass2;\r
+\r
+ // Impulses for accumulation/warm starting.\r
+ float32 m_impulse;\r
+ float32 m_limitImpulse1;\r
+ float32 m_limitImpulse2;\r
+\r
+ b2LimitState m_state;\r
+ b2LimitState m_limitState1;\r
+ b2LimitState m_limitState2;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Point-to-point constraint\r
+// C = p2 - p1\r
+// Cdot = v2 - v1\r
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)\r
+// J = [-I -r1_skew I r2_skew ]\r
+// Identity used:\r
+// w k % (rx i + ry j) = w * (-ry i + rx j)\r
+\r
+// Motor constraint\r
+// Cdot = w2 - w1\r
+// J = [0 0 -1 0 0 1]\r
+// K = invI1 + invI2\r
+\r
+void b2RevoluteJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor)\r
+{\r
+ bodyA = b1;\r
+ bodyB = b2;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor);\r
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();\r
+}\r
+\r
+b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_localAnchor1 = def->localAnchorA;\r
+ m_localAnchor2 = def->localAnchorB;\r
+ m_referenceAngle = def->referenceAngle;\r
+\r
+ m_impulse.SetZero();\r
+ m_motorImpulse = 0.0f;\r
+\r
+ m_lowerAngle = def->lowerAngle;\r
+ m_upperAngle = def->upperAngle;\r
+ m_maxMotorTorque = def->maxMotorTorque;\r
+ m_motorSpeed = def->motorSpeed;\r
+ m_enableLimit = def->enableLimit;\r
+ m_enableMotor = def->enableMotor;\r
+ m_limitState = e_inactiveLimit;\r
+}\r
+\r
+void b2RevoluteJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ if (m_enableMotor || m_enableLimit)\r
+ {\r
+ // You cannot create a rotation limit between bodies that\r
+ // both have fixed rotation.\r
+ b2Assert(b1->m_invI > 0.0f || b2->m_invI > 0.0f);\r
+ }\r
+\r
+ // Compute the effective mass matrix.\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ // J = [-I -r1_skew I r2_skew]\r
+ // [ 0 -1 0 1]\r
+ // r_skew = [-ry; rx]\r
+\r
+ // Matlab\r
+ // K = [ m1+r1y^2*i1+m2+r2y^2*i2, -r1y*i1*r1x-r2y*i2*r2x, -r1y*i1-r2y*i2]\r
+ // [ -r1y*i1*r1x-r2y*i2*r2x, m1+r1x^2*i1+m2+r2x^2*i2, r1x*i1+r2x*i2]\r
+ // [ -r1y*i1-r2y*i2, r1x*i1+r2x*i2, i1+i2]\r
+\r
+ float32 m1 = b1->m_invMass, m2 = b2->m_invMass;\r
+ float32 i1 = b1->m_invI, i2 = b2->m_invI;\r
+\r
+ m_mass.col1.x = m1 + m2 + r1.y * r1.y * i1 + r2.y * r2.y * i2;\r
+ m_mass.col2.x = -r1.y * r1.x * i1 - r2.y * r2.x * i2;\r
+ m_mass.col3.x = -r1.y * i1 - r2.y * i2;\r
+ m_mass.col1.y = m_mass.col2.x;\r
+ m_mass.col2.y = m1 + m2 + r1.x * r1.x * i1 + r2.x * r2.x * i2;\r
+ m_mass.col3.y = r1.x * i1 + r2.x * i2;\r
+ m_mass.col1.z = m_mass.col3.x;\r
+ m_mass.col2.z = m_mass.col3.y;\r
+ m_mass.col3.z = i1 + i2;\r
+\r
+ m_motorMass = i1 + i2;\r
+ if (m_motorMass > 0.0f)\r
+ {\r
+ m_motorMass = 1.0f / m_motorMass;\r
+ }\r
+\r
+ if (m_enableMotor == false)\r
+ {\r
+ m_motorImpulse = 0.0f;\r
+ }\r
+\r
+ if (m_enableLimit)\r
+ {\r
+ float32 jointAngle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;\r
+ if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)\r
+ {\r
+ m_limitState = e_equalLimits;\r
+ }\r
+ else if (jointAngle <= m_lowerAngle)\r
+ {\r
+ if (m_limitState != e_atLowerLimit)\r
+ {\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ m_limitState = e_atLowerLimit;\r
+ }\r
+ else if (jointAngle >= m_upperAngle)\r
+ {\r
+ if (m_limitState != e_atUpperLimit)\r
+ {\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ m_limitState = e_atUpperLimit;\r
+ }\r
+ else\r
+ {\r
+ m_limitState = e_inactiveLimit;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_limitState = e_inactiveLimit;\r
+ }\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Scale impulses to support a variable time step.\r
+ m_impulse *= step.dtRatio;\r
+ m_motorImpulse *= step.dtRatio;\r
+\r
+ b2Vec2 P(m_impulse.x, m_impulse.y);\r
+\r
+ b1->m_linearVelocity -= m1 * P;\r
+ b1->m_angularVelocity -= i1 * (b2Cross(r1, P) + m_motorImpulse + m_impulse.z);\r
+\r
+ b2->m_linearVelocity += m2 * P;\r
+ b2->m_angularVelocity += i2 * (b2Cross(r2, P) + m_motorImpulse + m_impulse.z);\r
+ }\r
+ else\r
+ {\r
+ m_impulse.SetZero();\r
+ m_motorImpulse = 0.0f;\r
+ }\r
+}\r
+\r
+void b2RevoluteJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ b2Vec2 v1 = b1->m_linearVelocity;\r
+ float32 w1 = b1->m_angularVelocity;\r
+ b2Vec2 v2 = b2->m_linearVelocity;\r
+ float32 w2 = b2->m_angularVelocity;\r
+\r
+ float32 m1 = b1->m_invMass, m2 = b2->m_invMass;\r
+ float32 i1 = b1->m_invI, i2 = b2->m_invI;\r
+\r
+ // Solve motor constraint.\r
+ if (m_enableMotor && m_limitState != e_equalLimits)\r
+ {\r
+ float32 Cdot = w2 - w1 - m_motorSpeed;\r
+ float32 impulse = m_motorMass * (-Cdot);\r
+ float32 oldImpulse = m_motorImpulse;\r
+ float32 maxImpulse = step.dt * m_maxMotorTorque;\r
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);\r
+ impulse = m_motorImpulse - oldImpulse;\r
+\r
+ w1 -= i1 * impulse;\r
+ w2 += i2 * impulse;\r
+ }\r
+\r
+ // Solve limit constraint.\r
+ if (m_enableLimit && m_limitState != e_inactiveLimit)\r
+ {\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ // Solve point-to-point constraint\r
+ b2Vec2 Cdot1 = v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1);\r
+ float32 Cdot2 = w2 - w1;\r
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);\r
+\r
+ b2Vec3 impulse = m_mass.Solve33(-Cdot);\r
+\r
+ if (m_limitState == e_equalLimits)\r
+ {\r
+ m_impulse += impulse;\r
+ }\r
+ else if (m_limitState == e_atLowerLimit)\r
+ {\r
+ float32 newImpulse = m_impulse.z + impulse.z;\r
+ if (newImpulse < 0.0f)\r
+ {\r
+ b2Vec2 reduced = m_mass.Solve22(-Cdot1);\r
+ impulse.x = reduced.x;\r
+ impulse.y = reduced.y;\r
+ impulse.z = -m_impulse.z;\r
+ m_impulse.x += reduced.x;\r
+ m_impulse.y += reduced.y;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ }\r
+ else if (m_limitState == e_atUpperLimit)\r
+ {\r
+ float32 newImpulse = m_impulse.z + impulse.z;\r
+ if (newImpulse > 0.0f)\r
+ {\r
+ b2Vec2 reduced = m_mass.Solve22(-Cdot1);\r
+ impulse.x = reduced.x;\r
+ impulse.y = reduced.y;\r
+ impulse.z = -m_impulse.z;\r
+ m_impulse.x += reduced.x;\r
+ m_impulse.y += reduced.y;\r
+ m_impulse.z = 0.0f;\r
+ }\r
+ }\r
+\r
+ b2Vec2 P(impulse.x, impulse.y);\r
+\r
+ v1 -= m1 * P;\r
+ w1 -= i1 * (b2Cross(r1, P) + impulse.z);\r
+\r
+ v2 += m2 * P;\r
+ w2 += i2 * (b2Cross(r2, P) + impulse.z);\r
+ }\r
+ else\r
+ {\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ // Solve point-to-point constraint\r
+ b2Vec2 Cdot = v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1);\r
+ b2Vec2 impulse = m_mass.Solve22(-Cdot);\r
+\r
+ m_impulse.x += impulse.x;\r
+ m_impulse.y += impulse.y;\r
+\r
+ v1 -= m1 * impulse;\r
+ w1 -= i1 * b2Cross(r1, impulse);\r
+\r
+ v2 += m2 * impulse;\r
+ w2 += i2 * b2Cross(r2, impulse);\r
+ }\r
+\r
+ b1->m_linearVelocity = v1;\r
+ b1->m_angularVelocity = w1;\r
+ b2->m_linearVelocity = v2;\r
+ b2->m_angularVelocity = w2;\r
+}\r
+\r
+bool b2RevoluteJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ // TODO_ERIN block solve with limit.\r
+\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+\r
+ float32 angularError = 0.0f;\r
+ float32 positionError = 0.0f;\r
+\r
+ // Solve angular limit constraint.\r
+ if (m_enableLimit && m_limitState != e_inactiveLimit)\r
+ {\r
+ float32 angle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;\r
+ float32 limitImpulse = 0.0f;\r
+\r
+ if (m_limitState == e_equalLimits)\r
+ {\r
+ // Prevent large angular corrections\r
+ float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);\r
+ limitImpulse = -m_motorMass * C;\r
+ angularError = b2Abs(C);\r
+ }\r
+ else if (m_limitState == e_atLowerLimit)\r
+ {\r
+ float32 C = angle - m_lowerAngle;\r
+ angularError = -C;\r
+\r
+ // Prevent large angular corrections and allow some slop.\r
+ C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);\r
+ limitImpulse = -m_motorMass * C;\r
+ }\r
+ else if (m_limitState == e_atUpperLimit)\r
+ {\r
+ float32 C = angle - m_upperAngle;\r
+ angularError = C;\r
+\r
+ // Prevent large angular corrections and allow some slop.\r
+ C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);\r
+ limitImpulse = -m_motorMass * C;\r
+ }\r
+\r
+ b1->m_sweep.a -= b1->m_invI * limitImpulse;\r
+ b2->m_sweep.a += b2->m_invI * limitImpulse;\r
+\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+ }\r
+\r
+ // Solve point-to-point constraint.\r
+ {\r
+ b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());\r
+ b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());\r
+\r
+ b2Vec2 C = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;\r
+ positionError = C.Length();\r
+\r
+ float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;\r
+ float32 invI1 = b1->m_invI, invI2 = b2->m_invI;\r
+\r
+ // Handle large detachment.\r
+ const float32 k_allowedStretch = 10.0f * b2_linearSlop;\r
+ if (C.LengthSquared() > k_allowedStretch * k_allowedStretch)\r
+ {\r
+ // Use a particle solution (no rotation).\r
+ b2Vec2 u = C; u.Normalize();\r
+ float32 m = invMass1 + invMass2;\r
+ if (m > 0.0f)\r
+ {\r
+ m = 1.0f / m;\r
+ }\r
+ b2Vec2 impulse = m * (-C);\r
+ const float32 k_beta = 0.5f;\r
+ b1->m_sweep.c -= k_beta * invMass1 * impulse;\r
+ b2->m_sweep.c += k_beta * invMass2 * impulse;\r
+\r
+ C = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;\r
+ }\r
+\r
+ b2Mat22 K1;\r
+ K1.col1.x = invMass1 + invMass2; K1.col2.x = 0.0f;\r
+ K1.col1.y = 0.0f; K1.col2.y = invMass1 + invMass2;\r
+\r
+ b2Mat22 K2;\r
+ K2.col1.x = invI1 * r1.y * r1.y; K2.col2.x = -invI1 * r1.x * r1.y;\r
+ K2.col1.y = -invI1 * r1.x * r1.y; K2.col2.y = invI1 * r1.x * r1.x;\r
+\r
+ b2Mat22 K3;\r
+ K3.col1.x = invI2 * r2.y * r2.y; K3.col2.x = -invI2 * r2.x * r2.y;\r
+ K3.col1.y = -invI2 * r2.x * r2.y; K3.col2.y = invI2 * r2.x * r2.x;\r
+\r
+ b2Mat22 K = K1 + K2 + K3;\r
+ b2Vec2 impulse = K.Solve(-C);\r
+\r
+ b1->m_sweep.c -= b1->m_invMass * impulse;\r
+ b1->m_sweep.a -= b1->m_invI * b2Cross(r1, impulse);\r
+\r
+ b2->m_sweep.c += b2->m_invMass * impulse;\r
+ b2->m_sweep.a += b2->m_invI * b2Cross(r2, impulse);\r
+\r
+ b1->SynchronizeTransform();\r
+ b2->SynchronizeTransform();\r
+ }\r
+ \r
+ return positionError <= b2_linearSlop && angularError <= b2_angularSlop;\r
+}\r
+\r
+b2Vec2 b2RevoluteJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchor1);\r
+}\r
+\r
+b2Vec2 b2RevoluteJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchor2);\r
+}\r
+\r
+b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ b2Vec2 P(m_impulse.x, m_impulse.y);\r
+ return inv_dt * P;\r
+}\r
+\r
+float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ return inv_dt * m_impulse.z;\r
+}\r
+\r
+float32 b2RevoluteJoint::GetJointAngle() const\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+ return b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;\r
+}\r
+\r
+float32 b2RevoluteJoint::GetJointSpeed() const\r
+{\r
+ b2Body* b1 = m_bodyA;\r
+ b2Body* b2 = m_bodyB;\r
+ return b2->m_angularVelocity - b1->m_angularVelocity;\r
+}\r
+\r
+bool b2RevoluteJoint::IsMotorEnabled() const\r
+{\r
+ return m_enableMotor;\r
+}\r
+\r
+void b2RevoluteJoint::EnableMotor(bool flag)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_enableMotor = flag;\r
+}\r
+\r
+float32 b2RevoluteJoint::GetMotorTorque() const\r
+{\r
+ return m_motorImpulse;\r
+}\r
+\r
+void b2RevoluteJoint::SetMotorSpeed(float32 speed)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_motorSpeed = speed;\r
+}\r
+\r
+void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_maxMotorTorque = torque;\r
+}\r
+\r
+bool b2RevoluteJoint::IsLimitEnabled() const\r
+{\r
+ return m_enableLimit;\r
+}\r
+\r
+void b2RevoluteJoint::EnableLimit(bool flag)\r
+{\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_enableLimit = flag;\r
+}\r
+\r
+float32 b2RevoluteJoint::GetLowerLimit() const\r
+{\r
+ return m_lowerAngle;\r
+}\r
+\r
+float32 b2RevoluteJoint::GetUpperLimit() const\r
+{\r
+ return m_upperAngle;\r
+}\r
+\r
+void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)\r
+{\r
+ b2Assert(lower <= upper);\r
+ m_bodyA->SetAwake(true);\r
+ m_bodyB->SetAwake(true);\r
+ m_lowerAngle = lower;\r
+ m_upperAngle = upper;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_REVOLUTE_JOINT_H\r
+#define B2_REVOLUTE_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Revolute joint definition. This requires defining an\r
+/// anchor point where the bodies are joined. The definition\r
+/// uses local anchor points so that the initial configuration\r
+/// can violate the constraint slightly. You also need to\r
+/// specify the initial relative angle for joint limits. This\r
+/// helps when saving and loading a game.\r
+/// The local anchor points are measured from the body's origin\r
+/// rather than the center of mass because:\r
+/// 1. you might not know where the center of mass will be.\r
+/// 2. if you add/remove shapes from a body and recompute the mass,\r
+/// the joints will be broken.\r
+struct b2RevoluteJointDef : public b2JointDef\r
+{\r
+ b2RevoluteJointDef()\r
+ {\r
+ type = e_revoluteJoint;\r
+ localAnchorA.Set(0.0f, 0.0f);\r
+ localAnchorB.Set(0.0f, 0.0f);\r
+ referenceAngle = 0.0f;\r
+ lowerAngle = 0.0f;\r
+ upperAngle = 0.0f;\r
+ maxMotorTorque = 0.0f;\r
+ motorSpeed = 0.0f;\r
+ enableLimit = false;\r
+ enableMotor = false;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, and reference angle using a world\r
+ /// anchor point.\r
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);\r
+\r
+ /// The local anchor point relative to body1's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to body2's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The body2 angle minus body1 angle in the reference state (radians).\r
+ float32 referenceAngle;\r
+\r
+ /// A flag to enable joint limits.\r
+ bool enableLimit;\r
+\r
+ /// The lower angle for the joint limit (radians).\r
+ float32 lowerAngle;\r
+\r
+ /// The upper angle for the joint limit (radians).\r
+ float32 upperAngle;\r
+\r
+ /// A flag to enable the joint motor.\r
+ bool enableMotor;\r
+\r
+ /// The desired motor speed. Usually in radians per second.\r
+ float32 motorSpeed;\r
+\r
+ /// The maximum motor torque used to achieve the desired motor speed.\r
+ /// Usually in N-m.\r
+ float32 maxMotorTorque;\r
+};\r
+\r
+/// A revolute joint constrains two bodies to share a common point while they\r
+/// are free to rotate about the point. The relative rotation about the shared\r
+/// point is the joint angle. You can limit the relative rotation with\r
+/// a joint limit that specifies a lower and upper angle. You can use a motor\r
+/// to drive the relative rotation about the shared point. A maximum motor torque\r
+/// is provided so that infinite forces are not generated.\r
+class b2RevoluteJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+ /// Get the current joint angle in radians.\r
+ float32 GetJointAngle() const;\r
+\r
+ /// Get the current joint angle speed in radians per second.\r
+ float32 GetJointSpeed() const;\r
+\r
+ /// Is the joint limit enabled?\r
+ bool IsLimitEnabled() const;\r
+\r
+ /// Enable/disable the joint limit.\r
+ void EnableLimit(bool flag);\r
+\r
+ /// Get the lower joint limit in radians.\r
+ float32 GetLowerLimit() const;\r
+\r
+ /// Get the upper joint limit in radians.\r
+ float32 GetUpperLimit() const;\r
+\r
+ /// Set the joint limits in radians.\r
+ void SetLimits(float32 lower, float32 upper);\r
+\r
+ /// Is the joint motor enabled?\r
+ bool IsMotorEnabled() const;\r
+\r
+ /// Enable/disable the joint motor.\r
+ void EnableMotor(bool flag);\r
+\r
+ /// Set the motor speed in radians per second.\r
+ void SetMotorSpeed(float32 speed);\r
+\r
+ /// Get the motor speed in radians per second.\r
+ float32 GetMotorSpeed() const;\r
+\r
+ /// Set the maximum motor torque, usually in N-m.\r
+ void SetMaxMotorTorque(float32 torque);\r
+\r
+ /// Get the current motor torque, usually in N-m.\r
+ float32 GetMotorTorque() const;\r
+\r
+protected:\r
+ \r
+ friend class b2Joint;\r
+ friend class b2GearJoint;\r
+\r
+ b2RevoluteJoint(const b2RevoluteJointDef* def);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_localAnchor1; // relative\r
+ b2Vec2 m_localAnchor2;\r
+ b2Vec3 m_impulse;\r
+ float32 m_motorImpulse;\r
+\r
+ b2Mat33 m_mass; // effective mass for point-to-point constraint.\r
+ float32 m_motorMass; // effective mass for motor/limit angular constraint.\r
+ \r
+ bool m_enableMotor;\r
+ float32 m_maxMotorTorque;\r
+ float32 m_motorSpeed;\r
+\r
+ bool m_enableLimit;\r
+ float32 m_referenceAngle;\r
+ float32 m_lowerAngle;\r
+ float32 m_upperAngle;\r
+ b2LimitState m_limitState;\r
+};\r
+\r
+inline float32 b2RevoluteJoint::GetMotorSpeed() const\r
+{\r
+ return m_motorSpeed;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+// Point-to-point constraint\r
+// C = p2 - p1\r
+// Cdot = v2 - v1\r
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)\r
+// J = [-I -r1_skew I r2_skew ]\r
+// Identity used:\r
+// w k % (rx i + ry j) = w * (-ry i + rx j)\r
+\r
+// Angle constraint\r
+// C = angle2 - angle1 - referenceAngle\r
+// Cdot = w2 - w1\r
+// J = [0 0 -1 0 0 1]\r
+// K = invI1 + invI2\r
+\r
+void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)\r
+{\r
+ bodyA = bA;\r
+ bodyB = bB;\r
+ localAnchorA = bodyA->GetLocalPoint(anchor);\r
+ localAnchorB = bodyB->GetLocalPoint(anchor);\r
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();\r
+}\r
+\r
+b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)\r
+: b2Joint(def)\r
+{\r
+ m_localAnchorA = def->localAnchorA;\r
+ m_localAnchorB = def->localAnchorB;\r
+ m_referenceAngle = def->referenceAngle;\r
+\r
+ m_impulse.SetZero();\r
+}\r
+\r
+void b2WeldJoint::InitVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ b2Body* bA = m_bodyA;\r
+ b2Body* bB = m_bodyB;\r
+\r
+ // Compute the effective mass matrix.\r
+ b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());\r
+ b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());\r
+\r
+ // J = [-I -r1_skew I r2_skew]\r
+ // [ 0 -1 0 1]\r
+ // r_skew = [-ry; rx]\r
+\r
+ // Matlab\r
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]\r
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]\r
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]\r
+\r
+ float32 mA = bA->m_invMass, mB = bB->m_invMass;\r
+ float32 iA = bA->m_invI, iB = bB->m_invI;\r
+\r
+ m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;\r
+ m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;\r
+ m_mass.col3.x = -rA.y * iA - rB.y * iB;\r
+ m_mass.col1.y = m_mass.col2.x;\r
+ m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;\r
+ m_mass.col3.y = rA.x * iA + rB.x * iB;\r
+ m_mass.col1.z = m_mass.col3.x;\r
+ m_mass.col2.z = m_mass.col3.y;\r
+ m_mass.col3.z = iA + iB;\r
+\r
+ if (step.warmStarting)\r
+ {\r
+ // Scale impulses to support a variable time step.\r
+ m_impulse *= step.dtRatio;\r
+\r
+ b2Vec2 P(m_impulse.x, m_impulse.y);\r
+\r
+ bA->m_linearVelocity -= mA * P;\r
+ bA->m_angularVelocity -= iA * (b2Cross(rA, P) + m_impulse.z);\r
+\r
+ bB->m_linearVelocity += mB * P;\r
+ bB->m_angularVelocity += iB * (b2Cross(rB, P) + m_impulse.z);\r
+ }\r
+ else\r
+ {\r
+ m_impulse.SetZero();\r
+ }\r
+}\r
+\r
+void b2WeldJoint::SolveVelocityConstraints(const b2TimeStep& step)\r
+{\r
+ B2_NOT_USED(step);\r
+\r
+ b2Body* bA = m_bodyA;\r
+ b2Body* bB = m_bodyB;\r
+\r
+ b2Vec2 vA = bA->m_linearVelocity;\r
+ float32 wA = bA->m_angularVelocity;\r
+ b2Vec2 vB = bB->m_linearVelocity;\r
+ float32 wB = bB->m_angularVelocity;\r
+\r
+ float32 mA = bA->m_invMass, mB = bB->m_invMass;\r
+ float32 iA = bA->m_invI, iB = bB->m_invI;\r
+\r
+ b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());\r
+ b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());\r
+\r
+ // Solve point-to-point constraint\r
+ b2Vec2 Cdot1 = vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA);\r
+ float32 Cdot2 = wB - wA;\r
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);\r
+\r
+ b2Vec3 impulse = m_mass.Solve33(-Cdot);\r
+ m_impulse += impulse;\r
+\r
+ b2Vec2 P(impulse.x, impulse.y);\r
+\r
+ vA -= mA * P;\r
+ wA -= iA * (b2Cross(rA, P) + impulse.z);\r
+\r
+ vB += mB * P;\r
+ wB += iB * (b2Cross(rB, P) + impulse.z);\r
+\r
+ bA->m_linearVelocity = vA;\r
+ bA->m_angularVelocity = wA;\r
+ bB->m_linearVelocity = vB;\r
+ bB->m_angularVelocity = wB;\r
+}\r
+\r
+bool b2WeldJoint::SolvePositionConstraints(float32 baumgarte)\r
+{\r
+ B2_NOT_USED(baumgarte);\r
+\r
+ b2Body* bA = m_bodyA;\r
+ b2Body* bB = m_bodyB;\r
+\r
+ float32 mA = bA->m_invMass, mB = bB->m_invMass;\r
+ float32 iA = bA->m_invI, iB = bB->m_invI;\r
+\r
+ b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());\r
+ b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());\r
+\r
+ b2Vec2 C1 = bB->m_sweep.c + rB - bA->m_sweep.c - rA;\r
+ float32 C2 = bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;\r
+\r
+ // Handle large detachment.\r
+ const float32 k_allowedStretch = 10.0f * b2_linearSlop;\r
+ float32 positionError = C1.Length();\r
+ float32 angularError = b2Abs(C2);\r
+ if (positionError > k_allowedStretch)\r
+ {\r
+ iA *= 1.0f;\r
+ iB *= 1.0f;\r
+ }\r
+\r
+ m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;\r
+ m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;\r
+ m_mass.col3.x = -rA.y * iA - rB.y * iB;\r
+ m_mass.col1.y = m_mass.col2.x;\r
+ m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;\r
+ m_mass.col3.y = rA.x * iA + rB.x * iB;\r
+ m_mass.col1.z = m_mass.col3.x;\r
+ m_mass.col2.z = m_mass.col3.y;\r
+ m_mass.col3.z = iA + iB;\r
+\r
+ b2Vec3 C(C1.x, C1.y, C2);\r
+\r
+ b2Vec3 impulse = m_mass.Solve33(-C);\r
+\r
+ b2Vec2 P(impulse.x, impulse.y);\r
+\r
+ bA->m_sweep.c -= mA * P;\r
+ bA->m_sweep.a -= iA * (b2Cross(rA, P) + impulse.z);\r
+\r
+ bB->m_sweep.c += mB * P;\r
+ bB->m_sweep.a += iB * (b2Cross(rB, P) + impulse.z);\r
+\r
+ bA->SynchronizeTransform();\r
+ bB->SynchronizeTransform();\r
+\r
+ return positionError <= b2_linearSlop && angularError <= b2_angularSlop;\r
+}\r
+\r
+b2Vec2 b2WeldJoint::GetAnchorA() const\r
+{\r
+ return m_bodyA->GetWorldPoint(m_localAnchorA);\r
+}\r
+\r
+b2Vec2 b2WeldJoint::GetAnchorB() const\r
+{\r
+ return m_bodyB->GetWorldPoint(m_localAnchorB);\r
+}\r
+\r
+b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const\r
+{\r
+ b2Vec2 P(m_impulse.x, m_impulse.y);\r
+ return inv_dt * P;\r
+}\r
+\r
+float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const\r
+{\r
+ return inv_dt * m_impulse.z;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_WELD_JOINT_H\r
+#define B2_WELD_JOINT_H\r
+\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+/// Weld joint definition. You need to specify local anchor points\r
+/// where they are attached and the relative body angle. The position\r
+/// of the anchor points is important for computing the reaction torque.\r
+struct b2WeldJointDef : public b2JointDef\r
+{\r
+ b2WeldJointDef()\r
+ {\r
+ type = e_weldJoint;\r
+ localAnchorA.Set(0.0f, 0.0f);\r
+ localAnchorB.Set(0.0f, 0.0f);\r
+ referenceAngle = 0.0f;\r
+ }\r
+\r
+ /// Initialize the bodies, anchors, and reference angle using a world\r
+ /// anchor point.\r
+ void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor);\r
+\r
+ /// The local anchor point relative to body1's origin.\r
+ b2Vec2 localAnchorA;\r
+\r
+ /// The local anchor point relative to body2's origin.\r
+ b2Vec2 localAnchorB;\r
+\r
+ /// The body2 angle minus body1 angle in the reference state (radians).\r
+ float32 referenceAngle;\r
+};\r
+\r
+/// A weld joint essentially glues two bodies together. A weld joint may\r
+/// distort somewhat because the island constraint solver is approximate.\r
+class b2WeldJoint : public b2Joint\r
+{\r
+public:\r
+ b2Vec2 GetAnchorA() const;\r
+ b2Vec2 GetAnchorB() const;\r
+\r
+ b2Vec2 GetReactionForce(float32 inv_dt) const;\r
+ float32 GetReactionTorque(float32 inv_dt) const;\r
+\r
+protected:\r
+\r
+ friend class b2Joint;\r
+\r
+ b2WeldJoint(const b2WeldJointDef* def);\r
+\r
+ void InitVelocityConstraints(const b2TimeStep& step);\r
+ void SolveVelocityConstraints(const b2TimeStep& step);\r
+\r
+ bool SolvePositionConstraints(float32 baumgarte);\r
+\r
+ b2Vec2 m_localAnchorA;\r
+ b2Vec2 m_localAnchorB;\r
+ float32 m_referenceAngle;\r
+\r
+ b2Vec3 m_impulse;\r
+\r
+ b2Mat33 m_mass;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2World.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+\r
+b2Body::b2Body(const b2BodyDef* bd, b2World* world)\r
+{\r
+ b2Assert(bd->position.IsValid());\r
+ b2Assert(bd->linearVelocity.IsValid());\r
+ b2Assert(b2IsValid(bd->angle));\r
+ b2Assert(b2IsValid(bd->angularVelocity));\r
+ b2Assert(b2IsValid(bd->inertiaScale) && bd->inertiaScale >= 0.0f);\r
+ b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);\r
+ b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);\r
+\r
+ m_flags = 0;\r
+\r
+ if (bd->bullet)\r
+ {\r
+ m_flags |= e_bulletFlag;\r
+ }\r
+ if (bd->fixedRotation)\r
+ {\r
+ m_flags |= e_fixedRotationFlag;\r
+ }\r
+ if (bd->allowSleep)\r
+ {\r
+ m_flags |= e_autoSleepFlag;\r
+ }\r
+ if (bd->awake)\r
+ {\r
+ m_flags |= e_awakeFlag;\r
+ }\r
+ if (bd->active)\r
+ {\r
+ m_flags |= e_activeFlag;\r
+ }\r
+\r
+ m_world = world;\r
+\r
+ m_xf.position = bd->position;\r
+ m_xf.R.Set(bd->angle);\r
+\r
+ m_sweep.localCenter.SetZero();\r
+ m_sweep.a0 = m_sweep.a = bd->angle;\r
+ m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);\r
+\r
+ m_jointList = NULL;\r
+ m_contactList = NULL;\r
+ m_prev = NULL;\r
+ m_next = NULL;\r
+\r
+ m_linearVelocity = bd->linearVelocity;\r
+ m_angularVelocity = bd->angularVelocity;\r
+\r
+ m_linearDamping = bd->linearDamping;\r
+ m_angularDamping = bd->angularDamping;\r
+\r
+ m_force.SetZero();\r
+ m_torque = 0.0f;\r
+\r
+ m_sleepTime = 0.0f;\r
+\r
+ m_type = bd->type;\r
+\r
+ if (m_type == b2_dynamicBody)\r
+ {\r
+ m_mass = 1.0f;\r
+ m_invMass = 1.0f;\r
+ }\r
+ else\r
+ {\r
+ m_mass = 0.0f;\r
+ m_invMass = 0.0f;\r
+ }\r
+\r
+ m_I = 0.0f;\r
+ m_invI = 0.0f;\r
+\r
+ m_userData = bd->userData;\r
+\r
+ m_fixtureList = NULL;\r
+ m_fixtureCount = 0;\r
+}\r
+\r
+b2Body::~b2Body()\r
+{\r
+ // shapes and joints are destroyed in b2World::Destroy\r
+}\r
+\r
+void b2Body::SetType(b2BodyType type)\r
+{\r
+ if (m_type == type)\r
+ {\r
+ return;\r
+ }\r
+\r
+ m_type = type;\r
+\r
+ ResetMassData();\r
+\r
+ if (m_type == b2_staticBody)\r
+ {\r
+ m_linearVelocity.SetZero();\r
+ m_angularVelocity = 0.0f;\r
+ }\r
+\r
+ SetAwake(true);\r
+\r
+ m_force.SetZero();\r
+ m_torque = 0.0f;\r
+\r
+ // Since the body type changed, we need to flag contacts for filtering.\r
+ for (b2ContactEdge* ce = m_contactList; ce; ce = ce->next)\r
+ {\r
+ ce->contact->FlagForFiltering();\r
+ }\r
+}\r
+\r
+b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)\r
+{\r
+ b2Assert(m_world->IsLocked() == false);\r
+ if (m_world->IsLocked() == true)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ b2BlockAllocator* allocator = &m_world->m_blockAllocator;\r
+\r
+ void* memory = allocator->Allocate(sizeof(b2Fixture));\r
+ b2Fixture* fixture = new (memory) b2Fixture;\r
+ fixture->Create(allocator, this, def);\r
+\r
+ if (m_flags & e_activeFlag)\r
+ {\r
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;\r
+ fixture->CreateProxy(broadPhase, m_xf);\r
+ }\r
+\r
+ fixture->m_next = m_fixtureList;\r
+ m_fixtureList = fixture;\r
+ ++m_fixtureCount;\r
+\r
+ fixture->m_body = this;\r
+\r
+ // Adjust mass properties if needed.\r
+ if (fixture->m_density > 0.0f)\r
+ {\r
+ ResetMassData();\r
+ }\r
+\r
+ // Let the world know we have a new fixture. This will cause new contacts\r
+ // to be created at the beginning of the next time step.\r
+ m_world->m_flags |= b2World::e_newFixture;\r
+\r
+ return fixture;\r
+}\r
+\r
+b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)\r
+{\r
+ b2FixtureDef def;\r
+ def.shape = shape;\r
+ def.density = density;\r
+\r
+ return CreateFixture(&def);\r
+}\r
+\r
+void b2Body::DestroyFixture(b2Fixture* fixture)\r
+{\r
+ b2Assert(m_world->IsLocked() == false);\r
+ if (m_world->IsLocked() == true)\r
+ {\r
+ return;\r
+ }\r
+\r
+ b2Assert(fixture->m_body == this);\r
+\r
+ // Remove the fixture from this body's singly linked list.\r
+ b2Assert(m_fixtureCount > 0);\r
+ b2Fixture** node = &m_fixtureList;\r
+ bool found = false;\r
+ while (*node != NULL)\r
+ {\r
+ if (*node == fixture)\r
+ {\r
+ *node = fixture->m_next;\r
+ found = true;\r
+ break;\r
+ }\r
+\r
+ node = &(*node)->m_next;\r
+ }\r
+\r
+ // You tried to remove a shape that is not attached to this body.\r
+ b2Assert(found);\r
+\r
+ // Destroy any contacts associated with the fixture.\r
+ b2ContactEdge* edge = m_contactList;\r
+ while (edge)\r
+ {\r
+ b2Contact* c = edge->contact;\r
+ edge = edge->next;\r
+\r
+ b2Fixture* fixtureA = c->GetFixtureA();\r
+ b2Fixture* fixtureB = c->GetFixtureB();\r
+\r
+ if (fixture == fixtureA || fixture == fixtureB)\r
+ {\r
+ // This destroys the contact and removes it from\r
+ // this body's contact list.\r
+ m_world->m_contactManager.Destroy(c);\r
+ }\r
+ }\r
+\r
+ b2BlockAllocator* allocator = &m_world->m_blockAllocator;\r
+\r
+ if (m_flags & e_activeFlag)\r
+ {\r
+ b2Assert(fixture->m_proxyId != b2BroadPhase::e_nullProxy);\r
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;\r
+ fixture->DestroyProxy(broadPhase);\r
+ }\r
+ else\r
+ {\r
+ b2Assert(fixture->m_proxyId == b2BroadPhase::e_nullProxy);\r
+ }\r
+\r
+ fixture->Destroy(allocator);\r
+ fixture->m_body = NULL;\r
+ fixture->m_next = NULL;\r
+ fixture->~b2Fixture();\r
+ allocator->Free(fixture, sizeof(b2Fixture));\r
+\r
+ --m_fixtureCount;\r
+\r
+ // Reset the mass data.\r
+ ResetMassData();\r
+}\r
+\r
+void b2Body::ResetMassData()\r
+{\r
+ // Compute mass data from shapes. Each shape has its own density.\r
+ m_mass = 0.0f;\r
+ m_invMass = 0.0f;\r
+ m_I = 0.0f;\r
+ m_invI = 0.0f;\r
+ m_sweep.localCenter.SetZero();\r
+\r
+ // Static and kinematic bodies have zero mass.\r
+ if (m_type == b2_staticBody || m_type == b2_kinematicBody)\r
+ {\r
+ m_sweep.c0 = m_sweep.c = m_xf.position;\r
+ return;\r
+ }\r
+\r
+ b2Assert(m_type == b2_dynamicBody);\r
+\r
+ // Accumulate mass over all fixtures.\r
+ b2Vec2 center = b2Vec2_zero;\r
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)\r
+ {\r
+ if (f->m_density == 0.0f)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2MassData massData;\r
+ f->GetMassData(&massData);\r
+ m_mass += massData.mass;\r
+ center += massData.mass * massData.center;\r
+ m_I += massData.I;\r
+ }\r
+\r
+ // Compute center of mass.\r
+ if (m_mass > 0.0f)\r
+ {\r
+ m_invMass = 1.0f / m_mass;\r
+ center *= m_invMass;\r
+ }\r
+ else\r
+ {\r
+ // Force all dynamic bodies to have a positive mass.\r
+ m_mass = 1.0f;\r
+ m_invMass = 1.0f;\r
+ }\r
+\r
+ if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)\r
+ {\r
+ // Center the inertia about the center of mass.\r
+ m_I -= m_mass * b2Dot(center, center);\r
+ b2Assert(m_I > 0.0f);\r
+ m_invI = 1.0f / m_I;\r
+\r
+ }\r
+ else\r
+ {\r
+ m_I = 0.0f;\r
+ m_invI = 0.0f;\r
+ }\r
+\r
+ // Move center of mass.\r
+ b2Vec2 oldCenter = m_sweep.c;\r
+ m_sweep.localCenter = center;\r
+ m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);\r
+\r
+ // Update center of mass velocity.\r
+ m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);\r
+}\r
+\r
+void b2Body::SetMassData(const b2MassData* massData)\r
+{\r
+ b2Assert(m_world->IsLocked() == false);\r
+ if (m_world->IsLocked() == true)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (m_type != b2_dynamicBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ m_invMass = 0.0f;\r
+ m_I = 0.0f;\r
+ m_invI = 0.0f;\r
+\r
+ m_mass = massData->mass;\r
+ if (m_mass <= 0.0f)\r
+ {\r
+ m_mass = 1.0f;\r
+ }\r
+\r
+ m_invMass = 1.0f / m_mass;\r
+\r
+ if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)\r
+ {\r
+ m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);\r
+ b2Assert(m_I > 0.0f);\r
+ m_invI = 1.0f / m_I;\r
+ }\r
+\r
+ // Move center of mass.\r
+ b2Vec2 oldCenter = m_sweep.c;\r
+ m_sweep.localCenter = massData->center;\r
+ m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);\r
+\r
+ // Update center of mass velocity.\r
+ m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);\r
+}\r
+\r
+bool b2Body::ShouldCollide(const b2Body* other) const\r
+{\r
+ // At least one body should be dynamic.\r
+ if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // Does a joint prevent collision?\r
+ for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)\r
+ {\r
+ if (jn->other == other)\r
+ {\r
+ if (jn->joint->m_collideConnected == false)\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+void b2Body::SetTransform(const b2Vec2& position, float32 angle)\r
+{\r
+ b2Assert(m_world->IsLocked() == false);\r
+ if (m_world->IsLocked() == true)\r
+ {\r
+ return;\r
+ }\r
+\r
+ m_xf.R.Set(angle);\r
+ m_xf.position = position;\r
+\r
+ m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);\r
+ m_sweep.a0 = m_sweep.a = angle;\r
+\r
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;\r
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)\r
+ {\r
+ f->Synchronize(broadPhase, m_xf, m_xf);\r
+ }\r
+\r
+ m_world->m_contactManager.FindNewContacts();\r
+}\r
+\r
+void b2Body::SynchronizeFixtures()\r
+{\r
+ b2Transform xf1;\r
+ xf1.R.Set(m_sweep.a0);\r
+ xf1.position = m_sweep.c0 - b2Mul(xf1.R, m_sweep.localCenter);\r
+\r
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;\r
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)\r
+ {\r
+ f->Synchronize(broadPhase, xf1, m_xf);\r
+ }\r
+}\r
+\r
+void b2Body::SetActive(bool flag)\r
+{\r
+ if (flag == IsActive())\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (flag)\r
+ {\r
+ m_flags |= e_activeFlag;\r
+\r
+ // Create all proxies.\r
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;\r
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)\r
+ {\r
+ f->CreateProxy(broadPhase, m_xf);\r
+ }\r
+\r
+ // Contacts are created the next time step.\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_activeFlag;\r
+\r
+ // Destroy all proxies.\r
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;\r
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)\r
+ {\r
+ f->DestroyProxy(broadPhase);\r
+ }\r
+\r
+ // Destroy the attached contacts.\r
+ b2ContactEdge* ce = m_contactList;\r
+ while (ce)\r
+ {\r
+ b2ContactEdge* ce0 = ce;\r
+ ce = ce->next;\r
+ m_world->m_contactManager.Destroy(ce0->contact);\r
+ }\r
+ m_contactList = NULL;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_BODY_H\r
+#define B2_BODY_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <Box2D/Collision/Shapes/b2Shape.h>\r
+#include <memory>\r
+\r
+class b2Fixture;\r
+class b2Joint;\r
+class b2Contact;\r
+class b2Controller;\r
+class b2World;\r
+struct b2FixtureDef;\r
+struct b2JointEdge;\r
+struct b2ContactEdge;\r
+\r
+/// The body type.\r
+/// static: zero mass, zero velocity, may be manually moved\r
+/// kinematic: zero mass, non-zero velocity set by user, moved by solver\r
+/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver\r
+enum b2BodyType\r
+{\r
+ b2_staticBody = 0,\r
+ b2_kinematicBody,\r
+ b2_dynamicBody,\r
+};\r
+\r
+/// A body definition holds all the data needed to construct a rigid body.\r
+/// You can safely re-use body definitions. Shapes are added to a body after construction.\r
+struct b2BodyDef\r
+{\r
+ /// This constructor sets the body definition default values.\r
+ b2BodyDef()\r
+ {\r
+ userData = NULL;\r
+ position.Set(0.0f, 0.0f);\r
+ angle = 0.0f;\r
+ linearVelocity.Set(0.0f, 0.0f);\r
+ angularVelocity = 0.0f;\r
+ linearDamping = 0.0f;\r
+ angularDamping = 0.0f;\r
+ allowSleep = true;\r
+ awake = true;\r
+ fixedRotation = false;\r
+ bullet = false;\r
+ type = b2_staticBody;\r
+ active = true;\r
+ inertiaScale = 1.0f;\r
+ }\r
+\r
+ /// The body type: static, kinematic, or dynamic.\r
+ /// Note: if a dynamic body would have zero mass, the mass is set to one.\r
+ b2BodyType type;\r
+\r
+ /// The world position of the body. Avoid creating bodies at the origin\r
+ /// since this can lead to many overlapping shapes.\r
+ b2Vec2 position;\r
+\r
+ /// The world angle of the body in radians.\r
+ float32 angle;\r
+\r
+ /// The linear velocity of the body's origin in world co-ordinates.\r
+ b2Vec2 linearVelocity;\r
+\r
+ /// The angular velocity of the body.\r
+ float32 angularVelocity;\r
+\r
+ /// Linear damping is use to reduce the linear velocity. The damping parameter\r
+ /// can be larger than 1.0f but the damping effect becomes sensitive to the\r
+ /// time step when the damping parameter is large.\r
+ float32 linearDamping;\r
+\r
+ /// Angular damping is use to reduce the angular velocity. The damping parameter\r
+ /// can be larger than 1.0f but the damping effect becomes sensitive to the\r
+ /// time step when the damping parameter is large.\r
+ float32 angularDamping;\r
+\r
+ /// Set this flag to false if this body should never fall asleep. Note that\r
+ /// this increases CPU usage.\r
+ bool allowSleep;\r
+\r
+ /// Is this body initially awake or sleeping?\r
+ bool awake;\r
+\r
+ /// Should this body be prevented from rotating? Useful for characters.\r
+ bool fixedRotation;\r
+\r
+ /// Is this a fast moving body that should be prevented from tunneling through\r
+ /// other moving bodies? Note that all bodies are prevented from tunneling through\r
+ /// kinematic and static bodies. This setting is only considered on dynamic bodies.\r
+ /// @warning You should use this flag sparingly since it increases processing time.\r
+ bool bullet;\r
+\r
+ /// Does this body start out active?\r
+ bool active;\r
+\r
+ /// Use this to store application specific body data.\r
+ void* userData;\r
+\r
+ /// Experimental: scales the inertia tensor.\r
+ float32 inertiaScale;\r
+};\r
+\r
+/// A rigid body. These are created via b2World::CreateBody.\r
+class b2Body\r
+{\r
+public:\r
+ /// Creates a fixture and attach it to this body. Use this function if you need\r
+ /// to set some fixture parameters, like friction. Otherwise you can create the\r
+ /// fixture directly from a shape.\r
+ /// If the density is non-zero, this function automatically updates the mass of the body.\r
+ /// Contacts are not created until the next time step.\r
+ /// @param def the fixture definition.\r
+ /// @warning This function is locked during callbacks.\r
+ b2Fixture* CreateFixture(const b2FixtureDef* def);\r
+\r
+ /// Creates a fixture from a shape and attach it to this body.\r
+ /// This is a convenience function. Use b2FixtureDef if you need to set parameters\r
+ /// like friction, restitution, user data, or filtering.\r
+ /// If the density is non-zero, this function automatically updates the mass of the body.\r
+ /// @param shape the shape to be cloned.\r
+ /// @param density the shape density (set to zero for static bodies).\r
+ /// @warning This function is locked during callbacks.\r
+ b2Fixture* CreateFixture(const b2Shape* shape, float32 density);\r
+\r
+ /// Destroy a fixture. This removes the fixture from the broad-phase and\r
+ /// destroys all contacts associated with this fixture. This will\r
+ /// automatically adjust the mass of the body if the body is dynamic and the\r
+ /// fixture has positive density.\r
+ /// All fixtures attached to a body are implicitly destroyed when the body is destroyed.\r
+ /// @param fixture the fixture to be removed.\r
+ /// @warning This function is locked during callbacks.\r
+ void DestroyFixture(b2Fixture* fixture);\r
+\r
+ /// Set the position of the body's origin and rotation.\r
+ /// This breaks any contacts and wakes the other bodies.\r
+ /// Manipulating a body's transform may cause non-physical behavior.\r
+ /// @param position the world position of the body's local origin.\r
+ /// @param angle the world rotation in radians.\r
+ void SetTransform(const b2Vec2& position, float32 angle);\r
+\r
+ /// Get the body transform for the body's origin.\r
+ /// @return the world transform of the body's origin.\r
+ const b2Transform& GetTransform() const;\r
+\r
+ /// Get the world body origin position.\r
+ /// @return the world position of the body's origin.\r
+ const b2Vec2& GetPosition() const;\r
+\r
+ /// Get the angle in radians.\r
+ /// @return the current world rotation angle in radians.\r
+ float32 GetAngle() const;\r
+\r
+ /// Get the world position of the center of mass.\r
+ const b2Vec2& GetWorldCenter() const;\r
+\r
+ /// Get the local position of the center of mass.\r
+ const b2Vec2& GetLocalCenter() const;\r
+\r
+ /// Set the linear velocity of the center of mass.\r
+ /// @param v the new linear velocity of the center of mass.\r
+ void SetLinearVelocity(const b2Vec2& v);\r
+\r
+ /// Get the linear velocity of the center of mass.\r
+ /// @return the linear velocity of the center of mass.\r
+ b2Vec2 GetLinearVelocity() const;\r
+\r
+ /// Set the angular velocity.\r
+ /// @param omega the new angular velocity in radians/second.\r
+ void SetAngularVelocity(float32 omega);\r
+\r
+ /// Get the angular velocity.\r
+ /// @return the angular velocity in radians/second.\r
+ float32 GetAngularVelocity() const;\r
+\r
+ /// Apply a force at a world point. If the force is not\r
+ /// applied at the center of mass, it will generate a torque and\r
+ /// affect the angular velocity. This wakes up the body.\r
+ /// @param force the world force vector, usually in Newtons (N).\r
+ /// @param point the world position of the point of application.\r
+ void ApplyForce(const b2Vec2& force, const b2Vec2& point);\r
+\r
+ /// Apply a torque. This affects the angular velocity\r
+ /// without affecting the linear velocity of the center of mass.\r
+ /// This wakes up the body.\r
+ /// @param torque about the z-axis (out of the screen), usually in N-m.\r
+ void ApplyTorque(float32 torque);\r
+\r
+ /// Apply an impulse at a point. This immediately modifies the velocity.\r
+ /// It also modifies the angular velocity if the point of application\r
+ /// is not at the center of mass. This wakes up the body.\r
+ /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.\r
+ /// @param point the world position of the point of application.\r
+ void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point);\r
+\r
+ /// Apply an angular impulse.\r
+ /// @param impulse the angular impulse in units of kg*m*m/s\r
+ void ApplyAngularImpulse(float32 impulse);\r
+\r
+ /// Get the total mass of the body.\r
+ /// @return the mass, usually in kilograms (kg).\r
+ float32 GetMass() const;\r
+\r
+ /// Get the rotational inertia of the body about the local origin.\r
+ /// @return the rotational inertia, usually in kg-m^2.\r
+ float32 GetInertia() const;\r
+\r
+ /// Get the mass data of the body.\r
+ /// @return a struct containing the mass, inertia and center of the body.\r
+ void GetMassData(b2MassData* data) const;\r
+\r
+ /// Set the mass properties to override the mass properties of the fixtures.\r
+ /// Note that this changes the center of mass position.\r
+ /// Note that creating or destroying fixtures can also alter the mass.\r
+ /// This function has no effect if the body isn't dynamic.\r
+ /// @param massData the mass properties.\r
+ void SetMassData(const b2MassData* data);\r
+\r
+ /// This resets the mass properties to the sum of the mass properties of the fixtures.\r
+ /// This normally does not need to be called unless you called SetMassData to override\r
+ /// the mass and you later want to reset the mass.\r
+ void ResetMassData();\r
+\r
+ /// Get the world coordinates of a point given the local coordinates.\r
+ /// @param localPoint a point on the body measured relative the the body's origin.\r
+ /// @return the same point expressed in world coordinates.\r
+ b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const;\r
+\r
+ /// Get the world coordinates of a vector given the local coordinates.\r
+ /// @param localVector a vector fixed in the body.\r
+ /// @return the same vector expressed in world coordinates.\r
+ b2Vec2 GetWorldVector(const b2Vec2& localVector) const;\r
+\r
+ /// Gets a local point relative to the body's origin given a world point.\r
+ /// @param a point in world coordinates.\r
+ /// @return the corresponding local point relative to the body's origin.\r
+ b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const;\r
+\r
+ /// Gets a local vector given a world vector.\r
+ /// @param a vector in world coordinates.\r
+ /// @return the corresponding local vector.\r
+ b2Vec2 GetLocalVector(const b2Vec2& worldVector) const;\r
+\r
+ /// Get the world linear velocity of a world point attached to this body.\r
+ /// @param a point in world coordinates.\r
+ /// @return the world velocity of a point.\r
+ b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;\r
+\r
+ /// Get the world velocity of a local point.\r
+ /// @param a point in local coordinates.\r
+ /// @return the world velocity of a point.\r
+ b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const;\r
+\r
+ /// Get the linear damping of the body.\r
+ float32 GetLinearDamping() const;\r
+\r
+ /// Set the linear damping of the body.\r
+ void SetLinearDamping(float32 linearDamping);\r
+\r
+ /// Get the angular damping of the body.\r
+ float32 GetAngularDamping() const;\r
+\r
+ /// Set the angular damping of the body.\r
+ void SetAngularDamping(float32 angularDamping);\r
+\r
+ /// Set the type of this body. This may alter the mass and velocity.\r
+ void SetType(b2BodyType type);\r
+\r
+ /// Get the type of this body.\r
+ b2BodyType GetType() const;\r
+\r
+ /// Should this body be treated like a bullet for continuous collision detection?\r
+ void SetBullet(bool flag);\r
+\r
+ /// Is this body treated like a bullet for continuous collision detection?\r
+ bool IsBullet() const;\r
+\r
+ /// You can disable sleeping on this body. If you disable sleeping, the\r
+ /// body will be woken.\r
+ void SetSleepingAllowed(bool flag);\r
+\r
+ /// Is this body allowed to sleep\r
+ bool IsSleepingAllowed() const;\r
+\r
+ /// Set the sleep state of the body. A sleeping body has very\r
+ /// low CPU cost.\r
+ /// @param flag set to true to put body to sleep, false to wake it.\r
+ void SetAwake(bool flag);\r
+\r
+ /// Get the sleeping state of this body.\r
+ /// @return true if the body is sleeping.\r
+ bool IsAwake() const;\r
+\r
+ /// Set the active state of the body. An inactive body is not\r
+ /// simulated and cannot be collided with or woken up.\r
+ /// If you pass a flag of true, all fixtures will be added to the\r
+ /// broad-phase.\r
+ /// If you pass a flag of false, all fixtures will be removed from\r
+ /// the broad-phase and all contacts will be destroyed.\r
+ /// Fixtures and joints are otherwise unaffected. You may continue\r
+ /// to create/destroy fixtures and joints on inactive bodies.\r
+ /// Fixtures on an inactive body are implicitly inactive and will\r
+ /// not participate in collisions, ray-casts, or queries.\r
+ /// Joints connected to an inactive body are implicitly inactive.\r
+ /// An inactive body is still owned by a b2World object and remains\r
+ /// in the body list.\r
+ void SetActive(bool flag);\r
+\r
+ /// Get the active state of the body.\r
+ bool IsActive() const;\r
+\r
+ /// Set this body to have fixed rotation. This causes the mass\r
+ /// to be reset.\r
+ void SetFixedRotation(bool flag);\r
+\r
+ /// Does this body have fixed rotation?\r
+ bool IsFixedRotation() const;\r
+\r
+ /// Get the list of all fixtures attached to this body.\r
+ b2Fixture* GetFixtureList();\r
+ const b2Fixture* GetFixtureList() const;\r
+\r
+ /// Get the list of all joints attached to this body.\r
+ b2JointEdge* GetJointList();\r
+ const b2JointEdge* GetJointList() const;\r
+\r
+ /// Get the list of all contacts attached to this body.\r
+ /// @warning this list changes during the time step and you may\r
+ /// miss some collisions if you don't use b2ContactListener.\r
+ b2ContactEdge* GetContactList();\r
+ const b2ContactEdge* GetContactList() const;\r
+\r
+ /// Get the next body in the world's body list.\r
+ b2Body* GetNext();\r
+ const b2Body* GetNext() const;\r
+\r
+ /// Get the user data pointer that was provided in the body definition.\r
+ void* GetUserData() const;\r
+\r
+ /// Set the user data. Use this to store your application specific data.\r
+ void SetUserData(void* data);\r
+\r
+ /// Get the parent world of this body.\r
+ b2World* GetWorld();\r
+ const b2World* GetWorld() const;\r
+\r
+private:\r
+\r
+ friend class b2World;\r
+ friend class b2Island;\r
+ friend class b2ContactManager;\r
+ friend class b2ContactSolver;\r
+ friend class b2TOISolver;\r
+ \r
+ friend class b2DistanceJoint;\r
+ friend class b2GearJoint;\r
+ friend class b2LineJoint;\r
+ friend class b2MouseJoint;\r
+ friend class b2PrismaticJoint;\r
+ friend class b2PulleyJoint;\r
+ friend class b2RevoluteJoint;\r
+ friend class b2WeldJoint;\r
+ friend class b2FrictionJoint;\r
+\r
+ // m_flags\r
+ enum\r
+ {\r
+ e_islandFlag = 0x0001,\r
+ e_awakeFlag = 0x0002,\r
+ e_autoSleepFlag = 0x0004,\r
+ e_bulletFlag = 0x0008,\r
+ e_fixedRotationFlag = 0x0010,\r
+ e_activeFlag = 0x0020,\r
+ e_toiFlag = 0x0040,\r
+ };\r
+\r
+ b2Body(const b2BodyDef* bd, b2World* world);\r
+ ~b2Body();\r
+\r
+ void SynchronizeFixtures();\r
+ void SynchronizeTransform();\r
+\r
+ // This is used to prevent connected bodies from colliding.\r
+ // It may lie, depending on the collideConnected flag.\r
+ bool ShouldCollide(const b2Body* other) const;\r
+\r
+ void Advance(float32 t);\r
+\r
+ b2BodyType m_type;\r
+\r
+ uint16 m_flags;\r
+\r
+ int32 m_islandIndex;\r
+\r
+ b2Transform m_xf; // the body origin transform\r
+ b2Sweep m_sweep; // the swept motion for CCD\r
+\r
+ b2Vec2 m_linearVelocity;\r
+ float32 m_angularVelocity;\r
+\r
+ b2Vec2 m_force;\r
+ float32 m_torque;\r
+\r
+ b2World* m_world;\r
+ b2Body* m_prev;\r
+ b2Body* m_next;\r
+\r
+ b2Fixture* m_fixtureList;\r
+ int32 m_fixtureCount;\r
+\r
+ b2JointEdge* m_jointList;\r
+ b2ContactEdge* m_contactList;\r
+\r
+ float32 m_mass, m_invMass;\r
+\r
+ // Rotational inertia about the center of mass.\r
+ float32 m_I, m_invI;\r
+\r
+ float32 m_linearDamping;\r
+ float32 m_angularDamping;\r
+\r
+ float32 m_sleepTime;\r
+\r
+ void* m_userData;\r
+};\r
+\r
+inline b2BodyType b2Body::GetType() const\r
+{\r
+ return m_type;\r
+}\r
+\r
+inline const b2Transform& b2Body::GetTransform() const\r
+{\r
+ return m_xf;\r
+}\r
+\r
+inline const b2Vec2& b2Body::GetPosition() const\r
+{\r
+ return m_xf.position;\r
+}\r
+\r
+inline float32 b2Body::GetAngle() const\r
+{\r
+ return m_sweep.a;\r
+}\r
+\r
+inline const b2Vec2& b2Body::GetWorldCenter() const\r
+{\r
+ return m_sweep.c;\r
+}\r
+\r
+inline const b2Vec2& b2Body::GetLocalCenter() const\r
+{\r
+ return m_sweep.localCenter;\r
+}\r
+\r
+inline void b2Body::SetLinearVelocity(const b2Vec2& v)\r
+{\r
+ if (m_type == b2_staticBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (b2Dot(v,v) > 0.0f)\r
+ {\r
+ SetAwake(true);\r
+ }\r
+\r
+ m_linearVelocity = v;\r
+}\r
+\r
+inline b2Vec2 b2Body::GetLinearVelocity() const\r
+{\r
+ return m_linearVelocity;\r
+}\r
+\r
+inline void b2Body::SetAngularVelocity(float32 w)\r
+{\r
+ if (m_type == b2_staticBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (w * w > 0.0f)\r
+ {\r
+ SetAwake(true);\r
+ }\r
+\r
+ m_angularVelocity = w;\r
+}\r
+\r
+inline float32 b2Body::GetAngularVelocity() const\r
+{\r
+ return m_angularVelocity;\r
+}\r
+\r
+inline float32 b2Body::GetMass() const\r
+{\r
+ return m_mass;\r
+}\r
+\r
+inline float32 b2Body::GetInertia() const\r
+{\r
+ return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);\r
+}\r
+\r
+inline void b2Body::GetMassData(b2MassData* data) const\r
+{\r
+ data->mass = m_mass;\r
+ data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);\r
+ data->center = m_sweep.localCenter;\r
+}\r
+\r
+inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const\r
+{\r
+ return b2Mul(m_xf, localPoint);\r
+}\r
+\r
+inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const\r
+{\r
+ return b2Mul(m_xf.R, localVector);\r
+}\r
+\r
+inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const\r
+{\r
+ return b2MulT(m_xf, worldPoint);\r
+}\r
+\r
+inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const\r
+{\r
+ return b2MulT(m_xf.R, worldVector);\r
+}\r
+\r
+inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const\r
+{\r
+ return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c);\r
+}\r
+\r
+inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const\r
+{\r
+ return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));\r
+}\r
+\r
+inline float32 b2Body::GetLinearDamping() const\r
+{\r
+ return m_linearDamping;\r
+}\r
+\r
+inline void b2Body::SetLinearDamping(float32 linearDamping)\r
+{\r
+ m_linearDamping = linearDamping;\r
+}\r
+\r
+inline float32 b2Body::GetAngularDamping() const\r
+{\r
+ return m_angularDamping;\r
+}\r
+\r
+inline void b2Body::SetAngularDamping(float32 angularDamping)\r
+{\r
+ m_angularDamping = angularDamping;\r
+}\r
+\r
+inline void b2Body::SetBullet(bool flag)\r
+{\r
+ if (flag)\r
+ {\r
+ m_flags |= e_bulletFlag;\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_bulletFlag;\r
+ }\r
+}\r
+\r
+inline bool b2Body::IsBullet() const\r
+{\r
+ return (m_flags & e_bulletFlag) == e_bulletFlag;\r
+}\r
+\r
+inline void b2Body::SetAwake(bool flag)\r
+{\r
+ if (flag)\r
+ {\r
+ if ((m_flags & e_awakeFlag) == 0)\r
+ {\r
+ m_flags |= e_awakeFlag;\r
+ m_sleepTime = 0.0f;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_awakeFlag;\r
+ m_sleepTime = 0.0f;\r
+ m_linearVelocity.SetZero();\r
+ m_angularVelocity = 0.0f;\r
+ m_force.SetZero();\r
+ m_torque = 0.0f;\r
+ }\r
+}\r
+\r
+inline bool b2Body::IsAwake() const\r
+{\r
+ return (m_flags & e_awakeFlag) == e_awakeFlag;\r
+}\r
+\r
+inline bool b2Body::IsActive() const\r
+{\r
+ return (m_flags & e_activeFlag) == e_activeFlag;\r
+}\r
+\r
+inline void b2Body::SetFixedRotation(bool flag)\r
+{\r
+ if (flag)\r
+ {\r
+ m_flags |= e_fixedRotationFlag;\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_fixedRotationFlag;\r
+ }\r
+\r
+ ResetMassData();\r
+}\r
+\r
+inline bool b2Body::IsFixedRotation() const\r
+{\r
+ return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;\r
+}\r
+\r
+inline void b2Body::SetSleepingAllowed(bool flag)\r
+{\r
+ if (flag)\r
+ {\r
+ m_flags |= e_autoSleepFlag;\r
+ }\r
+ else\r
+ {\r
+ m_flags &= ~e_autoSleepFlag;\r
+ SetAwake(true);\r
+ }\r
+}\r
+\r
+inline bool b2Body::IsSleepingAllowed() const\r
+{\r
+ return (m_flags & e_autoSleepFlag) == e_autoSleepFlag;\r
+}\r
+\r
+inline b2Fixture* b2Body::GetFixtureList()\r
+{\r
+ return m_fixtureList;\r
+}\r
+\r
+inline const b2Fixture* b2Body::GetFixtureList() const\r
+{\r
+ return m_fixtureList;\r
+}\r
+\r
+inline b2JointEdge* b2Body::GetJointList()\r
+{\r
+ return m_jointList;\r
+}\r
+\r
+inline const b2JointEdge* b2Body::GetJointList() const\r
+{\r
+ return m_jointList;\r
+}\r
+\r
+inline b2ContactEdge* b2Body::GetContactList()\r
+{\r
+ return m_contactList;\r
+}\r
+\r
+inline const b2ContactEdge* b2Body::GetContactList() const\r
+{\r
+ return m_contactList;\r
+}\r
+\r
+inline b2Body* b2Body::GetNext()\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline const b2Body* b2Body::GetNext() const\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline void b2Body::SetUserData(void* data)\r
+{\r
+ m_userData = data;\r
+}\r
+\r
+inline void* b2Body::GetUserData() const\r
+{\r
+ return m_userData;\r
+}\r
+\r
+inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point)\r
+{\r
+ if (m_type != b2_dynamicBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (IsAwake() == false)\r
+ {\r
+ SetAwake(true);\r
+ }\r
+\r
+ m_force += force;\r
+ m_torque += b2Cross(point - m_sweep.c, force);\r
+}\r
+\r
+inline void b2Body::ApplyTorque(float32 torque)\r
+{\r
+ if (m_type != b2_dynamicBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (IsAwake() == false)\r
+ {\r
+ SetAwake(true);\r
+ }\r
+\r
+ m_torque += torque;\r
+}\r
+\r
+inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point)\r
+{\r
+ if (m_type != b2_dynamicBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (IsAwake() == false)\r
+ {\r
+ SetAwake(true);\r
+ }\r
+ m_linearVelocity += m_invMass * impulse;\r
+ m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);\r
+}\r
+\r
+inline void b2Body::ApplyAngularImpulse(float32 impulse)\r
+{\r
+ if (m_type != b2_dynamicBody)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (IsAwake() == false)\r
+ {\r
+ SetAwake(true);\r
+ }\r
+ m_angularVelocity += m_invI * impulse;\r
+}\r
+\r
+inline void b2Body::SynchronizeTransform()\r
+{\r
+ m_xf.R.Set(m_sweep.a);\r
+ m_xf.position = m_sweep.c - b2Mul(m_xf.R, m_sweep.localCenter);\r
+}\r
+\r
+inline void b2Body::Advance(float32 t)\r
+{\r
+ // Advance to the new safe time.\r
+ m_sweep.Advance(t);\r
+ m_sweep.c = m_sweep.c0;\r
+ m_sweep.a = m_sweep.a0;\r
+ SynchronizeTransform();\r
+}\r
+\r
+inline b2World* b2Body::GetWorld()\r
+{\r
+ return m_world;\r
+}\r
+\r
+inline const b2World* b2Body::GetWorld() const\r
+{\r
+ return m_world;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/b2ContactManager.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2WorldCallbacks.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+\r
+b2ContactFilter b2_defaultFilter;\r
+b2ContactListener b2_defaultListener;\r
+\r
+b2ContactManager::b2ContactManager()\r
+{\r
+ m_contactList = NULL;\r
+ m_contactCount = 0;\r
+ m_contactFilter = &b2_defaultFilter;\r
+ m_contactListener = &b2_defaultListener;\r
+ m_allocator = NULL;\r
+}\r
+\r
+void b2ContactManager::Destroy(b2Contact* c)\r
+{\r
+ b2Fixture* fixtureA = c->GetFixtureA();\r
+ b2Fixture* fixtureB = c->GetFixtureB();\r
+ b2Body* bodyA = fixtureA->GetBody();\r
+ b2Body* bodyB = fixtureB->GetBody();\r
+\r
+ if (m_contactListener && c->IsTouching())\r
+ {\r
+ m_contactListener->EndContact(c);\r
+ }\r
+\r
+ // Remove from the world.\r
+ if (c->m_prev)\r
+ {\r
+ c->m_prev->m_next = c->m_next;\r
+ }\r
+\r
+ if (c->m_next)\r
+ {\r
+ c->m_next->m_prev = c->m_prev;\r
+ }\r
+\r
+ if (c == m_contactList)\r
+ {\r
+ m_contactList = c->m_next;\r
+ }\r
+\r
+ // Remove from body 1\r
+ if (c->m_nodeA.prev)\r
+ {\r
+ c->m_nodeA.prev->next = c->m_nodeA.next;\r
+ }\r
+\r
+ if (c->m_nodeA.next)\r
+ {\r
+ c->m_nodeA.next->prev = c->m_nodeA.prev;\r
+ }\r
+\r
+ if (&c->m_nodeA == bodyA->m_contactList)\r
+ {\r
+ bodyA->m_contactList = c->m_nodeA.next;\r
+ }\r
+\r
+ // Remove from body 2\r
+ if (c->m_nodeB.prev)\r
+ {\r
+ c->m_nodeB.prev->next = c->m_nodeB.next;\r
+ }\r
+\r
+ if (c->m_nodeB.next)\r
+ {\r
+ c->m_nodeB.next->prev = c->m_nodeB.prev;\r
+ }\r
+\r
+ if (&c->m_nodeB == bodyB->m_contactList)\r
+ {\r
+ bodyB->m_contactList = c->m_nodeB.next;\r
+ }\r
+\r
+ // Call the factory.\r
+ b2Contact::Destroy(c, m_allocator);\r
+ --m_contactCount;\r
+}\r
+\r
+// This is the top level collision call for the time step. Here\r
+// all the narrow phase collision is processed for the world\r
+// contact list.\r
+void b2ContactManager::Collide()\r
+{\r
+ // Update awake contacts.\r
+ b2Contact* c = m_contactList;\r
+ while (c)\r
+ {\r
+ b2Fixture* fixtureA = c->GetFixtureA();\r
+ b2Fixture* fixtureB = c->GetFixtureB();\r
+ b2Body* bodyA = fixtureA->GetBody();\r
+ b2Body* bodyB = fixtureB->GetBody();\r
+\r
+ if (bodyA->IsAwake() == false && bodyB->IsAwake() == false)\r
+ {\r
+ c = c->GetNext();\r
+ continue;\r
+ }\r
+\r
+ // Is this contact flagged for filtering?\r
+ if (c->m_flags & b2Contact::e_filterFlag)\r
+ {\r
+ // Should these bodies collide?\r
+ if (bodyB->ShouldCollide(bodyA) == false)\r
+ {\r
+ b2Contact* cNuke = c;\r
+ c = cNuke->GetNext();\r
+ Destroy(cNuke);\r
+ continue;\r
+ }\r
+\r
+ // Check user filtering.\r
+ if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)\r
+ {\r
+ b2Contact* cNuke = c;\r
+ c = cNuke->GetNext();\r
+ Destroy(cNuke);\r
+ continue;\r
+ }\r
+\r
+ // Clear the filtering flag.\r
+ c->m_flags &= ~b2Contact::e_filterFlag;\r
+ }\r
+\r
+ int32 proxyIdA = fixtureA->m_proxyId;\r
+ int32 proxyIdB = fixtureB->m_proxyId;\r
+ bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB);\r
+\r
+ // Here we destroy contacts that cease to overlap in the broad-phase.\r
+ if (overlap == false)\r
+ {\r
+ b2Contact* cNuke = c;\r
+ c = cNuke->GetNext();\r
+ Destroy(cNuke);\r
+ continue;\r
+ }\r
+\r
+ // The contact persists.\r
+ c->Update(m_contactListener);\r
+ c = c->GetNext();\r
+ }\r
+}\r
+\r
+void b2ContactManager::FindNewContacts()\r
+{\r
+ m_broadPhase.UpdatePairs(this);\r
+}\r
+\r
+void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB)\r
+{\r
+ b2Fixture* fixtureA = (b2Fixture*)proxyUserDataA;\r
+ b2Fixture* fixtureB = (b2Fixture*)proxyUserDataB;\r
+\r
+ b2Body* bodyA = fixtureA->GetBody();\r
+ b2Body* bodyB = fixtureB->GetBody();\r
+\r
+ // Are the fixtures on the same body?\r
+ if (bodyA == bodyB)\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Does a contact already exist?\r
+ b2ContactEdge* edge = bodyB->GetContactList();\r
+ while (edge)\r
+ {\r
+ if (edge->other == bodyA)\r
+ {\r
+ b2Fixture* fA = edge->contact->GetFixtureA();\r
+ b2Fixture* fB = edge->contact->GetFixtureB();\r
+ if (fA == fixtureA && fB == fixtureB)\r
+ {\r
+ // A contact already exists.\r
+ return;\r
+ }\r
+\r
+ if (fA == fixtureB && fB == fixtureA)\r
+ {\r
+ // A contact already exists.\r
+ return;\r
+ }\r
+ }\r
+\r
+ edge = edge->next;\r
+ }\r
+\r
+ // Does a joint override collision? Is at least one body dynamic?\r
+ if (bodyB->ShouldCollide(bodyA) == false)\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Check user filtering.\r
+ if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Call the factory.\r
+ b2Contact* c = b2Contact::Create(fixtureA, fixtureB, m_allocator);\r
+\r
+ // Contact creation may swap fixtures.\r
+ fixtureA = c->GetFixtureA();\r
+ fixtureB = c->GetFixtureB();\r
+ bodyA = fixtureA->GetBody();\r
+ bodyB = fixtureB->GetBody();\r
+\r
+ // Insert into the world.\r
+ c->m_prev = NULL;\r
+ c->m_next = m_contactList;\r
+ if (m_contactList != NULL)\r
+ {\r
+ m_contactList->m_prev = c;\r
+ }\r
+ m_contactList = c;\r
+\r
+ // Connect to island graph.\r
+\r
+ // Connect to body A\r
+ c->m_nodeA.contact = c;\r
+ c->m_nodeA.other = bodyB;\r
+\r
+ c->m_nodeA.prev = NULL;\r
+ c->m_nodeA.next = bodyA->m_contactList;\r
+ if (bodyA->m_contactList != NULL)\r
+ {\r
+ bodyA->m_contactList->prev = &c->m_nodeA;\r
+ }\r
+ bodyA->m_contactList = &c->m_nodeA;\r
+\r
+ // Connect to body B\r
+ c->m_nodeB.contact = c;\r
+ c->m_nodeB.other = bodyA;\r
+\r
+ c->m_nodeB.prev = NULL;\r
+ c->m_nodeB.next = bodyB->m_contactList;\r
+ if (bodyB->m_contactList != NULL)\r
+ {\r
+ bodyB->m_contactList->prev = &c->m_nodeB;\r
+ }\r
+ bodyB->m_contactList = &c->m_nodeB;\r
+\r
+ ++m_contactCount;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_CONTACT_MANAGER_H\r
+#define B2_CONTACT_MANAGER_H\r
+\r
+#include <Box2D/Collision/b2BroadPhase.h>\r
+\r
+class b2Contact;\r
+class b2ContactFilter;\r
+class b2ContactListener;\r
+class b2BlockAllocator;\r
+\r
+// Delegate of b2World.\r
+class b2ContactManager\r
+{\r
+public:\r
+ b2ContactManager();\r
+\r
+ // Broad-phase callback.\r
+ void AddPair(void* proxyUserDataA, void* proxyUserDataB);\r
+\r
+ void FindNewContacts();\r
+\r
+ void Destroy(b2Contact* c);\r
+\r
+ void Collide();\r
+ \r
+ b2BroadPhase m_broadPhase;\r
+ b2Contact* m_contactList;\r
+ int32 m_contactCount;\r
+ b2ContactFilter* m_contactFilter;\r
+ b2ContactListener* m_contactListener;\r
+ b2BlockAllocator* m_allocator;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+#include <Box2D/Collision/b2BroadPhase.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Common/b2BlockAllocator.h>\r
+\r
+\r
+b2Fixture::b2Fixture()\r
+{\r
+ m_userData = NULL;\r
+ m_body = NULL;\r
+ m_next = NULL;\r
+ m_proxyId = b2BroadPhase::e_nullProxy;\r
+ m_shape = NULL;\r
+ m_density = 0.0f;\r
+}\r
+\r
+b2Fixture::~b2Fixture()\r
+{\r
+ b2Assert(m_shape == NULL);\r
+ b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);\r
+}\r
+\r
+void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def)\r
+{\r
+ m_userData = def->userData;\r
+ m_friction = def->friction;\r
+ m_restitution = def->restitution;\r
+\r
+ m_body = body;\r
+ m_next = NULL;\r
+\r
+ m_filter = def->filter;\r
+\r
+ m_isSensor = def->isSensor;\r
+\r
+ m_shape = def->shape->Clone(allocator);\r
+\r
+ m_density = def->density;\r
+}\r
+\r
+void b2Fixture::Destroy(b2BlockAllocator* allocator)\r
+{\r
+ // The proxy must be destroyed before calling this.\r
+ b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);\r
+\r
+ // Free the child shape.\r
+ switch (m_shape->m_type)\r
+ {\r
+ case b2Shape::e_circle:\r
+ {\r
+ b2CircleShape* s = (b2CircleShape*)m_shape;\r
+ s->~b2CircleShape();\r
+ allocator->Free(s, sizeof(b2CircleShape));\r
+ }\r
+ break;\r
+\r
+ case b2Shape::e_polygon:\r
+ {\r
+ b2PolygonShape* s = (b2PolygonShape*)m_shape;\r
+ s->~b2PolygonShape();\r
+ allocator->Free(s, sizeof(b2PolygonShape));\r
+ }\r
+ break;\r
+\r
+ default:\r
+ b2Assert(false);\r
+ break;\r
+ }\r
+\r
+ m_shape = NULL;\r
+}\r
+\r
+void b2Fixture::CreateProxy(b2BroadPhase* broadPhase, const b2Transform& xf)\r
+{\r
+ b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);\r
+\r
+ // Create proxy in the broad-phase.\r
+ m_shape->ComputeAABB(&m_aabb, xf);\r
+ m_proxyId = broadPhase->CreateProxy(m_aabb, this);\r
+}\r
+\r
+void b2Fixture::DestroyProxy(b2BroadPhase* broadPhase)\r
+{\r
+ if (m_proxyId == b2BroadPhase::e_nullProxy)\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Destroy proxy in the broad-phase.\r
+ broadPhase->DestroyProxy(m_proxyId);\r
+ m_proxyId = b2BroadPhase::e_nullProxy;\r
+}\r
+\r
+void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2)\r
+{\r
+ if (m_proxyId == b2BroadPhase::e_nullProxy)\r
+ { \r
+ return;\r
+ }\r
+\r
+ // Compute an AABB that covers the swept shape (may miss some rotation effect).\r
+ b2AABB aabb1, aabb2;\r
+ m_shape->ComputeAABB(&aabb1, transform1);\r
+ m_shape->ComputeAABB(&aabb2, transform2);\r
+ \r
+ m_aabb.Combine(aabb1, aabb2);\r
+\r
+ b2Vec2 displacement = transform2.position - transform1.position;\r
+\r
+ broadPhase->MoveProxy(m_proxyId, m_aabb, displacement);\r
+}\r
+\r
+void b2Fixture::SetFilterData(const b2Filter& filter)\r
+{\r
+ m_filter = filter;\r
+\r
+ if (m_body == NULL)\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Flag associated contacts for filtering.\r
+ b2ContactEdge* edge = m_body->GetContactList();\r
+ while (edge)\r
+ {\r
+ b2Contact* contact = edge->contact;\r
+ b2Fixture* fixtureA = contact->GetFixtureA();\r
+ b2Fixture* fixtureB = contact->GetFixtureB();\r
+ if (fixtureA == this || fixtureB == this)\r
+ {\r
+ contact->FlagForFiltering();\r
+ }\r
+\r
+ edge = edge->next;\r
+ }\r
+}\r
+\r
+void b2Fixture::SetSensor(bool sensor)\r
+{\r
+ m_isSensor = sensor;\r
+}\r
+\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_FIXTURE_H\r
+#define B2_FIXTURE_H\r
+\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/Shapes/b2Shape.h>\r
+\r
+class b2BlockAllocator;\r
+class b2Body;\r
+class b2BroadPhase;\r
+\r
+/// This holds contact filtering data.\r
+struct b2Filter\r
+{\r
+ /// The collision category bits. Normally you would just set one bit.\r
+ uint16 categoryBits;\r
+\r
+ /// The collision mask bits. This states the categories that this\r
+ /// shape would accept for collision.\r
+ uint16 maskBits;\r
+\r
+ /// Collision groups allow a certain group of objects to never collide (negative)\r
+ /// or always collide (positive). Zero means no collision group. Non-zero group\r
+ /// filtering always wins against the mask bits.\r
+ int16 groupIndex;\r
+};\r
+\r
+/// A fixture definition is used to create a fixture. This class defines an\r
+/// abstract fixture definition. You can reuse fixture definitions safely.\r
+struct b2FixtureDef\r
+{\r
+ /// The constructor sets the default fixture definition values.\r
+ b2FixtureDef()\r
+ {\r
+ shape = NULL;\r
+ userData = NULL;\r
+ friction = 0.2f;\r
+ restitution = 0.0f;\r
+ density = 0.0f;\r
+ filter.categoryBits = 0x0001;\r
+ filter.maskBits = 0xFFFF;\r
+ filter.groupIndex = 0;\r
+ isSensor = false;\r
+ }\r
+\r
+ virtual ~b2FixtureDef() {}\r
+\r
+ /// The shape, this must be set. The shape will be cloned, so you\r
+ /// can create the shape on the stack.\r
+ const b2Shape* shape;\r
+\r
+ /// Use this to store application specific fixture data.\r
+ void* userData;\r
+\r
+ /// The friction coefficient, usually in the range [0,1].\r
+ float32 friction;\r
+\r
+ /// The restitution (elasticity) usually in the range [0,1].\r
+ float32 restitution;\r
+\r
+ /// The density, usually in kg/m^2.\r
+ float32 density;\r
+\r
+ /// A sensor shape collects contact information but never generates a collision\r
+ /// response.\r
+ bool isSensor;\r
+\r
+ /// Contact filtering data.\r
+ b2Filter filter;\r
+};\r
+\r
+\r
+/// A fixture is used to attach a shape to a body for collision detection. A fixture\r
+/// inherits its transform from its parent. Fixtures hold additional non-geometric data\r
+/// such as friction, collision filters, etc.\r
+/// Fixtures are created via b2Body::CreateFixture.\r
+/// @warning you cannot reuse fixtures.\r
+class b2Fixture\r
+{\r
+public:\r
+ /// Get the type of the child shape. You can use this to down cast to the concrete shape.\r
+ /// @return the shape type.\r
+ b2Shape::Type GetType() const;\r
+\r
+ /// Get the child shape. You can modify the child shape, however you should not change the\r
+ /// number of vertices because this will crash some collision caching mechanisms.\r
+ /// Manipulating the shape may lead to non-physical behavior.\r
+ b2Shape* GetShape();\r
+ const b2Shape* GetShape() const;\r
+\r
+ /// Set if this fixture is a sensor.\r
+ void SetSensor(bool sensor);\r
+\r
+ /// Is this fixture a sensor (non-solid)?\r
+ /// @return the true if the shape is a sensor.\r
+ bool IsSensor() const;\r
+\r
+ /// Set the contact filtering data. This will not update contacts until the next time\r
+ /// step when either parent body is active and awake.\r
+ void SetFilterData(const b2Filter& filter);\r
+\r
+ /// Get the contact filtering data.\r
+ const b2Filter& GetFilterData() const;\r
+\r
+ /// Get the parent body of this fixture. This is NULL if the fixture is not attached.\r
+ /// @return the parent body.\r
+ b2Body* GetBody();\r
+ const b2Body* GetBody() const;\r
+\r
+ /// Get the next fixture in the parent body's fixture list.\r
+ /// @return the next shape.\r
+ b2Fixture* GetNext();\r
+ const b2Fixture* GetNext() const;\r
+\r
+ /// Get the user data that was assigned in the fixture definition. Use this to\r
+ /// store your application specific data.\r
+ void* GetUserData() const;\r
+\r
+ /// Set the user data. Use this to store your application specific data.\r
+ void SetUserData(void* data);\r
+\r
+ /// Test a point for containment in this fixture.\r
+ /// @param xf the shape world transform.\r
+ /// @param p a point in world coordinates.\r
+ bool TestPoint(const b2Vec2& p) const;\r
+\r
+ /// Cast a ray against this shape.\r
+ /// @param output the ray-cast results.\r
+ /// @param input the ray-cast input parameters.\r
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;\r
+\r
+ /// Get the mass data for this fixture. The mass data is based on the density and\r
+ /// the shape. The rotational inertia is about the shape's origin. This operation\r
+ /// may be expensive.\r
+ void GetMassData(b2MassData* massData) const;\r
+\r
+ /// Set the density of this fixture. This will _not_ automatically adjust the mass\r
+ /// of the body. You must call b2Body::ResetMassData to update the body's mass.\r
+ void SetDensity(float32 density);\r
+\r
+ /// Get the density of this fixture.\r
+ float32 GetDensity() const;\r
+\r
+ /// Get the coefficient of friction.\r
+ float32 GetFriction() const;\r
+\r
+ /// Set the coefficient of friction.\r
+ void SetFriction(float32 friction);\r
+\r
+ /// Get the coefficient of restitution.\r
+ float32 GetRestitution() const;\r
+\r
+ /// Set the coefficient of restitution.\r
+ void SetRestitution(float32 restitution);\r
+\r
+ /// Get the fixture's AABB. This AABB may be enlarge and/or stale.\r
+ /// If you need a more accurate AABB, compute it using the shape and\r
+ /// the body transform.\r
+ const b2AABB& GetAABB() const;\r
+\r
+protected:\r
+\r
+ friend class b2Body;\r
+ friend class b2World;\r
+ friend class b2Contact;\r
+ friend class b2ContactManager;\r
+\r
+ b2Fixture();\r
+ ~b2Fixture();\r
+\r
+ // We need separation create/destroy functions from the constructor/destructor because\r
+ // the destructor cannot access the allocator (no destructor arguments allowed by C++).\r
+ void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def);\r
+ void Destroy(b2BlockAllocator* allocator);\r
+\r
+ // These support body activation/deactivation.\r
+ void CreateProxy(b2BroadPhase* broadPhase, const b2Transform& xf);\r
+ void DestroyProxy(b2BroadPhase* broadPhase);\r
+\r
+ void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2);\r
+\r
+ b2AABB m_aabb;\r
+\r
+ float32 m_density;\r
+\r
+ b2Fixture* m_next;\r
+ b2Body* m_body;\r
+\r
+ b2Shape* m_shape;\r
+\r
+ float32 m_friction;\r
+ float32 m_restitution;\r
+\r
+ int32 m_proxyId;\r
+ b2Filter m_filter;\r
+\r
+ bool m_isSensor;\r
+\r
+ void* m_userData;\r
+};\r
+\r
+inline b2Shape::Type b2Fixture::GetType() const\r
+{\r
+ return m_shape->GetType();\r
+}\r
+\r
+inline b2Shape* b2Fixture::GetShape()\r
+{\r
+ return m_shape;\r
+}\r
+\r
+inline const b2Shape* b2Fixture::GetShape() const\r
+{\r
+ return m_shape;\r
+}\r
+\r
+inline bool b2Fixture::IsSensor() const\r
+{\r
+ return m_isSensor;\r
+}\r
+\r
+inline const b2Filter& b2Fixture::GetFilterData() const\r
+{\r
+ return m_filter;\r
+}\r
+\r
+inline void* b2Fixture::GetUserData() const\r
+{\r
+ return m_userData;\r
+}\r
+\r
+inline void b2Fixture::SetUserData(void* data)\r
+{\r
+ m_userData = data;\r
+}\r
+\r
+inline b2Body* b2Fixture::GetBody()\r
+{\r
+ return m_body;\r
+}\r
+\r
+inline const b2Body* b2Fixture::GetBody() const\r
+{\r
+ return m_body;\r
+}\r
+\r
+inline b2Fixture* b2Fixture::GetNext()\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline const b2Fixture* b2Fixture::GetNext() const\r
+{\r
+ return m_next;\r
+}\r
+\r
+inline void b2Fixture::SetDensity(float32 density)\r
+{\r
+ b2Assert(b2IsValid(density) && density >= 0.0f);\r
+ m_density = density;\r
+}\r
+\r
+inline float32 b2Fixture::GetDensity() const\r
+{\r
+ return m_density;\r
+}\r
+\r
+inline float32 b2Fixture::GetFriction() const\r
+{\r
+ return m_friction;\r
+}\r
+\r
+inline void b2Fixture::SetFriction(float32 friction)\r
+{\r
+ m_friction = friction;\r
+}\r
+\r
+inline float32 b2Fixture::GetRestitution() const\r
+{\r
+ return m_restitution;\r
+}\r
+\r
+inline void b2Fixture::SetRestitution(float32 restitution)\r
+{\r
+ m_restitution = restitution;\r
+}\r
+\r
+inline bool b2Fixture::TestPoint(const b2Vec2& p) const\r
+{\r
+ return m_shape->TestPoint(m_body->GetTransform(), p);\r
+}\r
+\r
+inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const\r
+{\r
+ return m_shape->RayCast(output, input, m_body->GetTransform());\r
+}\r
+\r
+inline void b2Fixture::GetMassData(b2MassData* massData) const\r
+{\r
+ m_shape->ComputeMass(massData, m_density);\r
+}\r
+\r
+inline const b2AABB& b2Fixture::GetAABB() const\r
+{\r
+ return m_aabb;\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/b2Island.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2World.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>\r
+#include <Box2D/Dynamics/Joints/b2Joint.h>\r
+#include <Box2D/Common/b2StackAllocator.h>\r
+\r
+/*\r
+Position Correction Notes\r
+=========================\r
+I tried the several algorithms for position correction of the 2D revolute joint.\r
+I looked at these systems:\r
+- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.\r
+- suspension bridge with 30 1m long planks of length 1m.\r
+- multi-link chain with 30 1m long links.\r
+\r
+Here are the algorithms:\r
+\r
+Baumgarte - A fraction of the position error is added to the velocity error. There is no\r
+separate position solver.\r
+\r
+Pseudo Velocities - After the velocity solver and position integration,\r
+the position error, Jacobian, and effective mass are recomputed. Then\r
+the velocity constraints are solved with pseudo velocities and a fraction\r
+of the position error is added to the pseudo velocity error. The pseudo\r
+velocities are initialized to zero and there is no warm-starting. After\r
+the position solver, the pseudo velocities are added to the positions.\r
+This is also called the First Order World method or the Position LCP method.\r
+\r
+Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the\r
+position error is re-computed for each constraint and the positions are updated\r
+after the constraint is solved. The radius vectors (aka Jacobians) are\r
+re-computed too (otherwise the algorithm has horrible instability). The pseudo\r
+velocity states are not needed because they are effectively zero at the beginning\r
+of each iteration. Since we have the current position error, we allow the\r
+iterations to terminate early if the error becomes smaller than b2_linearSlop.\r
+\r
+Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed\r
+each time a constraint is solved.\r
+\r
+Here are the results:\r
+Baumgarte - this is the cheapest algorithm but it has some stability problems,\r
+especially with the bridge. The chain links separate easily close to the root\r
+and they jitter as they struggle to pull together. This is one of the most common\r
+methods in the field. The big drawback is that the position correction artificially\r
+affects the momentum, thus leading to instabilities and false bounce. I used a\r
+bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller\r
+factor makes joints and contacts more spongy.\r
+\r
+Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is\r
+stable. However, joints still separate with large angular velocities. Drag the\r
+simple pendulum in a circle quickly and the joint will separate. The chain separates\r
+easily and does not recover. I used a bias factor of 0.2. A larger value lead to\r
+the bridge collapsing when a heavy cube drops on it.\r
+\r
+Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo\r
+Velocities, but in other ways it is worse. The bridge and chain are much more\r
+stable, but the simple pendulum goes unstable at high angular velocities.\r
+\r
+Full NGS - stable in all tests. The joints display good stiffness. The bridge\r
+still sags, but this is better than infinite forces.\r
+\r
+Recommendations\r
+Pseudo Velocities are not really worthwhile because the bridge and chain cannot\r
+recover from joint separation. In other cases the benefit over Baumgarte is small.\r
+\r
+Modified NGS is not a robust method for the revolute joint due to the violent\r
+instability seen in the simple pendulum. Perhaps it is viable with other constraint\r
+types, especially scalar constraints where the effective mass is a scalar.\r
+\r
+This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities\r
+and is very fast. I don't think we can escape Baumgarte, especially in highly\r
+demanding cases where high constraint fidelity is not needed.\r
+\r
+Full NGS is robust and easy on the eyes. I recommend this as an option for\r
+higher fidelity simulation and certainly for suspension bridges and long chains.\r
+Full NGS might be a good choice for ragdolls, especially motorized ragdolls where\r
+joint separation can be problematic. The number of NGS iterations can be reduced\r
+for better performance without harming robustness much.\r
+\r
+Each joint in a can be handled differently in the position solver. So I recommend\r
+a system where the user can select the algorithm on a per joint basis. I would\r
+probably default to the slower Full NGS and let the user select the faster\r
+Baumgarte method in performance critical scenarios.\r
+*/\r
+\r
+/*\r
+Cache Performance\r
+\r
+The Box2D solvers are dominated by cache misses. Data structures are designed\r
+to increase the number of cache hits. Much of misses are due to random access\r
+to body data. The constraint structures are iterated over linearly, which leads\r
+to few cache misses.\r
+\r
+The bodies are not accessed during iteration. Instead read only data, such as\r
+the mass values are stored with the constraints. The mutable data are the constraint\r
+impulses and the bodies velocities/positions. The impulses are held inside the\r
+constraint structures. The body velocities/positions are held in compact, temporary\r
+arrays to increase the number of cache hits. Linear and angular velocity are\r
+stored in a single array since multiple arrays lead to multiple misses.\r
+*/\r
+\r
+/*\r
+2D Rotation\r
+\r
+R = [cos(theta) -sin(theta)]\r
+ [sin(theta) cos(theta) ]\r
+\r
+thetaDot = omega\r
+\r
+Let q1 = cos(theta), q2 = sin(theta).\r
+R = [q1 -q2]\r
+ [q2 q1]\r
+\r
+q1Dot = -thetaDot * q2\r
+q2Dot = thetaDot * q1\r
+\r
+q1_new = q1_old - dt * w * q2\r
+q2_new = q2_old + dt * w * q1\r
+then normalize.\r
+\r
+This might be faster than computing sin+cos.\r
+However, we can compute sin+cos of the same angle fast.\r
+*/\r
+\r
+b2Island::b2Island(\r
+ int32 bodyCapacity,\r
+ int32 contactCapacity,\r
+ int32 jointCapacity,\r
+ b2StackAllocator* allocator,\r
+ b2ContactListener* listener)\r
+{\r
+ m_bodyCapacity = bodyCapacity;\r
+ m_contactCapacity = contactCapacity;\r
+ m_jointCapacity = jointCapacity;\r
+ m_bodyCount = 0;\r
+ m_contactCount = 0;\r
+ m_jointCount = 0;\r
+\r
+ m_allocator = allocator;\r
+ m_listener = listener;\r
+\r
+ m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*));\r
+ m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*));\r
+ m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*));\r
+\r
+ m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity));\r
+ m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position));\r
+}\r
+\r
+b2Island::~b2Island()\r
+{\r
+ // Warning: the order should reverse the constructor order.\r
+ m_allocator->Free(m_positions);\r
+ m_allocator->Free(m_velocities);\r
+ m_allocator->Free(m_joints);\r
+ m_allocator->Free(m_contacts);\r
+ m_allocator->Free(m_bodies);\r
+}\r
+\r
+void b2Island::Solve(const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep)\r
+{\r
+ // Integrate velocities and apply damping.\r
+ for (int32 i = 0; i < m_bodyCount; ++i)\r
+ {\r
+ b2Body* b = m_bodies[i];\r
+\r
+ if (b->GetType() != b2_dynamicBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Integrate velocities.\r
+ b->m_linearVelocity += step.dt * (gravity + b->m_invMass * b->m_force);\r
+ b->m_angularVelocity += step.dt * b->m_invI * b->m_torque;\r
+\r
+ // Apply damping.\r
+ // ODE: dv/dt + c * v = 0\r
+ // Solution: v(t) = v0 * exp(-c * t)\r
+ // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)\r
+ // v2 = exp(-c * dt) * v1\r
+ // Taylor expansion:\r
+ // v2 = (1.0f - c * dt) * v1\r
+ b->m_linearVelocity *= b2Clamp(1.0f - step.dt * b->m_linearDamping, 0.0f, 1.0f);\r
+ b->m_angularVelocity *= b2Clamp(1.0f - step.dt * b->m_angularDamping, 0.0f, 1.0f);\r
+ }\r
+\r
+ // Partition contacts so that contacts with static bodies are solved last.\r
+ int32 i1 = -1;\r
+ for (int32 i2 = 0; i2 < m_contactCount; ++i2)\r
+ {\r
+ b2Fixture* fixtureA = m_contacts[i2]->GetFixtureA();\r
+ b2Fixture* fixtureB = m_contacts[i2]->GetFixtureB();\r
+ b2Body* bodyA = fixtureA->GetBody();\r
+ b2Body* bodyB = fixtureB->GetBody();\r
+ bool nonStatic = bodyA->GetType() != b2_staticBody && bodyB->GetType() != b2_staticBody;\r
+ if (nonStatic)\r
+ {\r
+ ++i1;\r
+ b2Swap(m_contacts[i1], m_contacts[i2]);\r
+ }\r
+ }\r
+\r
+ // Initialize velocity constraints.\r
+ b2ContactSolver contactSolver(m_contacts, m_contactCount, m_allocator, step.dtRatio);\r
+ contactSolver.WarmStart();\r
+ for (int32 i = 0; i < m_jointCount; ++i)\r
+ {\r
+ m_joints[i]->InitVelocityConstraints(step);\r
+ }\r
+\r
+ // Solve velocity constraints.\r
+ for (int32 i = 0; i < step.velocityIterations; ++i)\r
+ {\r
+ for (int32 j = 0; j < m_jointCount; ++j)\r
+ {\r
+ m_joints[j]->SolveVelocityConstraints(step);\r
+ }\r
+\r
+ contactSolver.SolveVelocityConstraints();\r
+ }\r
+\r
+ // Post-solve (store impulses for warm starting).\r
+ contactSolver.StoreImpulses();\r
+\r
+ // Integrate positions.\r
+ for (int32 i = 0; i < m_bodyCount; ++i)\r
+ {\r
+ b2Body* b = m_bodies[i];\r
+\r
+ if (b->GetType() == b2_staticBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Check for large velocities.\r
+ b2Vec2 translation = step.dt * b->m_linearVelocity;\r
+ if (b2Dot(translation, translation) > b2_maxTranslationSquared)\r
+ {\r
+ float32 ratio = b2_maxTranslation / translation.Length();\r
+ b->m_linearVelocity *= ratio;\r
+ }\r
+\r
+ float32 rotation = step.dt * b->m_angularVelocity;\r
+ if (rotation * rotation > b2_maxRotationSquared)\r
+ {\r
+ float32 ratio = b2_maxRotation / b2Abs(rotation);\r
+ b->m_angularVelocity *= ratio;\r
+ }\r
+\r
+ // Store positions for continuous collision.\r
+ b->m_sweep.c0 = b->m_sweep.c;\r
+ b->m_sweep.a0 = b->m_sweep.a;\r
+\r
+ // Integrate\r
+ b->m_sweep.c += step.dt * b->m_linearVelocity;\r
+ b->m_sweep.a += step.dt * b->m_angularVelocity;\r
+\r
+ // Compute new transform\r
+ b->SynchronizeTransform();\r
+\r
+ // Note: shapes are synchronized later.\r
+ }\r
+\r
+ // Iterate over constraints.\r
+ for (int32 i = 0; i < step.positionIterations; ++i)\r
+ {\r
+ bool contactsOkay = contactSolver.SolvePositionConstraints(b2_contactBaumgarte);\r
+\r
+ bool jointsOkay = true;\r
+ for (int32 i = 0; i < m_jointCount; ++i)\r
+ {\r
+ bool jointOkay = m_joints[i]->SolvePositionConstraints(b2_contactBaumgarte);\r
+ jointsOkay = jointsOkay && jointOkay;\r
+ }\r
+\r
+ if (contactsOkay && jointsOkay)\r
+ {\r
+ // Exit early if the position errors are small.\r
+ break;\r
+ }\r
+ }\r
+\r
+ Report(contactSolver.m_constraints);\r
+\r
+ if (allowSleep)\r
+ {\r
+ float32 minSleepTime = b2_maxFloat;\r
+\r
+ const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance;\r
+ const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance;\r
+\r
+ for (int32 i = 0; i < m_bodyCount; ++i)\r
+ {\r
+ b2Body* b = m_bodies[i];\r
+ if (b->GetType() == b2_staticBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if ((b->m_flags & b2Body::e_autoSleepFlag) == 0)\r
+ {\r
+ b->m_sleepTime = 0.0f;\r
+ minSleepTime = 0.0f;\r
+ }\r
+\r
+ if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 ||\r
+ b->m_angularVelocity * b->m_angularVelocity > angTolSqr ||\r
+ b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr)\r
+ {\r
+ b->m_sleepTime = 0.0f;\r
+ minSleepTime = 0.0f;\r
+ }\r
+ else\r
+ {\r
+ b->m_sleepTime += step.dt;\r
+ minSleepTime = b2Min(minSleepTime, b->m_sleepTime);\r
+ }\r
+ }\r
+\r
+ if (minSleepTime >= b2_timeToSleep)\r
+ {\r
+ for (int32 i = 0; i < m_bodyCount; ++i)\r
+ {\r
+ b2Body* b = m_bodies[i];\r
+ b->SetAwake(false);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void b2Island::Report(const b2ContactConstraint* constraints)\r
+{\r
+ if (m_listener == NULL)\r
+ {\r
+ return;\r
+ }\r
+\r
+ for (int32 i = 0; i < m_contactCount; ++i)\r
+ {\r
+ b2Contact* c = m_contacts[i];\r
+\r
+ const b2ContactConstraint* cc = constraints + i;\r
+ \r
+ b2ContactImpulse impulse;\r
+ for (int32 j = 0; j < cc->pointCount; ++j)\r
+ {\r
+ impulse.normalImpulses[j] = cc->points[j].normalImpulse;\r
+ impulse.tangentImpulses[j] = cc->points[j].tangentImpulse;\r
+ }\r
+\r
+ m_listener->PostSolve(c, &impulse);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_ISLAND_H\r
+#define B2_ISLAND_H\r
+\r
+#include <Box2D/Common/b2Math.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2TimeStep.h>\r
+\r
+class b2Contact;\r
+class b2Joint;\r
+class b2StackAllocator;\r
+class b2ContactListener;\r
+struct b2ContactConstraint;\r
+\r
+/// This is an internal structure.\r
+struct b2Position\r
+{\r
+ b2Vec2 x;\r
+ float32 a;\r
+};\r
+\r
+/// This is an internal structure.\r
+struct b2Velocity\r
+{\r
+ b2Vec2 v;\r
+ float32 w;\r
+};\r
+\r
+/// This is an internal class.\r
+class b2Island\r
+{\r
+public:\r
+ b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity,\r
+ b2StackAllocator* allocator, b2ContactListener* listener);\r
+ ~b2Island();\r
+\r
+ void Clear()\r
+ {\r
+ m_bodyCount = 0;\r
+ m_contactCount = 0;\r
+ m_jointCount = 0;\r
+ }\r
+\r
+ void Solve(const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep);\r
+\r
+ void Add(b2Body* body)\r
+ {\r
+ b2Assert(m_bodyCount < m_bodyCapacity);\r
+ body->m_islandIndex = m_bodyCount;\r
+ m_bodies[m_bodyCount++] = body;\r
+ }\r
+\r
+ void Add(b2Contact* contact)\r
+ {\r
+ b2Assert(m_contactCount < m_contactCapacity);\r
+ m_contacts[m_contactCount++] = contact;\r
+ }\r
+\r
+ void Add(b2Joint* joint)\r
+ {\r
+ b2Assert(m_jointCount < m_jointCapacity);\r
+ m_joints[m_jointCount++] = joint;\r
+ }\r
+\r
+ void Report(const b2ContactConstraint* constraints);\r
+\r
+ b2StackAllocator* m_allocator;\r
+ b2ContactListener* m_listener;\r
+\r
+ b2Body** m_bodies;\r
+ b2Contact** m_contacts;\r
+ b2Joint** m_joints;\r
+\r
+ b2Position* m_positions;\r
+ b2Velocity* m_velocities;\r
+\r
+ int32 m_bodyCount;\r
+ int32 m_jointCount;\r
+ int32 m_contactCount;\r
+\r
+ int32 m_bodyCapacity;\r
+ int32 m_contactCapacity;\r
+ int32 m_jointCapacity;\r
+\r
+ int32 m_positionIterationCount;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_TIME_STEP_H\r
+#define B2_TIME_STEP_H\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+\r
+/// This is an internal structure.
+struct b2TimeStep
+{
+ float32 dt; // time step
+ float32 inv_dt; // inverse time step (0 if dt == 0).
+ float32 dtRatio; // dt * inv_dt0
+ int32 velocityIterations;
+ int32 positionIterations;
+ bool warmStarting;
+};
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/b2World.h>\r
+#include <Box2D/Dynamics/b2Body.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+#include <Box2D/Dynamics/b2Island.h>\r
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>\r
+#include <Box2D/Dynamics/Contacts/b2Contact.h>\r
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>\r
+#include <Box2D/Dynamics/Contacts/b2TOISolver.h>\r
+#include <Box2D/Collision/b2Collision.h>\r
+#include <Box2D/Collision/b2BroadPhase.h>\r
+#include <Box2D/Collision/Shapes/b2CircleShape.h>\r
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>\r
+#include <Box2D/Collision/b2TimeOfImpact.h>\r
+#include <new>\r
+\r
+b2World::b2World(const b2Vec2& gravity, bool doSleep)\r
+{\r
+ m_destructionListener = NULL;\r
+ m_debugDraw = NULL;\r
+\r
+ m_bodyList = NULL;\r
+ m_jointList = NULL;\r
+\r
+ m_bodyCount = 0;\r
+ m_jointCount = 0;\r
+\r
+ m_warmStarting = true;\r
+ m_continuousPhysics = true;\r
+\r
+ m_allowSleep = doSleep;\r
+ m_gravity = gravity;\r
+\r
+ m_flags = e_clearForces;\r
+\r
+ m_inv_dt0 = 0.0f;\r
+\r
+ m_contactManager.m_allocator = &m_blockAllocator;\r
+}\r
+\r
+b2World::~b2World()\r
+{\r
+}\r
+\r
+void b2World::SetDestructionListener(b2DestructionListener* listener)\r
+{\r
+ m_destructionListener = listener;\r
+}\r
+\r
+void b2World::SetContactFilter(b2ContactFilter* filter)\r
+{\r
+ m_contactManager.m_contactFilter = filter;\r
+}\r
+\r
+void b2World::SetContactListener(b2ContactListener* listener)\r
+{\r
+ m_contactManager.m_contactListener = listener;\r
+}\r
+\r
+void b2World::SetDebugDraw(b2DebugDraw* debugDraw)\r
+{\r
+ m_debugDraw = debugDraw;\r
+}\r
+\r
+b2Body* b2World::CreateBody(const b2BodyDef* def)\r
+{\r
+ b2Assert(IsLocked() == false);\r
+ if (IsLocked())\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ void* mem = m_blockAllocator.Allocate(sizeof(b2Body));\r
+ b2Body* b = new (mem) b2Body(def, this);\r
+\r
+ // Add to world doubly linked list.\r
+ b->m_prev = NULL;\r
+ b->m_next = m_bodyList;\r
+ if (m_bodyList)\r
+ {\r
+ m_bodyList->m_prev = b;\r
+ }\r
+ m_bodyList = b;\r
+ ++m_bodyCount;\r
+\r
+ return b;\r
+}\r
+\r
+void b2World::DestroyBody(b2Body* b)\r
+{\r
+ b2Assert(m_bodyCount > 0);\r
+ b2Assert(IsLocked() == false);\r
+ if (IsLocked())\r
+ {\r
+ return;\r
+ }\r
+\r
+ // Delete the attached joints.\r
+ b2JointEdge* je = b->m_jointList;\r
+ while (je)\r
+ {\r
+ b2JointEdge* je0 = je;\r
+ je = je->next;\r
+\r
+ if (m_destructionListener)\r
+ {\r
+ m_destructionListener->SayGoodbye(je0->joint);\r
+ }\r
+\r
+ DestroyJoint(je0->joint);\r
+ }\r
+ b->m_jointList = NULL;\r
+\r
+ // Delete the attached contacts.\r
+ b2ContactEdge* ce = b->m_contactList;\r
+ while (ce)\r
+ {\r
+ b2ContactEdge* ce0 = ce;\r
+ ce = ce->next;\r
+ m_contactManager.Destroy(ce0->contact);\r
+ }\r
+ b->m_contactList = NULL;\r
+\r
+ // Delete the attached fixtures. This destroys broad-phase proxies.\r
+ b2Fixture* f = b->m_fixtureList;\r
+ while (f)\r
+ {\r
+ b2Fixture* f0 = f;\r
+ f = f->m_next;\r
+\r
+ if (m_destructionListener)\r
+ {\r
+ m_destructionListener->SayGoodbye(f0);\r
+ }\r
+\r
+ f0->DestroyProxy(&m_contactManager.m_broadPhase);\r
+ f0->Destroy(&m_blockAllocator);\r
+ f0->~b2Fixture();\r
+ m_blockAllocator.Free(f0, sizeof(b2Fixture));\r
+ }\r
+ b->m_fixtureList = NULL;\r
+ b->m_fixtureCount = 0;\r
+\r
+ // Remove world body list.\r
+ if (b->m_prev)\r
+ {\r
+ b->m_prev->m_next = b->m_next;\r
+ }\r
+\r
+ if (b->m_next)\r
+ {\r
+ b->m_next->m_prev = b->m_prev;\r
+ }\r
+\r
+ if (b == m_bodyList)\r
+ {\r
+ m_bodyList = b->m_next;\r
+ }\r
+\r
+ --m_bodyCount;\r
+ b->~b2Body();\r
+ m_blockAllocator.Free(b, sizeof(b2Body));\r
+}\r
+\r
+b2Joint* b2World::CreateJoint(const b2JointDef* def)\r
+{\r
+ b2Assert(IsLocked() == false);\r
+ if (IsLocked())\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ b2Joint* j = b2Joint::Create(def, &m_blockAllocator);\r
+\r
+ // Connect to the world list.\r
+ j->m_prev = NULL;\r
+ j->m_next = m_jointList;\r
+ if (m_jointList)\r
+ {\r
+ m_jointList->m_prev = j;\r
+ }\r
+ m_jointList = j;\r
+ ++m_jointCount;\r
+\r
+ // Connect to the bodies' doubly linked lists.\r
+ j->m_edgeA.joint = j;\r
+ j->m_edgeA.other = j->m_bodyB;\r
+ j->m_edgeA.prev = NULL;\r
+ j->m_edgeA.next = j->m_bodyA->m_jointList;\r
+ if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA;\r
+ j->m_bodyA->m_jointList = &j->m_edgeA;\r
+\r
+ j->m_edgeB.joint = j;\r
+ j->m_edgeB.other = j->m_bodyA;\r
+ j->m_edgeB.prev = NULL;\r
+ j->m_edgeB.next = j->m_bodyB->m_jointList;\r
+ if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB;\r
+ j->m_bodyB->m_jointList = &j->m_edgeB;\r
+\r
+ b2Body* bodyA = def->bodyA;\r
+ b2Body* bodyB = def->bodyB;\r
+\r
+ // If the joint prevents collisions, then flag any contacts for filtering.\r
+ if (def->collideConnected == false)\r
+ {\r
+ b2ContactEdge* edge = bodyB->GetContactList();\r
+ while (edge)\r
+ {\r
+ if (edge->other == bodyA)\r
+ {\r
+ // Flag the contact for filtering at the next time step (where either\r
+ // body is awake).\r
+ edge->contact->FlagForFiltering();\r
+ }\r
+\r
+ edge = edge->next;\r
+ }\r
+ }\r
+\r
+ // Note: creating a joint doesn't wake the bodies.\r
+\r
+ return j;\r
+}\r
+\r
+void b2World::DestroyJoint(b2Joint* j)\r
+{\r
+ b2Assert(IsLocked() == false);\r
+ if (IsLocked())\r
+ {\r
+ return;\r
+ }\r
+\r
+ bool collideConnected = j->m_collideConnected;\r
+\r
+ // Remove from the doubly linked list.\r
+ if (j->m_prev)\r
+ {\r
+ j->m_prev->m_next = j->m_next;\r
+ }\r
+\r
+ if (j->m_next)\r
+ {\r
+ j->m_next->m_prev = j->m_prev;\r
+ }\r
+\r
+ if (j == m_jointList)\r
+ {\r
+ m_jointList = j->m_next;\r
+ }\r
+\r
+ // Disconnect from island graph.\r
+ b2Body* bodyA = j->m_bodyA;\r
+ b2Body* bodyB = j->m_bodyB;\r
+\r
+ // Wake up connected bodies.\r
+ bodyA->SetAwake(true);\r
+ bodyB->SetAwake(true);\r
+\r
+ // Remove from body 1.\r
+ if (j->m_edgeA.prev)\r
+ {\r
+ j->m_edgeA.prev->next = j->m_edgeA.next;\r
+ }\r
+\r
+ if (j->m_edgeA.next)\r
+ {\r
+ j->m_edgeA.next->prev = j->m_edgeA.prev;\r
+ }\r
+\r
+ if (&j->m_edgeA == bodyA->m_jointList)\r
+ {\r
+ bodyA->m_jointList = j->m_edgeA.next;\r
+ }\r
+\r
+ j->m_edgeA.prev = NULL;\r
+ j->m_edgeA.next = NULL;\r
+\r
+ // Remove from body 2\r
+ if (j->m_edgeB.prev)\r
+ {\r
+ j->m_edgeB.prev->next = j->m_edgeB.next;\r
+ }\r
+\r
+ if (j->m_edgeB.next)\r
+ {\r
+ j->m_edgeB.next->prev = j->m_edgeB.prev;\r
+ }\r
+\r
+ if (&j->m_edgeB == bodyB->m_jointList)\r
+ {\r
+ bodyB->m_jointList = j->m_edgeB.next;\r
+ }\r
+\r
+ j->m_edgeB.prev = NULL;\r
+ j->m_edgeB.next = NULL;\r
+\r
+ b2Joint::Destroy(j, &m_blockAllocator);\r
+\r
+ b2Assert(m_jointCount > 0);\r
+ --m_jointCount;\r
+\r
+ // If the joint prevents collisions, then flag any contacts for filtering.\r
+ if (collideConnected == false)\r
+ {\r
+ b2ContactEdge* edge = bodyB->GetContactList();\r
+ while (edge)\r
+ {\r
+ if (edge->other == bodyA)\r
+ {\r
+ // Flag the contact for filtering at the next time step (where either\r
+ // body is awake).\r
+ edge->contact->FlagForFiltering();\r
+ }\r
+\r
+ edge = edge->next;\r
+ }\r
+ }\r
+}\r
+\r
+// Find islands, integrate and solve constraints, solve position constraints\r
+void b2World::Solve(const b2TimeStep& step)\r
+{\r
+ // Size the island for the worst case.\r
+ b2Island island(m_bodyCount,\r
+ m_contactManager.m_contactCount,\r
+ m_jointCount,\r
+ &m_stackAllocator,\r
+ m_contactManager.m_contactListener);\r
+\r
+ // Clear all the island flags.\r
+ for (b2Body* b = m_bodyList; b; b = b->m_next)\r
+ {\r
+ b->m_flags &= ~b2Body::e_islandFlag;\r
+ }\r
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)\r
+ {\r
+ c->m_flags &= ~b2Contact::e_islandFlag;\r
+ }\r
+ for (b2Joint* j = m_jointList; j; j = j->m_next)\r
+ {\r
+ j->m_islandFlag = false;\r
+ }\r
+\r
+ // Build and simulate all awake islands.\r
+ int32 stackSize = m_bodyCount;\r
+ b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*));\r
+ for (b2Body* seed = m_bodyList; seed; seed = seed->m_next)\r
+ {\r
+ if (seed->m_flags & b2Body::e_islandFlag)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (seed->IsAwake() == false || seed->IsActive() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // The seed can be dynamic or kinematic.\r
+ if (seed->GetType() == b2_staticBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Reset island and stack.\r
+ island.Clear();\r
+ int32 stackCount = 0;\r
+ stack[stackCount++] = seed;\r
+ seed->m_flags |= b2Body::e_islandFlag;\r
+\r
+ // Perform a depth first search (DFS) on the constraint graph.\r
+ while (stackCount > 0)\r
+ {\r
+ // Grab the next body off the stack and add it to the island.\r
+ b2Body* b = stack[--stackCount];\r
+ b2Assert(b->IsActive() == true);\r
+ island.Add(b);\r
+\r
+ // Make sure the body is awake.\r
+ b->SetAwake(true);\r
+\r
+ // To keep islands as small as possible, we don't\r
+ // propagate islands across static bodies.\r
+ if (b->GetType() == b2_staticBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Search all contacts connected to this body.\r
+ for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next)\r
+ {\r
+ b2Contact* contact = ce->contact;\r
+\r
+ // Has this contact already been added to an island?\r
+ if (contact->m_flags & b2Contact::e_islandFlag)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Is this contact solid and touching?\r
+ if (contact->IsEnabled() == false ||\r
+ contact->IsTouching() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Skip sensors.\r
+ bool sensorA = contact->m_fixtureA->m_isSensor;\r
+ bool sensorB = contact->m_fixtureB->m_isSensor;\r
+ if (sensorA || sensorB)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ island.Add(contact);\r
+ contact->m_flags |= b2Contact::e_islandFlag;\r
+\r
+ b2Body* other = ce->other;\r
+\r
+ // Was the other body already added to this island?\r
+ if (other->m_flags & b2Body::e_islandFlag)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Assert(stackCount < stackSize);\r
+ stack[stackCount++] = other;\r
+ other->m_flags |= b2Body::e_islandFlag;\r
+ }\r
+\r
+ // Search all joints connect to this body.\r
+ for (b2JointEdge* je = b->m_jointList; je; je = je->next)\r
+ {\r
+ if (je->joint->m_islandFlag == true)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Body* other = je->other;\r
+\r
+ // Don't simulate joints connected to inactive bodies.\r
+ if (other->IsActive() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ island.Add(je->joint);\r
+ je->joint->m_islandFlag = true;\r
+\r
+ if (other->m_flags & b2Body::e_islandFlag)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Assert(stackCount < stackSize);\r
+ stack[stackCount++] = other;\r
+ other->m_flags |= b2Body::e_islandFlag;\r
+ }\r
+ }\r
+\r
+ island.Solve(step, m_gravity, m_allowSleep);\r
+\r
+ // Post solve cleanup.\r
+ for (int32 i = 0; i < island.m_bodyCount; ++i)\r
+ {\r
+ // Allow static bodies to participate in other islands.\r
+ b2Body* b = island.m_bodies[i];\r
+ if (b->GetType() == b2_staticBody)\r
+ {\r
+ b->m_flags &= ~b2Body::e_islandFlag;\r
+ }\r
+ }\r
+ }\r
+\r
+ m_stackAllocator.Free(stack);\r
+\r
+ // Synchronize fixtures, check for out of range bodies.\r
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())\r
+ {\r
+ // If a body was not in an island then it did not move.\r
+ if ((b->m_flags & b2Body::e_islandFlag) == 0)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (b->GetType() == b2_staticBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Update fixtures (for broad-phase).\r
+ b->SynchronizeFixtures();\r
+ }\r
+\r
+ // Look for new contacts.\r
+ m_contactManager.FindNewContacts();\r
+}\r
+\r
+// Advance a dynamic body to its first time of contact\r
+// and adjust the position to ensure clearance.\r
+void b2World::SolveTOI(b2Body* body)\r
+{\r
+ // Find the minimum contact.\r
+ b2Contact* toiContact = NULL;\r
+ float32 toi = 1.0f;\r
+ b2Body* toiOther = NULL;\r
+ bool found;\r
+ int32 count;\r
+ int32 iter = 0;\r
+\r
+ bool bullet = body->IsBullet();\r
+\r
+ // Iterate until all contacts agree on the minimum TOI. We have\r
+ // to iterate because the TOI algorithm may skip some intermediate\r
+ // collisions when objects rotate through each other.\r
+ do\r
+ {\r
+ count = 0;\r
+ found = false;\r
+ for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)\r
+ {\r
+ if (ce->contact == toiContact)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Body* other = ce->other;\r
+ b2BodyType type = other->GetType();\r
+\r
+ // Only bullets perform TOI with dynamic bodies.\r
+ if (bullet == true)\r
+ {\r
+ // Bullets only perform TOI with bodies that have their TOI resolved.\r
+ if ((other->m_flags & b2Body::e_toiFlag) == 0)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // No repeated hits on non-static bodies\r
+ if (type != b2_staticBody && (ce->contact->m_flags & b2Contact::e_bulletHitFlag) != 0)\r
+ {\r
+ continue;\r
+ }\r
+ }\r
+ else if (type == b2_dynamicBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Check for a disabled contact.\r
+ b2Contact* contact = ce->contact;\r
+ if (contact->IsEnabled() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Prevent infinite looping.\r
+ if (contact->m_toiCount > 10)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Fixture* fixtureA = contact->m_fixtureA;\r
+ b2Fixture* fixtureB = contact->m_fixtureB;\r
+\r
+ // Cull sensors.\r
+ if (fixtureA->IsSensor() || fixtureB->IsSensor())\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Body* bodyA = fixtureA->m_body;\r
+ b2Body* bodyB = fixtureB->m_body;\r
+\r
+ // Compute the time of impact in interval [0, minTOI]\r
+ b2TOIInput input;\r
+ input.proxyA.Set(fixtureA->GetShape());\r
+ input.proxyB.Set(fixtureB->GetShape());\r
+ input.sweepA = bodyA->m_sweep;\r
+ input.sweepB = bodyB->m_sweep;\r
+ input.tMax = toi;\r
+\r
+ b2TOIOutput output;\r
+ b2TimeOfImpact(&output, &input);\r
+\r
+ if (output.state == b2TOIOutput::e_touching && output.t < toi)\r
+ {\r
+ toiContact = contact;\r
+ toi = output.t;\r
+ toiOther = other;\r
+ found = true;\r
+ }\r
+\r
+ ++count;\r
+ }\r
+\r
+ ++iter;\r
+ } while (found && count > 1 && iter < 50);\r
+\r
+ if (toiContact == NULL)\r
+ {\r
+ body->Advance(1.0f);\r
+ return;\r
+ }\r
+\r
+ b2Sweep backup = body->m_sweep;\r
+ body->Advance(toi);\r
+ toiContact->Update(m_contactManager.m_contactListener);\r
+ if (toiContact->IsEnabled() == false)\r
+ {\r
+ // Contact disabled. Backup and recurse.\r
+ body->m_sweep = backup;\r
+ SolveTOI(body);\r
+ }\r
+\r
+ ++toiContact->m_toiCount;\r
+\r
+ // Update all the valid contacts on this body and build a contact island.\r
+ b2Contact* contacts[b2_maxTOIContacts];\r
+ count = 0;\r
+ for (b2ContactEdge* ce = body->m_contactList; ce && count < b2_maxTOIContacts; ce = ce->next)\r
+ {\r
+ b2Body* other = ce->other;\r
+ b2BodyType type = other->GetType();\r
+\r
+ // Only perform correction with static bodies, so the\r
+ // body won't get pushed out of the world.\r
+ if (type == b2_dynamicBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // Check for a disabled contact.\r
+ b2Contact* contact = ce->contact;\r
+ if (contact->IsEnabled() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Fixture* fixtureA = contact->m_fixtureA;\r
+ b2Fixture* fixtureB = contact->m_fixtureB;\r
+\r
+ // Cull sensors.\r
+ if (fixtureA->IsSensor() || fixtureB->IsSensor())\r
+ {\r
+ continue;\r
+ }\r
+\r
+ // The contact likely has some new contact points. The listener\r
+ // gives the user a chance to disable the contact.\r
+ if (contact != toiContact)\r
+ {\r
+ contact->Update(m_contactManager.m_contactListener);\r
+ }\r
+\r
+ // Did the user disable the contact?\r
+ if (contact->IsEnabled() == false)\r
+ {\r
+ // Skip this contact.\r
+ continue;\r
+ }\r
+\r
+ if (contact->IsTouching() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ contacts[count] = contact;\r
+ ++count;\r
+ }\r
+\r
+ // Reduce the TOI body's overlap with the contact island.\r
+ b2TOISolver solver(&m_stackAllocator);\r
+ solver.Initialize(contacts, count, body);\r
+\r
+ const float32 k_toiBaumgarte = 0.75f;\r
+ bool solved = false;\r
+ for (int32 i = 0; i < 20; ++i)\r
+ {\r
+ bool contactsOkay = solver.Solve(k_toiBaumgarte);\r
+ if (contactsOkay)\r
+ {\r
+ solved = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (toiOther->GetType() != b2_staticBody)\r
+ {\r
+ toiContact->m_flags |= b2Contact::e_bulletHitFlag;\r
+ }\r
+}\r
+\r
+// Sequentially solve TOIs for each body. We bring each\r
+// body to the time of contact and perform some position correction.\r
+// Time is not conserved.\r
+void b2World::SolveTOI()\r
+{\r
+ // Prepare all contacts.\r
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)\r
+ {\r
+ // Enable the contact\r
+ c->m_flags |= b2Contact::e_enabledFlag;\r
+\r
+ // Set the number of TOI events for this contact to zero.\r
+ c->m_toiCount = 0;\r
+ }\r
+\r
+ // Initialize the TOI flag.\r
+ for (b2Body* body = m_bodyList; body; body = body->m_next)\r
+ {\r
+ // Kinematic, and static bodies will not be affected by the TOI event.\r
+ // If a body was not in an island then it did not move.\r
+ if ((body->m_flags & b2Body::e_islandFlag) == 0 || body->GetType() == b2_kinematicBody || body->GetType() == b2_staticBody)\r
+ {\r
+ body->m_flags |= b2Body::e_toiFlag;\r
+ }\r
+ else\r
+ {\r
+ body->m_flags &= ~b2Body::e_toiFlag;\r
+ }\r
+ }\r
+\r
+ // Collide non-bullets.\r
+ for (b2Body* body = m_bodyList; body; body = body->m_next)\r
+ {\r
+ if (body->m_flags & b2Body::e_toiFlag)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (body->IsBullet() == true)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ SolveTOI(body);\r
+\r
+ body->m_flags |= b2Body::e_toiFlag;\r
+ }\r
+\r
+ // Collide bullets.\r
+ for (b2Body* body = m_bodyList; body; body = body->m_next)\r
+ {\r
+ if (body->m_flags & b2Body::e_toiFlag)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (body->IsBullet() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ SolveTOI(body);\r
+\r
+ body->m_flags |= b2Body::e_toiFlag;\r
+ }\r
+}\r
+\r
+void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations)\r
+{\r
+ // If new fixtures were added, we need to find the new contacts.\r
+ if (m_flags & e_newFixture)\r
+ {\r
+ m_contactManager.FindNewContacts();\r
+ m_flags &= ~e_newFixture;\r
+ }\r
+\r
+ m_flags |= e_locked;\r
+\r
+ b2TimeStep step;\r
+ step.dt = dt;\r
+ step.velocityIterations = velocityIterations;\r
+ step.positionIterations = positionIterations;\r
+ if (dt > 0.0f)\r
+ {\r
+ step.inv_dt = 1.0f / dt;\r
+ }\r
+ else\r
+ {\r
+ step.inv_dt = 0.0f;\r
+ }\r
+\r
+ step.dtRatio = m_inv_dt0 * dt;\r
+\r
+ step.warmStarting = m_warmStarting;\r
+\r
+ // Update contacts. This is where some contacts are destroyed.\r
+ m_contactManager.Collide();\r
+\r
+ // Integrate velocities, solve velocity constraints, and integrate positions.\r
+ if (step.dt > 0.0f)\r
+ {\r
+ Solve(step);\r
+ }\r
+\r
+ // Handle TOI events.\r
+ if (m_continuousPhysics && step.dt > 0.0f)\r
+ {\r
+ SolveTOI();\r
+ }\r
+\r
+ if (step.dt > 0.0f)\r
+ {\r
+ m_inv_dt0 = step.inv_dt;\r
+ }\r
+\r
+ if (m_flags & e_clearForces)\r
+ {\r
+ ClearForces();\r
+ }\r
+\r
+ m_flags &= ~e_locked;\r
+}\r
+\r
+void b2World::ClearForces()\r
+{\r
+ for (b2Body* body = m_bodyList; body; body = body->GetNext())\r
+ {\r
+ body->m_force.SetZero();\r
+ body->m_torque = 0.0f;\r
+ }\r
+}\r
+\r
+struct b2WorldQueryWrapper\r
+{\r
+ bool QueryCallback(int32 proxyId)\r
+ {\r
+ b2Fixture* fixture = (b2Fixture*)broadPhase->GetUserData(proxyId);\r
+ return callback->ReportFixture(fixture);\r
+ }\r
+\r
+ const b2BroadPhase* broadPhase;\r
+ b2QueryCallback* callback;\r
+};\r
+\r
+void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const\r
+{\r
+ b2WorldQueryWrapper wrapper;\r
+ wrapper.broadPhase = &m_contactManager.m_broadPhase;\r
+ wrapper.callback = callback;\r
+ m_contactManager.m_broadPhase.Query(&wrapper, aabb);\r
+}\r
+\r
+struct b2WorldRayCastWrapper\r
+{\r
+ float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)\r
+ {\r
+ void* userData = broadPhase->GetUserData(proxyId);\r
+ b2Fixture* fixture = (b2Fixture*)userData;\r
+ b2RayCastOutput output;\r
+ bool hit = fixture->RayCast(&output, input);\r
+\r
+ if (hit)\r
+ {\r
+ float32 fraction = output.fraction;\r
+ b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2;\r
+ return callback->ReportFixture(fixture, point, output.normal, fraction);\r
+ }\r
+\r
+ return input.maxFraction;\r
+ }\r
+\r
+ const b2BroadPhase* broadPhase;\r
+ b2RayCastCallback* callback;\r
+};\r
+\r
+void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const\r
+{\r
+ b2WorldRayCastWrapper wrapper;\r
+ wrapper.broadPhase = &m_contactManager.m_broadPhase;\r
+ wrapper.callback = callback;\r
+ b2RayCastInput input;\r
+ input.maxFraction = 1.0f;\r
+ input.p1 = point1;\r
+ input.p2 = point2;\r
+ m_contactManager.m_broadPhase.RayCast(&wrapper, input);\r
+}\r
+\r
+void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color)\r
+{\r
+ switch (fixture->GetType())\r
+ {\r
+ case b2Shape::e_circle:\r
+ {\r
+ b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();\r
+\r
+ b2Vec2 center = b2Mul(xf, circle->m_p);\r
+ float32 radius = circle->m_radius;\r
+ b2Vec2 axis = xf.R.col1;\r
+\r
+ m_debugDraw->DrawSolidCircle(center, radius, axis, color);\r
+ }\r
+ break;\r
+\r
+ case b2Shape::e_polygon:\r
+ {\r
+ b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();\r
+ int32 vertexCount = poly->m_vertexCount;\r
+ b2Assert(vertexCount <= b2_maxPolygonVertices);\r
+ b2Vec2 vertices[b2_maxPolygonVertices];\r
+\r
+ for (int32 i = 0; i < vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(xf, poly->m_vertices[i]);\r
+ }\r
+\r
+ m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color);\r
+ }\r
+ break;\r
+ }\r
+}\r
+\r
+void b2World::DrawJoint(b2Joint* joint)\r
+{\r
+ b2Body* bodyA = joint->GetBodyA();\r
+ b2Body* bodyB = joint->GetBodyB();\r
+ const b2Transform& xf1 = bodyA->GetTransform();\r
+ const b2Transform& xf2 = bodyB->GetTransform();\r
+ b2Vec2 x1 = xf1.position;\r
+ b2Vec2 x2 = xf2.position;\r
+ b2Vec2 p1 = joint->GetAnchorA();\r
+ b2Vec2 p2 = joint->GetAnchorB();\r
+\r
+ b2Color color(0.5f, 0.8f, 0.8f);\r
+\r
+ switch (joint->GetType())\r
+ {\r
+ case e_distanceJoint:\r
+ m_debugDraw->DrawSegment(p1, p2, color);\r
+ break;\r
+\r
+ case e_pulleyJoint:\r
+ {\r
+ b2PulleyJoint* pulley = (b2PulleyJoint*)joint;\r
+ b2Vec2 s1 = pulley->GetGroundAnchorA();\r
+ b2Vec2 s2 = pulley->GetGroundAnchorB();\r
+ m_debugDraw->DrawSegment(s1, p1, color);\r
+ m_debugDraw->DrawSegment(s2, p2, color);\r
+ m_debugDraw->DrawSegment(s1, s2, color);\r
+ }\r
+ break;\r
+\r
+ case e_mouseJoint:\r
+ // don't draw this\r
+ break;\r
+\r
+ default:\r
+ m_debugDraw->DrawSegment(x1, p1, color);\r
+ m_debugDraw->DrawSegment(p1, p2, color);\r
+ m_debugDraw->DrawSegment(x2, p2, color);\r
+ }\r
+}\r
+\r
+void b2World::DrawDebugData()\r
+{\r
+ if (m_debugDraw == NULL)\r
+ {\r
+ return;\r
+ }\r
+\r
+ uint32 flags = m_debugDraw->GetFlags();\r
+\r
+ if (flags & b2DebugDraw::e_shapeBit)\r
+ {\r
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())\r
+ {\r
+ const b2Transform& xf = b->GetTransform();\r
+ for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())\r
+ {\r
+ if (b->IsActive() == false)\r
+ {\r
+ DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f));\r
+ }\r
+ else if (b->GetType() == b2_staticBody)\r
+ {\r
+ DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f));\r
+ }\r
+ else if (b->GetType() == b2_kinematicBody)\r
+ {\r
+ DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f));\r
+ }\r
+ else if (b->IsAwake() == false)\r
+ {\r
+ DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f));\r
+ }\r
+ else\r
+ {\r
+ DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f));\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (flags & b2DebugDraw::e_jointBit)\r
+ {\r
+ for (b2Joint* j = m_jointList; j; j = j->GetNext())\r
+ {\r
+ DrawJoint(j);\r
+ }\r
+ }\r
+\r
+ if (flags & b2DebugDraw::e_pairBit)\r
+ {\r
+ b2Color color(0.3f, 0.9f, 0.9f);\r
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext())\r
+ {\r
+ b2Fixture* fixtureA = c->GetFixtureA();\r
+ b2Fixture* fixtureB = c->GetFixtureB();\r
+\r
+ b2Vec2 cA = fixtureA->GetAABB().GetCenter();\r
+ b2Vec2 cB = fixtureB->GetAABB().GetCenter();\r
+\r
+ m_debugDraw->DrawSegment(cA, cB, color);\r
+ }\r
+ }\r
+\r
+ if (flags & b2DebugDraw::e_aabbBit)\r
+ {\r
+ b2Color color(0.9f, 0.3f, 0.9f);\r
+ b2BroadPhase* bp = &m_contactManager.m_broadPhase;\r
+\r
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())\r
+ {\r
+ if (b->IsActive() == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())\r
+ {\r
+ b2AABB aabb = bp->GetFatAABB(f->m_proxyId);\r
+ b2Vec2 vs[4];\r
+ vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y);\r
+ vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y);\r
+ vs[2].Set(aabb.upperBound.x, aabb.upperBound.y);\r
+ vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y);\r
+\r
+ m_debugDraw->DrawPolygon(vs, 4, color);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (flags & b2DebugDraw::e_centerOfMassBit)\r
+ {\r
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())\r
+ {\r
+ b2Transform xf = b->GetTransform();\r
+ xf.position = b->GetWorldCenter();\r
+ m_debugDraw->DrawTransform(xf);\r
+ }\r
+ }\r
+}\r
+\r
+int32 b2World::GetProxyCount() const\r
+{\r
+ return m_contactManager.m_broadPhase.GetProxyCount();\r
+}\r
--- /dev/null
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_WORLD_H
+#define B2_WORLD_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Common/b2StackAllocator.h>
+#include <Box2D/Dynamics/b2ContactManager.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+
+struct b2AABB;
+struct b2BodyDef;
+struct b2JointDef;
+struct b2TimeStep;
+class b2Body;
+class b2Fixture;
+class b2Joint;
+
+/// The world class manages all physics entities, dynamic simulation,
+/// and asynchronous queries. The world also contains efficient memory
+/// management facilities.
+class b2World
+{
+public:
+ /// Construct a world object.
+ /// @param gravity the world gravity vector.
+ /// @param doSleep improve performance by not simulating inactive bodies.
+ b2World(const b2Vec2& gravity, bool doSleep);
+
+ /// Destruct the world. All physics entities are destroyed and all heap memory is released.
+ ~b2World();
+
+ /// Register a destruction listener. The listener is owned by you and must
+ /// remain in scope.
+ void SetDestructionListener(b2DestructionListener* listener);
+
+ /// Register a contact filter to provide specific control over collision.
+ /// Otherwise the default filter is used (b2_defaultFilter). The listener is
+ /// owned by you and must remain in scope.
+ void SetContactFilter(b2ContactFilter* filter);
+
+ /// Register a contact event listener. The listener is owned by you and must
+ /// remain in scope.
+ void SetContactListener(b2ContactListener* listener);
+
+ /// Register a routine for debug drawing. The debug draw functions are called
+ /// inside with b2World::DrawDebugData method. The debug draw object is owned
+ /// by you and must remain in scope.
+ void SetDebugDraw(b2DebugDraw* debugDraw);
+
+ /// Create a rigid body given a definition. No reference to the definition
+ /// is retained.
+ /// @warning This function is locked during callbacks.
+ b2Body* CreateBody(const b2BodyDef* def);
+
+ /// Destroy a rigid body given a definition. No reference to the definition
+ /// is retained. This function is locked during callbacks.
+ /// @warning This automatically deletes all associated shapes and joints.
+ /// @warning This function is locked during callbacks.
+ void DestroyBody(b2Body* body);
+
+ /// Create a joint to constrain bodies together. No reference to the definition
+ /// is retained. This may cause the connected bodies to cease colliding.
+ /// @warning This function is locked during callbacks.
+ b2Joint* CreateJoint(const b2JointDef* def);
+
+ /// Destroy a joint. This may cause the connected bodies to begin colliding.
+ /// @warning This function is locked during callbacks.
+ void DestroyJoint(b2Joint* joint);
+
+ /// Take a time step. This performs collision detection, integration,
+ /// and constraint solution.
+ /// @param timeStep the amount of time to simulate, this should not vary.
+ /// @param velocityIterations for the velocity constraint solver.
+ /// @param positionIterations for the position constraint solver.
+ void Step( float32 timeStep,
+ int32 velocityIterations,
+ int32 positionIterations);
+
+ /// Call this after you are done with time steps to clear the forces. You normally
+ /// call this after each call to Step, unless you are performing sub-steps. By default,
+ /// forces will be automatically cleared, so you don't need to call this function.
+ /// @see SetAutoClearForces
+ void ClearForces();
+
+ /// Call this to draw shapes and other debug draw data.
+ void DrawDebugData();
+
+ /// Query the world for all fixtures that potentially overlap the
+ /// provided AABB.
+ /// @param callback a user implemented callback class.
+ /// @param aabb the query box.
+ void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const;
+
+ /// Ray-cast the world for all fixtures in the path of the ray. Your callback
+ /// controls whether you get the closest point, any point, or n-points.
+ /// The ray-cast ignores shapes that contain the starting point.
+ /// @param callback a user implemented callback class.
+ /// @param point1 the ray starting point
+ /// @param point2 the ray ending point
+ void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const;
+
+ /// Get the world body list. With the returned body, use b2Body::GetNext to get
+ /// the next body in the world list. A NULL body indicates the end of the list.
+ /// @return the head of the world body list.
+ b2Body* GetBodyList();
+
+ /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get
+ /// the next joint in the world list. A NULL joint indicates the end of the list.
+ /// @return the head of the world joint list.
+ b2Joint* GetJointList();
+
+ /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get
+ /// the next contact in the world list. A NULL contact indicates the end of the list.
+ /// @return the head of the world contact list.
+ /// @warning contacts are
+ b2Contact* GetContactList();
+
+ /// Enable/disable warm starting. For testing.
+ void SetWarmStarting(bool flag) { m_warmStarting = flag; }
+
+ /// Enable/disable continuous physics. For testing.
+ void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; }
+
+ /// Get the number of broad-phase proxies.
+ int32 GetProxyCount() const;
+
+ /// Get the number of bodies.
+ int32 GetBodyCount() const;
+
+ /// Get the number of joints.
+ int32 GetJointCount() const;
+
+ /// Get the number of contacts (each may have 0 or more contact points).
+ int32 GetContactCount() const;
+
+ /// Change the global gravity vector.
+ void SetGravity(const b2Vec2& gravity);
+
+ /// Get the global gravity vector.
+ b2Vec2 GetGravity() const;
+
+ /// Is the world locked (in the middle of a time step).
+ bool IsLocked() const;
+
+ /// Set flag to control automatic clearing of forces after each time step.
+ void SetAutoClearForces(bool flag);
+
+ /// Get the flag that controls automatic clearing of forces after each time step.
+ bool GetAutoClearForces() const;
+
+private:
+
+ // m_flags
+ enum
+ {
+ e_newFixture = 0x0001,
+ e_locked = 0x0002,
+ e_clearForces = 0x0004,
+ };
+
+ friend class b2Body;
+ friend class b2ContactManager;
+ friend class b2Controller;
+
+ void Solve(const b2TimeStep& step);
+ void SolveTOI();
+ void SolveTOI(b2Body* body);
+
+ void DrawJoint(b2Joint* joint);
+ void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color);
+
+ b2BlockAllocator m_blockAllocator;
+ b2StackAllocator m_stackAllocator;
+
+ int32 m_flags;
+
+ b2ContactManager m_contactManager;
+
+ b2Body* m_bodyList;
+ b2Joint* m_jointList;
+
+ int32 m_bodyCount;
+ int32 m_jointCount;
+
+ b2Vec2 m_gravity;
+ bool m_allowSleep;
+
+ b2Body* m_groundBody;
+
+ b2DestructionListener* m_destructionListener;
+ b2DebugDraw* m_debugDraw;
+
+ // This is used to compute the time step ratio to
+ // support a variable time step.
+ float32 m_inv_dt0;
+
+ // This is for debugging the solver.
+ bool m_warmStarting;
+
+ // This is for debugging the solver.
+ bool m_continuousPhysics;
+};
+
+inline b2Body* b2World::GetBodyList()
+{
+ return m_bodyList;
+}
+
+inline b2Joint* b2World::GetJointList()
+{
+ return m_jointList;
+}
+
+inline b2Contact* b2World::GetContactList()
+{
+ return m_contactManager.m_contactList;
+}
+
+inline int32 b2World::GetBodyCount() const
+{
+ return m_bodyCount;
+}
+
+inline int32 b2World::GetJointCount() const
+{
+ return m_jointCount;
+}
+
+inline int32 b2World::GetContactCount() const
+{
+ return m_contactManager.m_contactCount;
+}
+
+inline void b2World::SetGravity(const b2Vec2& gravity)
+{
+ m_gravity = gravity;
+}
+
+inline b2Vec2 b2World::GetGravity() const
+{
+ return m_gravity;
+}
+
+inline bool b2World::IsLocked() const
+{
+ return (m_flags & e_locked) == e_locked;
+}
+
+inline void b2World::SetAutoClearForces(bool flag)
+{
+ if (flag)
+ {
+ m_flags |= e_clearForces;
+ }
+ else
+ {
+ m_flags &= ~e_clearForces;
+ }
+}
+
+/// Get the flag that controls automatic clearing of forces after each time step.
+inline bool b2World::GetAutoClearForces() const
+{
+ return (m_flags & e_clearForces) == e_clearForces;
+}
+
+#endif
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#include <Box2D/Dynamics/b2WorldCallbacks.h>\r
+#include <Box2D/Dynamics/b2Fixture.h>\r
+\r
+// Return true if contact calculations should be performed between these two shapes.\r
+// If you implement your own collision filter you may want to build from this implementation.\r
+bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)\r
+{\r
+ const b2Filter& filterA = fixtureA->GetFilterData();\r
+ const b2Filter& filterB = fixtureB->GetFilterData();\r
+\r
+ if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0)\r
+ {\r
+ return filterA.groupIndex > 0;\r
+ }\r
+\r
+ bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;\r
+ return collide;\r
+}\r
+\r
+b2DebugDraw::b2DebugDraw()\r
+{\r
+ m_drawFlags = 0;\r
+}\r
+\r
+void b2DebugDraw::SetFlags(uint32 flags)\r
+{\r
+ m_drawFlags = flags;\r
+}\r
+\r
+uint32 b2DebugDraw::GetFlags() const\r
+{\r
+ return m_drawFlags;\r
+}\r
+\r
+void b2DebugDraw::AppendFlags(uint32 flags)\r
+{\r
+ m_drawFlags |= flags;\r
+}\r
+\r
+void b2DebugDraw::ClearFlags(uint32 flags)\r
+{\r
+ m_drawFlags &= ~flags;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef B2_WORLD_CALLBACKS_H\r
+#define B2_WORLD_CALLBACKS_H\r
+\r
+#include <Box2D/Common/b2Settings.h>\r
+\r
+struct b2Vec2;\r
+struct b2Transform;\r
+class b2Fixture;\r
+class b2Body;\r
+class b2Joint;\r
+class b2Contact;\r
+struct b2ContactPoint;\r
+struct b2ContactResult;\r
+struct b2Manifold;\r
+\r
+/// Joints and fixtures are destroyed when their associated\r
+/// body is destroyed. Implement this listener so that you\r
+/// may nullify references to these joints and shapes.\r
+class b2DestructionListener\r
+{\r
+public:\r
+ virtual ~b2DestructionListener() {}\r
+\r
+ /// Called when any joint is about to be destroyed due\r
+ /// to the destruction of one of its attached bodies.\r
+ virtual void SayGoodbye(b2Joint* joint) = 0;\r
+\r
+ /// Called when any fixture is about to be destroyed due\r
+ /// to the destruction of its parent body.\r
+ virtual void SayGoodbye(b2Fixture* fixture) = 0;\r
+};\r
+\r
+/// Implement this class to provide collision filtering. In other words, you can implement\r
+/// this class if you want finer control over contact creation.\r
+class b2ContactFilter\r
+{\r
+public:\r
+ virtual ~b2ContactFilter() {}\r
+\r
+ /// Return true if contact calculations should be performed between these two shapes.\r
+ /// @warning for performance reasons this is only called when the AABBs begin to overlap.\r
+ virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB);\r
+};\r
+\r
+/// Contact impulses for reporting. Impulses are used instead of forces because\r
+/// sub-step forces may approach infinity for rigid body collisions. These\r
+/// match up one-to-one with the contact points in b2Manifold.\r
+struct b2ContactImpulse\r
+{\r
+ float32 normalImpulses[b2_maxManifoldPoints];\r
+ float32 tangentImpulses[b2_maxManifoldPoints];\r
+};\r
+\r
+/// Implement this class to get contact information. You can use these results for\r
+/// things like sounds and game logic. You can also get contact results by\r
+/// traversing the contact lists after the time step. However, you might miss\r
+/// some contacts because continuous physics leads to sub-stepping.\r
+/// Additionally you may receive multiple callbacks for the same contact in a\r
+/// single time step.\r
+/// You should strive to make your callbacks efficient because there may be\r
+/// many callbacks per time step.\r
+/// @warning You cannot create/destroy Box2D entities inside these callbacks.\r
+class b2ContactListener\r
+{\r
+public:\r
+ virtual ~b2ContactListener() {}\r
+\r
+ /// Called when two fixtures begin to touch.\r
+ virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }\r
+\r
+ /// Called when two fixtures cease to touch.\r
+ virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }\r
+\r
+ /// This is called after a contact is updated. This allows you to inspect a\r
+ /// contact before it goes to the solver. If you are careful, you can modify the\r
+ /// contact manifold (e.g. disable contact).\r
+ /// A copy of the old manifold is provided so that you can detect changes.\r
+ /// Note: this is called only for awake bodies.\r
+ /// Note: this is called even when the number of contact points is zero.\r
+ /// Note: this is not called for sensors.\r
+ /// Note: if you set the number of contact points to zero, you will not\r
+ /// get an EndContact callback. However, you may get a BeginContact callback\r
+ /// the next step.\r
+ virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)\r
+ {\r
+ B2_NOT_USED(contact);\r
+ B2_NOT_USED(oldManifold);\r
+ }\r
+\r
+ /// This lets you inspect a contact after the solver is finished. This is useful\r
+ /// for inspecting impulses.\r
+ /// Note: the contact manifold does not include time of impact impulses, which can be\r
+ /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly\r
+ /// in a separate data structure.\r
+ /// Note: this is only called for contacts that are touching, solid, and awake.\r
+ virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)\r
+ {\r
+ B2_NOT_USED(contact);\r
+ B2_NOT_USED(impulse);\r
+ }\r
+};\r
+\r
+/// Callback class for AABB queries.\r
+/// See b2World::Query\r
+class b2QueryCallback\r
+{\r
+public:\r
+ virtual ~b2QueryCallback() {}\r
+\r
+ /// Called for each fixture found in the query AABB.\r
+ /// @return false to terminate the query.\r
+ virtual bool ReportFixture(b2Fixture* fixture) = 0;\r
+};\r
+\r
+/// Callback class for ray casts.\r
+/// See b2World::RayCast\r
+class b2RayCastCallback\r
+{\r
+public:\r
+ virtual ~b2RayCastCallback() {}\r
+\r
+ /// Called for each fixture found in the query. You control how the ray cast\r
+ /// proceeds by returning a float:\r
+ /// return -1: ignore this fixture and continue\r
+ /// return 0: terminate the ray cast\r
+ /// return fraction: clip the ray to this point\r
+ /// return 1: don't clip the ray and continue\r
+ /// @param fixture the fixture hit by the ray\r
+ /// @param point the point of initial intersection\r
+ /// @param normal the normal vector at the point of intersection\r
+ /// @return -1 to filter, 0 to terminate, fraction to clip the ray for\r
+ /// closest hit, 1 to continue\r
+ virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,\r
+ const b2Vec2& normal, float32 fraction) = 0;\r
+};\r
+\r
+/// Color for debug drawing. Each value has the range [0,1].\r
+struct b2Color\r
+{\r
+ b2Color() {}\r
+ b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}\r
+ void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }\r
+ float32 r, g, b;\r
+};\r
+\r
+/// Implement and register this class with a b2World to provide debug drawing of physics\r
+/// entities in your game.\r
+class b2DebugDraw\r
+{\r
+public:\r
+ b2DebugDraw();\r
+\r
+ virtual ~b2DebugDraw() {}\r
+\r
+ enum\r
+ {\r
+ e_shapeBit = 0x0001, ///< draw shapes\r
+ e_jointBit = 0x0002, ///< draw joint connections\r
+ e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes\r
+ e_pairBit = 0x0008, ///< draw broad-phase pairs\r
+ e_centerOfMassBit = 0x0010, ///< draw center of mass frame\r
+ };\r
+\r
+ /// Set the drawing flags.\r
+ void SetFlags(uint32 flags);\r
+\r
+ /// Get the drawing flags.\r
+ uint32 GetFlags() const;\r
+ \r
+ /// Append flags to the current flags.\r
+ void AppendFlags(uint32 flags);\r
+\r
+ /// Clear flags from the current flags.\r
+ void ClearFlags(uint32 flags);\r
+\r
+ /// Draw a closed polygon provided in CCW order.\r
+ virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;\r
+\r
+ /// Draw a solid closed polygon provided in CCW order.\r
+ virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;\r
+\r
+ /// Draw a circle.\r
+ virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;\r
+ \r
+ /// Draw a solid circle.\r
+ virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;\r
+ \r
+ /// Draw a line segment.\r
+ virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;\r
+\r
+ /// Draw a transform. Choose your own length scale.\r
+ /// @param xf a transform.\r
+ virtual void DrawTransform(const b2Transform& xf) = 0;\r
+\r
+protected:\r
+ uint32 m_drawFlags;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef APPLY_FORCE_H\r
+#define APPLY_FORCE_H\r
+\r
+class ApplyForce : public Test\r
+{\r
+public:\r
+ ApplyForce()\r
+ {\r
+ m_world->SetGravity(b2Vec2(0.0f, 0.0f));\r
+\r
+ const float32 k_restitution = 0.4f;\r
+\r
+ b2Body* ground;\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(0.0f, 20.0f);\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+\r
+ b2FixtureDef sd;\r
+ sd.shape = &shape;\r
+ sd.density = 0.0f;\r
+ sd.restitution = k_restitution;\r
+\r
+ // Left vertical\r
+ shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(-20.0f, 20.0f));\r
+ ground->CreateFixture(&sd);\r
+\r
+ // Right vertical\r
+ shape.Set(b2Vec2(20.0f, -20.0f), b2Vec2(20.0f, 20.0f));\r
+ ground->CreateFixture(&sd);\r
+\r
+ // Top horizontal\r
+ shape.Set(b2Vec2(-20.0f, 20.0f), b2Vec2(20.0f, 20.0f));\r
+ ground->CreateFixture(&sd);\r
+\r
+ // Bottom horizontal\r
+ shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(20.0f, -20.0f));\r
+ ground->CreateFixture(&sd);\r
+ }\r
+\r
+ {\r
+ b2Transform xf1;\r
+ xf1.R.Set(0.3524f * b2_pi);\r
+ xf1.position = b2Mul(xf1.R, b2Vec2(1.0f, 0.0f));\r
+\r
+ b2Vec2 vertices[3];\r
+ vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));\r
+ vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));\r
+ vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));\r
+ \r
+ b2PolygonShape poly1;\r
+ poly1.Set(vertices, 3);\r
+\r
+ b2FixtureDef sd1;\r
+ sd1.shape = &poly1;\r
+ sd1.density = 4.0f;\r
+\r
+ b2Transform xf2;\r
+ xf2.R.Set(-0.3524f * b2_pi);\r
+ xf2.position = b2Mul(xf2.R, b2Vec2(-1.0f, 0.0f));\r
+\r
+ vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));\r
+ vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));\r
+ vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));\r
+ \r
+ b2PolygonShape poly2;\r
+ poly2.Set(vertices, 3);\r
+\r
+ b2FixtureDef sd2;\r
+ sd2.shape = &poly2;\r
+ sd2.density = 2.0f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.angularDamping = 5.0f;\r
+ bd.linearDamping = 0.1f;\r
+\r
+ bd.position.Set(0.0f, 2.0);\r
+ bd.angle = b2_pi;\r
+ bd.allowSleep = false;\r
+ m_body = m_world->CreateBody(&bd);\r
+ m_body->CreateFixture(&sd1);\r
+ m_body->CreateFixture(&sd2);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.5f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.3f;\r
+\r
+ for (int i = 0; i < 10; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ bd.position.Set(0.0f, 5.0f + 1.54f * i);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ body->CreateFixture(&fd);\r
+\r
+ float32 gravity = 10.0f;\r
+ float32 I = body->GetInertia();\r
+ float32 mass = body->GetMass();\r
+\r
+ // For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m)\r
+ float32 radius = b2Sqrt(2.0f * I / mass);\r
+\r
+ b2FrictionJointDef jd;\r
+ jd.localAnchorA.SetZero();\r
+ jd.localAnchorB.SetZero();\r
+ jd.bodyA = ground;\r
+ jd.bodyB = body;\r
+ jd.collideConnected = true;\r
+ jd.maxForce = mass * gravity;\r
+ jd.maxTorque = mass * radius * gravity;\r
+\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'w':\r
+ {\r
+ b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -200.0f));\r
+ b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 2.0f));\r
+ m_body->ApplyForce(f, p);\r
+ }\r
+ break;\r
+\r
+ case 'a':\r
+ {\r
+ m_body->ApplyTorque(50.0f);\r
+ }\r
+ break;\r
+\r
+ case 'd':\r
+ {\r
+ m_body->ApplyTorque(-50.0f);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new ApplyForce;\r
+ }\r
+\r
+ b2Body* m_body;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef BODY_TYPES_H\r
+#define BODY_TYPES_H\r
+\r
+class BodyTypes : public Test\r
+{\r
+public:\r
+ BodyTypes()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+\r
+ ground->CreateFixture(&fd);\r
+ }\r
+\r
+ // Define attachment\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 3.0f);\r
+ m_attachment = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 2.0f);\r
+ m_attachment->CreateFixture(&shape, 2.0f);\r
+ }\r
+\r
+ // Define platform\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-4.0f, 5.0f);\r
+ m_platform = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 4.0f, b2Vec2(4.0f, 0.0f), 0.5f * b2_pi);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.friction = 0.6f;\r
+ fd.density = 2.0f;\r
+ m_platform->CreateFixture(&fd);\r
+\r
+ b2RevoluteJointDef rjd;\r
+ rjd.Initialize(m_attachment, m_platform, b2Vec2(0.0f, 5.0f));\r
+ rjd.maxMotorTorque = 50.0f;\r
+ rjd.enableMotor = true;\r
+ m_world->CreateJoint(&rjd);\r
+\r
+ b2PrismaticJointDef pjd;\r
+ pjd.Initialize(ground, m_platform, b2Vec2(0.0f, 5.0f), b2Vec2(1.0f, 0.0f));\r
+\r
+ pjd.maxMotorForce = 1000.0f;\r
+ pjd.enableMotor = true;\r
+ pjd.lowerTranslation = -10.0f;\r
+ pjd.upperTranslation = 10.0f;\r
+ pjd.enableLimit = true;\r
+\r
+ (b2PrismaticJoint*)m_world->CreateJoint(&pjd);\r
+\r
+ m_speed = 3.0f;\r
+ }\r
+\r
+ // Create a payload\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 8.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.75f, 0.75f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.friction = 0.6f;\r
+ fd.density = 2.0f;\r
+\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'd':\r
+ m_platform->SetType(b2_dynamicBody);\r
+ break;\r
+\r
+ case 's':\r
+ m_platform->SetType(b2_staticBody);\r
+ break;\r
+\r
+ case 'k':\r
+ m_platform->SetType(b2_kinematicBody);\r
+ m_platform->SetLinearVelocity(b2Vec2(-m_speed, 0.0f));\r
+ m_platform->SetAngularVelocity(0.0f);\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ // Drive the kinematic body.\r
+ if (m_platform->GetType() == b2_kinematicBody)\r
+ {\r
+ b2Vec2 p = m_platform->GetTransform().position;\r
+ b2Vec2 v = m_platform->GetLinearVelocity();\r
+\r
+ if ((p.x < -10.0f && v.x < 0.0f) ||\r
+ (p.x > 10.0f && v.x > 0.0f))\r
+ {\r
+ v.x = -v.x;\r
+ m_platform->SetLinearVelocity(v);\r
+ }\r
+ }\r
+\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (d) dynamic, (s) static, (k) kinematic");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new BodyTypes;\r
+ }\r
+\r
+ b2Body* m_attachment;\r
+ b2Body* m_platform;\r
+ float32 m_speed;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef BREAKABLE_TEST_H\r
+#define BREAKABLE_TEST_H\r
+\r
+// This is used to test sensor shapes.\r
+class Breakable : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_count = 7\r
+ };\r
+\r
+ Breakable()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Breakable dynamic body\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 40.0f);\r
+ bd.angle = 0.25f * b2_pi;\r
+ m_body1 = m_world->CreateBody(&bd);\r
+\r
+ m_shape1.SetAsBox(0.5f, 0.5f, b2Vec2(-0.5f, 0.0f), 0.0f);\r
+ m_piece1 = m_body1->CreateFixture(&m_shape1, 1.0f);\r
+\r
+ m_shape2.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, 0.0f), 0.0f);\r
+ m_piece2 = m_body1->CreateFixture(&m_shape2, 1.0f);\r
+ }\r
+\r
+ m_break = false;\r
+ m_broke = false;\r
+ }\r
+\r
+ void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)\r
+ {\r
+ if (m_broke)\r
+ {\r
+ // The body already broke.\r
+ return;\r
+ }\r
+\r
+ // Should the body break?\r
+ int32 count = contact->GetManifold()->pointCount;\r
+\r
+ float32 maxImpulse = 0.0f;\r
+ for (int32 i = 0; i < count; ++i)\r
+ {\r
+ maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);\r
+ }\r
+\r
+ if (maxImpulse > 40.0f)\r
+ {\r
+ // Flag the body for breaking.\r
+ m_break = true;\r
+ }\r
+ }\r
+\r
+ void Break()\r
+ {\r
+ // Create two bodies from one.\r
+ b2Body* body1 = m_piece1->GetBody();\r
+ b2Vec2 center = body1->GetWorldCenter();\r
+\r
+ body1->DestroyFixture(m_piece2);\r
+ m_piece2 = NULL;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position = body1->GetPosition();\r
+ bd.angle = body1->GetAngle();\r
+\r
+ b2Body* body2 = m_world->CreateBody(&bd);\r
+ m_piece2 = body2->CreateFixture(&m_shape2, 1.0f);\r
+\r
+ // Compute consistent velocities for new bodies based on\r
+ // cached velocity.\r
+ b2Vec2 center1 = body1->GetWorldCenter();\r
+ b2Vec2 center2 = body2->GetWorldCenter();\r
+ \r
+ b2Vec2 velocity1 = m_velocity + b2Cross(m_angularVelocity, center1 - center);\r
+ b2Vec2 velocity2 = m_velocity + b2Cross(m_angularVelocity, center2 - center);\r
+\r
+ body1->SetAngularVelocity(m_angularVelocity);\r
+ body1->SetLinearVelocity(velocity1);\r
+\r
+ body2->SetAngularVelocity(m_angularVelocity);\r
+ body2->SetLinearVelocity(velocity2);\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ if (m_break)\r
+ {\r
+ Break();\r
+ m_broke = true;\r
+ m_break = false;\r
+ }\r
+\r
+ // Cache velocities to improve movement on breakage.\r
+ if (m_broke == false)\r
+ {\r
+ m_velocity = m_body1->GetLinearVelocity();\r
+ m_angularVelocity = m_body1->GetAngularVelocity();\r
+ }\r
+\r
+ Test::Step(settings);\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Breakable;\r
+ }\r
+\r
+ b2Body* m_body1;\r
+ b2Vec2 m_velocity;\r
+ float32 m_angularVelocity;\r
+ b2PolygonShape m_shape1;\r
+ b2PolygonShape m_shape2;\r
+ b2Fixture* m_piece1;\r
+ b2Fixture* m_piece2;\r
+\r
+ bool m_broke;\r
+ bool m_break;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef BRIDGE_H\r
+#define BRIDGE_H\r
+\r
+class Bridge : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_count = 30\r
+ };\r
+\r
+ Bridge()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ fd.friction = 0.2f;\r
+\r
+ b2RevoluteJointDef jd;\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-14.5f + 1.0f * i, 5.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ if (i == (e_count >> 1))\r
+ {\r
+ m_middle = body;\r
+ }\r
+ prevBody = body;\r
+ }\r
+\r
+ b2Vec2 anchor(-15.0f + 1.0f * e_count, 5.0f);\r
+ jd.Initialize(prevBody, ground, anchor);\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ for (int32 i = 0; i < 2; ++i)\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.5f, 0.0f);\r
+ vertices[1].Set(0.5f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+\r
+ b2PolygonShape shape;\r
+ shape.Set(vertices, 3);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-8.0f + 8.0f * i, 12.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+ }\r
+\r
+ for (int32 i = 0; i < 3; ++i)\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.5f;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-6.0f + 6.0f * i, 10.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Bridge;\r
+ }\r
+\r
+ b2Body* m_middle;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef BULLET_TEST_H\r
+#define BULLET_TEST_H\r
+\r
+class BulletTest : public Test\r
+{\r
+public:\r
+\r
+ BulletTest()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(0.0f, 0.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape edge;\r
+\r
+ edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));\r
+ body->CreateFixture(&edge, 0.0f);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);\r
+ body->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 4.0f);\r
+\r
+ b2PolygonShape box;\r
+ box.SetAsBox(2.0f, 0.1f);\r
+\r
+ m_body = m_world->CreateBody(&bd);\r
+ m_body->CreateFixture(&box, 1.0f);\r
+\r
+ box.SetAsBox(0.25f, 0.25f);\r
+\r
+ //m_x = RandomFloat(-1.0f, 1.0f);\r
+ m_x = 0.20352793f;\r
+ bd.position.Set(m_x, 10.0f);\r
+ bd.bullet = true;\r
+\r
+ m_bullet = m_world->CreateBody(&bd);\r
+ m_bullet->CreateFixture(&box, 100.0f);\r
+\r
+ m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));\r
+ }\r
+ }\r
+\r
+ void Launch()\r
+ {\r
+ m_body->SetTransform(b2Vec2(0.0f, 4.0f), 0.0f);\r
+ m_body->SetLinearVelocity(b2Vec2_zero);\r
+ m_body->SetAngularVelocity(0.0f);\r
+\r
+ m_x = RandomFloat(-1.0f, 1.0f);\r
+ m_bullet->SetTransform(b2Vec2(m_x, 10.0f), 0.0f);\r
+ m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));\r
+ m_bullet->SetAngularVelocity(0.0f);\r
+\r
+ extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;\r
+ extern int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;\r
+ extern int32 b2_toiRootIters, b2_toiMaxRootIters;\r
+\r
+ b2_gjkCalls = 0;\r
+ b2_gjkIters = 0;\r
+ b2_gjkMaxIters = 0;\r
+\r
+ b2_toiCalls = 0;\r
+ b2_toiIters = 0;\r
+ b2_toiMaxIters = 0;\r
+ b2_toiRootIters = 0;\r
+ b2_toiMaxRootIters = 0;\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;\r
+ extern int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;\r
+ extern int32 b2_toiRootIters, b2_toiMaxRootIters;\r
+\r
+ if (b2_gjkCalls > 0)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",\r
+ b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ if (b2_toiCalls > 0)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",\r
+ b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters);\r
+ m_textLine += 15;\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",\r
+ b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ if (m_stepCount % 60 == 0)\r
+ {\r
+ Launch();\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new BulletTest;\r
+ }\r
+\r
+ b2Body* m_body;\r
+ b2Body* m_bullet;\r
+ float32 m_x;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef CANTILEVER_H\r
+#define CANTILEVER_H\r
+\r
+class Cantilever : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_count = 8\r
+ };\r
+\r
+ Cantilever()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+\r
+ b2WeldJointDef jd;\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-14.5f + 1.0f * i, 5.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ prevBody = body;\r
+ }\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+\r
+ b2WeldJointDef jd;\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-14.5f + 1.0f * i, 15.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ b2Vec2 anchor(-15.0f + 1.0f * i, 15.0f);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ prevBody = body;\r
+ }\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+\r
+ b2WeldJointDef jd;\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-4.5f + 1.0f * i, 5.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ if (i > 0)\r
+ {\r
+ b2Vec2 anchor(-5.0f + 1.0f * i, 5.0f);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ prevBody = body;\r
+ }\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+\r
+ b2WeldJointDef jd;\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(5.5f + 1.0f * i, 10.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ if (i > 0)\r
+ {\r
+ b2Vec2 anchor(5.0f + 1.0f * i, 10.0f);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ prevBody = body;\r
+ }\r
+ }\r
+\r
+ for (int32 i = 0; i < 2; ++i)\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.5f, 0.0f);\r
+ vertices[1].Set(0.5f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+\r
+ b2PolygonShape shape;\r
+ shape.Set(vertices, 3);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-8.0f + 8.0f * i, 12.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+ }\r
+\r
+ for (int32 i = 0; i < 2; ++i)\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.5f;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-6.0f + 6.0f * i, 10.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Cantilever;\r
+ }\r
+\r
+ b2Body* m_middle;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef CAR_H\r
+#define CAR_H\r
+\r
+// This is a fun demo that shows off the wheel joint\r
+class Car : public Test\r
+{\r
+public:\r
+ Car()\r
+ { \r
+ m_hz = 4.0f;\r
+ m_zeta = 0.7f;\r
+ m_speed = 50.0f;\r
+\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 0.0f;\r
+ fd.friction = 0.6f;\r
+\r
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));\r
+ ground->CreateFixture(&fd);\r
+\r
+ float32 hs[10] = {0.25f, 1.0f, 4.0f, 0.0f, 0.0f, -1.0f, -2.0f, -2.0f, -1.25f, 0.0f};\r
+\r
+ float32 x = 20.0f, y1 = 0.0f, dx = 5.0f;\r
+\r
+ for (int32 i = 0; i < 10; ++i)\r
+ {\r
+ float32 y2 = hs[i];\r
+ shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2));\r
+ ground->CreateFixture(&fd);\r
+ y1 = y2;\r
+ x += dx;\r
+ }\r
+\r
+ for (int32 i = 0; i < 10; ++i)\r
+ {\r
+ float32 y2 = hs[i];\r
+ shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2));\r
+ ground->CreateFixture(&fd);\r
+ y1 = y2;\r
+ x += dx;\r
+ }\r
+\r
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));\r
+ ground->CreateFixture(&fd);\r
+\r
+ x += 80.0f;\r
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));\r
+ ground->CreateFixture(&fd);\r
+\r
+ x += 40.0f;\r
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 10.0f, 5.0f));\r
+ ground->CreateFixture(&fd);\r
+\r
+ x += 20.0f;\r
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));\r
+ ground->CreateFixture(&fd);\r
+\r
+ x += 40.0f;\r
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x, 20.0f));\r
+ ground->CreateFixture(&fd);\r
+ }\r
+\r
+ // Teeter\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(140.0f, 1.0f);\r
+ bd.type = b2_dynamicBody;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape box;\r
+ box.SetAsBox(10.0f, 0.25f);\r
+ body->CreateFixture(&box, 1.0f);\r
+\r
+ b2RevoluteJointDef jd;\r
+ jd.Initialize(ground, body, body->GetPosition());\r
+ jd.lowerAngle = -8.0f * b2_pi / 180.0f;\r
+ jd.upperAngle = 8.0f * b2_pi / 180.0f;\r
+ jd.enableLimit = true;\r
+ m_world->CreateJoint(&jd);\r
+\r
+ body->ApplyAngularImpulse(100.0f);\r
+ }\r
+\r
+ // Bridge\r
+ {\r
+ int32 N = 20;\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(1.0f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.6f;\r
+\r
+ b2RevoluteJointDef jd;\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < N; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(161.0f + 2.0f * i, -0.125f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ b2Vec2 anchor(160.0f + 2.0f * i, -0.125f);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ prevBody = body;\r
+ }\r
+\r
+ b2Vec2 anchor(160.0f + 2.0f * N, -0.125f);\r
+ jd.Initialize(prevBody, ground, anchor);\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ // Boxes\r
+ {\r
+ b2PolygonShape box;\r
+ box.SetAsBox(0.5f, 0.5f);\r
+\r
+ b2Body* body = NULL;\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ bd.position.Set(230.0f, 0.5f);\r
+ body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&box, 0.5f);\r
+\r
+ bd.position.Set(230.0f, 1.5f);\r
+ body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&box, 0.5f);\r
+\r
+ bd.position.Set(230.0f, 2.5f);\r
+ body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&box, 0.5f);\r
+\r
+ bd.position.Set(230.0f, 3.5f);\r
+ body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&box, 0.5f);\r
+\r
+ bd.position.Set(230.0f, 4.5f);\r
+ body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&box, 0.5f);\r
+ }\r
+\r
+ // Car\r
+ {\r
+ b2PolygonShape chassis;\r
+ b2Vec2 vertices[8];\r
+ vertices[0].Set(-1.5f, -0.5f);\r
+ vertices[1].Set(1.5f, -0.5f);\r
+ vertices[2].Set(1.5f, 0.0f);\r
+ vertices[3].Set(0.0f, 0.9f);\r
+ vertices[4].Set(-1.15f, 0.9f);\r
+ vertices[5].Set(-1.5f, 0.2f);\r
+ chassis.Set(vertices, 6);\r
+\r
+ b2CircleShape circle;\r
+ circle.m_radius = 0.4f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 1.0f);\r
+ m_car = m_world->CreateBody(&bd);\r
+ m_car->CreateFixture(&chassis, 1.0f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &circle;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.9f;\r
+\r
+ bd.position.Set(-1.0f, 0.35f);\r
+ m_wheel1 = m_world->CreateBody(&bd);\r
+ m_wheel1->CreateFixture(&fd);\r
+\r
+ bd.position.Set(1.0f, 0.4f);\r
+ m_wheel2 = m_world->CreateBody(&bd);\r
+ m_wheel2->CreateFixture(&fd);\r
+\r
+ b2WheelJointDef jd;\r
+ b2Vec2 axis(0.0f, 1.0f);\r
+\r
+ jd.Initialize(m_car, m_wheel1, m_wheel1->GetPosition(), axis);\r
+ jd.motorSpeed = 0.0f;\r
+ jd.maxMotorTorque = 20.0f;\r
+ jd.enableMotor = true;\r
+ jd.frequencyHz = m_hz;\r
+ jd.dampingRatio = m_zeta;\r
+ m_spring1 = (b2WheelJoint*)m_world->CreateJoint(&jd);\r
+\r
+ jd.Initialize(m_car, m_wheel2, m_wheel2->GetPosition(), axis);\r
+ jd.motorSpeed = 0.0f;\r
+ jd.maxMotorTorque = 10.0f;\r
+ jd.enableMotor = false;\r
+ jd.frequencyHz = m_hz;\r
+ jd.dampingRatio = m_zeta;\r
+ m_spring2 = (b2WheelJoint*)m_world->CreateJoint(&jd);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'a':\r
+ m_spring1->SetMotorSpeed(m_speed);\r
+ break;\r
+\r
+ case 's':\r
+ m_spring1->SetMotorSpeed(0.0f);\r
+ break;\r
+\r
+ case 'd':\r
+ m_spring1->SetMotorSpeed(-m_speed);\r
+ break;\r
+\r
+ case 'q':\r
+ m_hz = b2Max(0.0f, m_hz - 1.0f);\r
+ m_spring1->SetSpringFrequencyHz(m_hz);\r
+ m_spring2->SetSpringFrequencyHz(m_hz);\r
+ break;\r
+\r
+ case 'e':\r
+ m_hz += 1.0f;\r
+ m_spring1->SetSpringFrequencyHz(m_hz);\r
+ m_spring2->SetSpringFrequencyHz(m_hz);\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, hz down = q, hz up = e");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "frequency = %g hz, damping ratio = %g", m_hz, m_zeta);\r
+ m_textLine += 15;\r
+\r
+ settings->viewCenter.x = m_car->GetPosition().x;\r
+ Test::Step(settings);\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Car;\r
+ }\r
+\r
+ b2Body* m_car;\r
+ b2Body* m_wheel1;\r
+ b2Body* m_wheel2;\r
+\r
+ float32 m_hz;\r
+ float32 m_zeta;\r
+ float32 m_speed;\r
+ b2WheelJoint* m_spring1;\r
+ b2WheelJoint* m_spring2;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef CHAIN_H\r
+#define CHAIN_H\r
+\r
+class Chain : public Test\r
+{\r
+public:\r
+ Chain()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.6f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ fd.friction = 0.2f;\r
+\r
+ b2RevoluteJointDef jd;\r
+ jd.collideConnected = false;\r
+\r
+ const float32 y = 25.0f;\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < 30; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.5f + i, y);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+\r
+ b2Vec2 anchor(float32(i), y);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ prevBody = body;\r
+ }\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Chain;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef CHARACTER_COLLISION_H\r
+#define CHARACTER_COLLISION_H\r
+\r
+/// This is a test of typical character collision scenarios. This does not\r
+/// show how you should implement a character in your application.\r
+\r
+class CharacterCollision : public Test\r
+{\r
+public:\r
+ CharacterCollision()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Collinear edges with no adjacency information.\r
+ // This shows the problematic case where a box shape can hit\r
+ // an internal vertex.\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-8.0f, 1.0f), b2Vec2(-6.0f, 1.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ shape.Set(b2Vec2(-6.0f, 1.0f), b2Vec2(-4.0f, 1.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ shape.Set(b2Vec2(-4.0f, 1.0f), b2Vec2(-2.0f, 1.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Square tiles. This shows that adjacency shapes may\r
+ // have non-smooth collision. There is no solution\r
+ // to this problem.\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(1.0f, 1.0f, b2Vec2(4.0f, 3.0f), 0.0f);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ shape.SetAsBox(1.0f, 1.0f, b2Vec2(6.0f, 3.0f), 0.0f);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ shape.SetAsBox(1.0f, 1.0f, b2Vec2(8.0f, 3.0f), 0.0f);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Square made from an edge loop. Collision should be smooth.\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2Vec2 vs[4];\r
+ vs[0].Set(-1.0f, 3.0f);\r
+ vs[1].Set(1.0f, 3.0f);\r
+ vs[2].Set(1.0f, 5.0f);\r
+ vs[3].Set(-1.0f, 5.0f);\r
+ b2LoopShape shape;\r
+ shape.Create(vs, 4);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Edge loop. Collision should be smooth.\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(-10.0f, 4.0f);\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2Vec2 vs[10];\r
+ vs[0].Set(0.0f, 0.0f);\r
+ vs[1].Set(6.0f, 0.0f);\r
+ vs[2].Set(6.0f, 2.0f);\r
+ vs[3].Set(4.0f, 1.0f);\r
+ vs[4].Set(2.0f, 2.0f);\r
+ vs[5].Set(0.0f, 2.0f);\r
+ vs[6].Set(-2.0f, 2.0f);\r
+ vs[7].Set(-4.0f, 3.0f);\r
+ vs[8].Set(-6.0f, 2.0f);\r
+ vs[9].Set(-6.0f, 0.0f);\r
+ b2LoopShape shape;\r
+ shape.Create(vs, 10);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Square character 1\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(-3.0f, 8.0f);\r
+ bd.type = b2_dynamicBody;\r
+ bd.fixedRotation = true;\r
+ bd.allowSleep = false;\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.5f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ body->CreateFixture(&fd);\r
+ }\r
+\r
+ // Square character 2\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(-5.0f, 5.0f);\r
+ bd.type = b2_dynamicBody;\r
+ bd.fixedRotation = true;\r
+ bd.allowSleep = false;\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.25f, 0.25f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ body->CreateFixture(&fd);\r
+ }\r
+\r
+ // Hexagon character\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(-5.0f, 8.0f);\r
+ bd.type = b2_dynamicBody;\r
+ bd.fixedRotation = true;\r
+ bd.allowSleep = false;\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ float32 angle = 0.0f;\r
+ float32 delta = b2_pi / 3.0f;\r
+ b2Vec2 vertices[6];\r
+ for (int32 i = 0; i < 6; ++i)\r
+ {\r
+ vertices[i].Set(0.5f * cosf(angle), 0.5f * sinf(angle));\r
+ angle += delta;\r
+ }\r
+\r
+ b2PolygonShape shape;\r
+ shape.Set(vertices, 6);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ body->CreateFixture(&fd);\r
+ }\r
+\r
+ // Circle character\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(3.0f, 5.0f);\r
+ bd.type = b2_dynamicBody;\r
+ bd.fixedRotation = true;\r
+ bd.allowSleep = false;\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.5f;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "This tests various character collision shapes.");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Limitation: square and hexagon can snag on aligned boxes.");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Feature: loops have smooth collision inside and out.");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new CharacterCollision;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef COLLISION_FILTERING_H\r
+#define COLLISION_FILTERING_H\r
+\r
+// This is a test of collision filtering.\r
+// There is a triangle, a box, and a circle.\r
+// There are 6 shapes. 3 large and 3 small.\r
+// The 3 small ones always collide.\r
+// The 3 large ones never collide.\r
+// The boxes don't collide with triangles (except if both are small).\r
+const int16 k_smallGroup = 1;\r
+const int16 k_largeGroup = -1;\r
+\r
+const uint16 k_defaultCategory = 0x0001;\r
+const uint16 k_triangleCategory = 0x0002;\r
+const uint16 k_boxCategory = 0x0004;\r
+const uint16 k_circleCategory = 0x0008;\r
+\r
+const uint16 k_triangleMask = 0xFFFF;\r
+const uint16 k_boxMask = 0xFFFF ^ k_triangleCategory;\r
+const uint16 k_circleMask = 0xFFFF;\r
+\r
+class CollisionFiltering : public Test\r
+{\r
+public:\r
+ CollisionFiltering()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+\r
+ b2FixtureDef sd;\r
+ sd.shape = &shape;\r
+ sd.friction = 0.3f;\r
+\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&sd);\r
+ }\r
+\r
+ // Small triangle\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-1.0f, 0.0f);\r
+ vertices[1].Set(1.0f, 0.0f);\r
+ vertices[2].Set(0.0f, 2.0f);\r
+ b2PolygonShape polygon;\r
+ polygon.Set(vertices, 3);\r
+\r
+ b2FixtureDef triangleShapeDef;\r
+ triangleShapeDef.shape = &polygon;\r
+ triangleShapeDef.density = 1.0f;\r
+\r
+ triangleShapeDef.filter.groupIndex = k_smallGroup;\r
+ triangleShapeDef.filter.categoryBits = k_triangleCategory;\r
+ triangleShapeDef.filter.maskBits = k_triangleMask;\r
+\r
+ b2BodyDef triangleBodyDef;\r
+ triangleBodyDef.type = b2_dynamicBody;\r
+ triangleBodyDef.position.Set(-5.0f, 2.0f);\r
+\r
+ b2Body* body1 = m_world->CreateBody(&triangleBodyDef);\r
+ body1->CreateFixture(&triangleShapeDef);\r
+\r
+ // Large triangle (recycle definitions)\r
+ vertices[0] *= 2.0f;\r
+ vertices[1] *= 2.0f;\r
+ vertices[2] *= 2.0f;\r
+ polygon.Set(vertices, 3);\r
+ triangleShapeDef.filter.groupIndex = k_largeGroup;\r
+ triangleBodyDef.position.Set(-5.0f, 6.0f);\r
+ triangleBodyDef.fixedRotation = true; // look at me!\r
+\r
+ b2Body* body2 = m_world->CreateBody(&triangleBodyDef);\r
+ body2->CreateFixture(&triangleShapeDef);\r
+\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-5.0f, 10.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape p;\r
+ p.SetAsBox(0.5f, 1.0f);\r
+ body->CreateFixture(&p, 1.0f);\r
+\r
+ b2PrismaticJointDef jd;\r
+ jd.bodyA = body2;\r
+ jd.bodyB = body;\r
+ jd.enableLimit = true;\r
+ jd.localAnchorA.Set(0.0f, 4.0f);\r
+ jd.localAnchorB.SetZero();\r
+ jd.localAxis1.Set(0.0f, 1.0f);\r
+ jd.lowerTranslation = -1.0f;\r
+ jd.upperTranslation = 1.0f;\r
+\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ // Small box\r
+ polygon.SetAsBox(1.0f, 0.5f);\r
+ b2FixtureDef boxShapeDef;\r
+ boxShapeDef.shape = &polygon;\r
+ boxShapeDef.density = 1.0f;\r
+ boxShapeDef.restitution = 0.1f;\r
+\r
+ boxShapeDef.filter.groupIndex = k_smallGroup;\r
+ boxShapeDef.filter.categoryBits = k_boxCategory;\r
+ boxShapeDef.filter.maskBits = k_boxMask;\r
+\r
+ b2BodyDef boxBodyDef;\r
+ boxBodyDef.type = b2_dynamicBody;\r
+ boxBodyDef.position.Set(0.0f, 2.0f);\r
+\r
+ b2Body* body3 = m_world->CreateBody(&boxBodyDef);\r
+ body3->CreateFixture(&boxShapeDef);\r
+\r
+ // Large box (recycle definitions)\r
+ polygon.SetAsBox(2.0f, 1.0f);\r
+ boxShapeDef.filter.groupIndex = k_largeGroup;\r
+ boxBodyDef.position.Set(0.0f, 6.0f);\r
+\r
+ b2Body* body4 = m_world->CreateBody(&boxBodyDef);\r
+ body4->CreateFixture(&boxShapeDef);\r
+\r
+ // Small circle\r
+ b2CircleShape circle;\r
+ circle.m_radius = 1.0f;\r
+\r
+ b2FixtureDef circleShapeDef;\r
+ circleShapeDef.shape = &circle;\r
+ circleShapeDef.density = 1.0f;\r
+\r
+ circleShapeDef.filter.groupIndex = k_smallGroup;\r
+ circleShapeDef.filter.categoryBits = k_circleCategory;\r
+ circleShapeDef.filter.maskBits = k_circleMask;\r
+\r
+ b2BodyDef circleBodyDef;\r
+ circleBodyDef.type = b2_dynamicBody;\r
+ circleBodyDef.position.Set(5.0f, 2.0f);\r
+ \r
+ b2Body* body5 = m_world->CreateBody(&circleBodyDef);\r
+ body5->CreateFixture(&circleShapeDef);\r
+\r
+ // Large circle\r
+ circle.m_radius *= 2.0f;\r
+ circleShapeDef.filter.groupIndex = k_largeGroup;\r
+ circleBodyDef.position.Set(5.0f, 6.0f);\r
+\r
+ b2Body* body6 = m_world->CreateBody(&circleBodyDef);\r
+ body6->CreateFixture(&circleShapeDef);\r
+ }\r
+ static Test* Create()\r
+ {\r
+ return new CollisionFiltering;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef COLLISION_PROCESSING_H\r
+#define COLLISION_PROCESSING_H\r
+\r
+#include <algorithm>\r
+\r
+// This test shows collision processing and tests\r
+// deferred body destruction.\r
+class CollisionProcessing : public Test\r
+{\r
+public:\r
+ CollisionProcessing()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));\r
+\r
+ b2FixtureDef sd;\r
+ sd.shape = &shape;;\r
+\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&sd);\r
+ }\r
+\r
+ float32 xLo = -5.0f, xHi = 5.0f;\r
+ float32 yLo = 2.0f, yHi = 35.0f;\r
+\r
+ // Small triangle\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-1.0f, 0.0f);\r
+ vertices[1].Set(1.0f, 0.0f);\r
+ vertices[2].Set(0.0f, 2.0f);\r
+\r
+ b2PolygonShape polygon;\r
+ polygon.Set(vertices, 3);\r
+\r
+ b2FixtureDef triangleShapeDef;\r
+ triangleShapeDef.shape = &polygon;\r
+ triangleShapeDef.density = 1.0f;\r
+\r
+ b2BodyDef triangleBodyDef;\r
+ triangleBodyDef.type = b2_dynamicBody;\r
+ triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));\r
+\r
+ b2Body* body1 = m_world->CreateBody(&triangleBodyDef);\r
+ body1->CreateFixture(&triangleShapeDef);\r
+\r
+ // Large triangle (recycle definitions)\r
+ vertices[0] *= 2.0f;\r
+ vertices[1] *= 2.0f;\r
+ vertices[2] *= 2.0f;\r
+ polygon.Set(vertices, 3);\r
+\r
+ triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));\r
+\r
+ b2Body* body2 = m_world->CreateBody(&triangleBodyDef);\r
+ body2->CreateFixture(&triangleShapeDef);\r
+ \r
+ // Small box\r
+ polygon.SetAsBox(1.0f, 0.5f);\r
+\r
+ b2FixtureDef boxShapeDef;\r
+ boxShapeDef.shape = &polygon;\r
+ boxShapeDef.density = 1.0f;\r
+\r
+ b2BodyDef boxBodyDef;\r
+ boxBodyDef.type = b2_dynamicBody;\r
+ boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));\r
+\r
+ b2Body* body3 = m_world->CreateBody(&boxBodyDef);\r
+ body3->CreateFixture(&boxShapeDef);\r
+\r
+ // Large box (recycle definitions)\r
+ polygon.SetAsBox(2.0f, 1.0f);\r
+ boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));\r
+ \r
+ b2Body* body4 = m_world->CreateBody(&boxBodyDef);\r
+ body4->CreateFixture(&boxShapeDef);\r
+\r
+ // Small circle\r
+ b2CircleShape circle;\r
+ circle.m_radius = 1.0f;\r
+\r
+ b2FixtureDef circleShapeDef;\r
+ circleShapeDef.shape = &circle;\r
+ circleShapeDef.density = 1.0f;\r
+\r
+ b2BodyDef circleBodyDef;\r
+ circleBodyDef.type = b2_dynamicBody;\r
+ circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));\r
+\r
+ b2Body* body5 = m_world->CreateBody(&circleBodyDef);\r
+ body5->CreateFixture(&circleShapeDef);\r
+\r
+ // Large circle\r
+ circle.m_radius *= 2.0f;\r
+ circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));\r
+\r
+ b2Body* body6 = m_world->CreateBody(&circleBodyDef);\r
+ body6->CreateFixture(&circleShapeDef);\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ // We are going to destroy some bodies according to contact\r
+ // points. We must buffer the bodies that should be destroyed\r
+ // because they may belong to multiple contact points.\r
+ const int32 k_maxNuke = 6;\r
+ b2Body* nuke[k_maxNuke];\r
+ int32 nukeCount = 0;\r
+\r
+ // Traverse the contact results. Destroy bodies that\r
+ // are touching heavier bodies.\r
+ for (int32 i = 0; i < m_pointCount; ++i)\r
+ {\r
+ ContactPoint* point = m_points + i;\r
+\r
+ b2Body* body1 = point->fixtureA->GetBody();\r
+ b2Body* body2 = point->fixtureB->GetBody();\r
+ float32 mass1 = body1->GetMass();\r
+ float32 mass2 = body2->GetMass();\r
+\r
+ if (mass1 > 0.0f && mass2 > 0.0f)\r
+ {\r
+ if (mass2 > mass1)\r
+ {\r
+ nuke[nukeCount++] = body1;\r
+ }\r
+ else\r
+ {\r
+ nuke[nukeCount++] = body2;\r
+ }\r
+\r
+ if (nukeCount == k_maxNuke)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Sort the nuke array to group duplicates.\r
+ std::sort(nuke, nuke + nukeCount);\r
+\r
+ // Destroy the bodies, skipping duplicates.\r
+ int32 i = 0;\r
+ while (i < nukeCount)\r
+ {\r
+ b2Body* b = nuke[i++];\r
+ while (i < nukeCount && nuke[i] == b)\r
+ {\r
+ ++i;\r
+ }\r
+\r
+ if (b != m_bomb)\r
+ {\r
+ m_world->DestroyBody(b);\r
+ }\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new CollisionProcessing;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef COMPOUND_SHAPES_H\r
+#define COMPOUND_SHAPES_H\r
+\r
+// TODO_ERIN test joints on compounds.\r
+class CompoundShapes : public Test\r
+{\r
+public:\r
+ CompoundShapes()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(0.0f, 0.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));\r
+\r
+ body->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2CircleShape circle1;\r
+ circle1.m_radius = 0.5f;\r
+ circle1.m_p.Set(-0.5f, 0.5f);\r
+\r
+ b2CircleShape circle2;\r
+ circle2.m_radius = 0.5f;\r
+ circle2.m_p.Set(0.5f, 0.5f);\r
+\r
+ for (int i = 0; i < 10; ++i)\r
+ {\r
+ float32 x = RandomFloat(-0.1f, 0.1f);\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(x + 5.0f, 1.05f + 2.5f * i);\r
+ bd.angle = RandomFloat(-b2_pi, b2_pi);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&circle1, 2.0f);\r
+ body->CreateFixture(&circle2, 0.0f);\r
+ }\r
+ }\r
+\r
+ {\r
+ b2PolygonShape polygon1;\r
+ polygon1.SetAsBox(0.25f, 0.5f);\r
+\r
+ b2PolygonShape polygon2;\r
+ polygon2.SetAsBox(0.25f, 0.5f, b2Vec2(0.0f, -0.5f), 0.5f * b2_pi);\r
+\r
+ for (int i = 0; i < 10; ++i)\r
+ {\r
+ float32 x = RandomFloat(-0.1f, 0.1f);\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(x - 5.0f, 1.05f + 2.5f * i);\r
+ bd.angle = RandomFloat(-b2_pi, b2_pi);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&polygon1, 2.0f);\r
+ body->CreateFixture(&polygon2, 2.0f);\r
+ }\r
+ }\r
+\r
+ {\r
+ b2Transform xf1;\r
+ xf1.R.Set(0.3524f * b2_pi);\r
+ xf1.position = b2Mul(xf1.R, b2Vec2(1.0f, 0.0f));\r
+\r
+ b2Vec2 vertices[3];\r
+\r
+ b2PolygonShape triangle1;\r
+ vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));\r
+ vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));\r
+ vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));\r
+ triangle1.Set(vertices, 3);\r
+\r
+ b2Transform xf2;\r
+ xf2.R.Set(-0.3524f * b2_pi);\r
+ xf2.position = b2Mul(xf2.R, b2Vec2(-1.0f, 0.0f));\r
+\r
+ b2PolygonShape triangle2;\r
+ vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));\r
+ vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));\r
+ vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));\r
+ triangle2.Set(vertices, 3);\r
+\r
+ for (int32 i = 0; i < 10; ++i)\r
+ {\r
+ float32 x = RandomFloat(-0.1f, 0.1f);\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(x, 2.05f + 2.5f * i);\r
+ bd.angle = 0.0f;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&triangle1, 2.0f);\r
+ body->CreateFixture(&triangle2, 2.0f);\r
+ }\r
+ }\r
+\r
+ {\r
+ b2PolygonShape bottom;\r
+ bottom.SetAsBox( 1.5f, 0.15f );\r
+\r
+ b2PolygonShape left;\r
+ left.SetAsBox(0.15f, 2.7f, b2Vec2(-1.45f, 2.35f), 0.2f);\r
+\r
+ b2PolygonShape right;\r
+ right.SetAsBox(0.15f, 2.7f, b2Vec2(1.45f, 2.35f), -0.2f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set( 0.0f, 2.0f );\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&bottom, 4.0f);\r
+ body->CreateFixture(&left, 4.0f);\r
+ body->CreateFixture(&right, 4.0f);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new CompoundShapes;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef CONFINED_H\r
+#define CONFINED_H\r
+\r
+class Confined : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_columnCount = 0,\r
+ e_rowCount = 0\r
+ };\r
+\r
+ Confined()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+\r
+ // Floor\r
+ shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ // Left wall\r
+ shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(-10.0f, 20.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ // Right wall\r
+ shape.Set(b2Vec2(10.0f, 0.0f), b2Vec2(10.0f, 20.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ // Roof\r
+ shape.Set(b2Vec2(-10.0f, 20.0f), b2Vec2(10.0f, 20.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ float32 radius = 0.5f;\r
+ b2CircleShape shape;\r
+ shape.m_p.SetZero();\r
+ shape.m_radius = radius;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.1f;\r
+\r
+ for (int32 j = 0; j < e_columnCount; ++j)\r
+ {\r
+ for (int i = 0; i < e_rowCount; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-10.0f + (2.1f * j + 1.0f + 0.01f * i) * radius, (2.0f * i + 1.0f) * radius);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ m_world->SetGravity(b2Vec2(0.0f, 0.0f));\r
+ }\r
+\r
+ void CreateCircle()\r
+ {\r
+ float32 radius = 2.0f;\r
+ b2CircleShape shape;\r
+ shape.m_p.SetZero();\r
+ shape.m_radius = radius;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.0f;\r
+\r
+ b2Vec2 p(RandomFloat(), 3.0f + RandomFloat());\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position = p;\r
+ //bd.allowSleep = false;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ body->CreateFixture(&fd);\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'c':\r
+ CreateCircle();\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ bool sleeping = true;\r
+ for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())\r
+ {\r
+ if (b->GetType() != b2_dynamicBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (b->IsAwake())\r
+ {\r
+ sleeping = false;\r
+ }\r
+ }\r
+\r
+ if (m_stepCount == 180)\r
+ {\r
+ m_stepCount += 0;\r
+ }\r
+\r
+ //if (sleeping)\r
+ //{\r
+ // CreateCircle();\r
+ //}\r
+\r
+ Test::Step(settings);\r
+\r
+ for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())\r
+ {\r
+ if (b->GetType() != b2_dynamicBody)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Vec2 p = b->GetPosition();\r
+ if (p.x <= -10.0f || 10.0f <= p.x || p.y <= 0.0f || 20.0f <= p.y)\r
+ {\r
+ p.x += 0.0;\r
+ }\r
+ }\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 'c' to create a circle.");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Confined;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef CONTINUOUS_TEST_H\r
+#define CONTINUOUS_TEST_H\r
+\r
+class ContinuousTest : public Test\r
+{\r
+public:\r
+\r
+ ContinuousTest()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(0.0f, 0.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape edge;\r
+\r
+ edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));\r
+ body->CreateFixture(&edge, 0.0f);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);\r
+ body->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+#if 1\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 20.0f);\r
+ //bd.angle = 0.1f;\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(2.0f, 0.1f);\r
+\r
+ m_body = m_world->CreateBody(&bd);\r
+ m_body->CreateFixture(&shape, 1.0f);\r
+\r
+ m_angularVelocity = RandomFloat(-50.0f, 50.0f);\r
+ //m_angularVelocity = 46.661274f;\r
+ m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));\r
+ m_body->SetAngularVelocity(m_angularVelocity);\r
+ }\r
+#else\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 2.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2CircleShape shape;\r
+ shape.m_p.SetZero();\r
+ shape.m_radius = 0.5f;\r
+ body->CreateFixture(&shape, 1.0f);\r
+\r
+ bd.bullet = true;\r
+ bd.position.Set(0.0f, 10.0f);\r
+ body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 1.0f);\r
+ body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));\r
+ }\r
+#endif\r
+ }\r
+\r
+ void Launch()\r
+ {\r
+ m_body->SetTransform(b2Vec2(0.0f, 20.0f), 0.0f);\r
+ m_angularVelocity = RandomFloat(-50.0f, 50.0f);\r
+ m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));\r
+ m_body->SetAngularVelocity(m_angularVelocity);\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ if (m_stepCount == 12)\r
+ {\r
+ m_stepCount += 0;\r
+ }\r
+\r
+ Test::Step(settings);\r
+\r
+ extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;\r
+\r
+ if (b2_gjkCalls > 0)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",\r
+ b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ extern int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;\r
+ extern int32 b2_toiRootIters, b2_toiMaxRootIters;\r
+\r
+ if (b2_toiCalls > 0)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",\r
+ b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters);\r
+ m_textLine += 15;\r
+ \r
+ m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",\r
+ b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ if (m_stepCount % 60 == 0)\r
+ {\r
+ //Launch();\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new ContinuousTest;\r
+ }\r
+\r
+ b2Body* m_body;\r
+ float32 m_angularVelocity;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef DISTANCE_TEST_H
+#define DISTANCE_TEST_H
+
+class DistanceTest : public Test
+{
+public:
+ DistanceTest()
+ {
+ {
+ m_transformA.SetIdentity();
+ m_transformA.position.Set(0.0f, -0.2f);
+ m_polygonA.SetAsBox(10.0f, 0.2f);
+ }
+
+ {
+ m_positionB.Set(12.017401f, 0.13678508f);
+ m_angleB = -0.0109265f;
+ m_transformB.Set(m_positionB, m_angleB);
+
+ m_polygonB.SetAsBox(2.0f, 0.1f);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new DistanceTest;
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ b2DistanceInput input;
+ input.proxyA.Set(&m_polygonA, 0);
+ input.proxyB.Set(&m_polygonB, 0);
+ input.transformA = m_transformA;
+ input.transformB = m_transformB;
+ input.useRadii = true;
+ b2SimplexCache cache;
+ cache.count = 0;
+ b2DistanceOutput output;
+ b2Distance(&output, &cache, &input);
+
+ m_debugDraw.DrawString(5, m_textLine, "distance = %g", output.distance);
+ m_textLine += 15;
+
+ m_debugDraw.DrawString(5, m_textLine, "iterations = %d", output.iterations);
+ m_textLine += 15;
+
+ {
+ b2Color color(0.9f, 0.9f, 0.9f);
+ b2Vec2 v[b2_maxPolygonVertices];
+ for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i)
+ {
+ v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color);
+
+ for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i)
+ {
+ v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color);
+ }
+
+ b2Vec2 x1 = output.pointA;
+ b2Vec2 x2 = output.pointB;
+
+ b2Color c1(1.0f, 0.0f, 0.0f);
+ m_debugDraw.DrawPoint(x1, 4.0f, c1);
+
+ b2Color c2(1.0f, 1.0f, 0.0f);
+ m_debugDraw.DrawPoint(x2, 4.0f, c2);
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ m_positionB.x -= 0.1f;
+ break;
+
+ case 'd':
+ m_positionB.x += 0.1f;
+ break;
+
+ case 's':
+ m_positionB.y -= 0.1f;
+ break;
+
+ case 'w':
+ m_positionB.y += 0.1f;
+ break;
+
+ case 'q':
+ m_angleB += 0.1f * b2_pi;
+ break;
+
+ case 'e':
+ m_angleB -= 0.1f * b2_pi;
+ break;
+ }
+
+ m_transformB.Set(m_positionB, m_angleB);
+ }
+
+ b2Vec2 m_positionB;
+ float32 m_angleB;
+
+ b2Transform m_transformA;
+ b2Transform m_transformB;
+ b2PolygonShape m_polygonA;
+ b2PolygonShape m_polygonB;
+};
+
+#endif
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef DOMINOS_H\r
+#define DOMINOS_H\r
+\r
+class Dominos : public Test\r
+{\r
+public:\r
+\r
+ Dominos()\r
+ {\r
+ b2Body* b1;\r
+ {\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+\r
+ b2BodyDef bd;\r
+ b1 = m_world->CreateBody(&bd);\r
+ b1->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(6.0f, 0.25f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(-1.5f, 10.0f);\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.1f, 1.0f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ fd.friction = 0.1f;\r
+\r
+ for (int i = 0; i < 10; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-6.0f + 1.0f * i, 11.25f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(7.0f, 0.25f, b2Vec2_zero, 0.3f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(1.0f, 6.0f);\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ b2Body* b2;\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.25f, 1.5f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(-7.0f, 4.0f);\r
+ b2 = m_world->CreateBody(&bd);\r
+ b2->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ b2Body* b3;\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(6.0f, 0.125f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-0.9f, 1.0f);\r
+ bd.angle = -0.15f;\r
+\r
+ b3 = m_world->CreateBody(&bd);\r
+ b3->CreateFixture(&shape, 10.0f);\r
+ }\r
+\r
+ b2RevoluteJointDef jd;\r
+ b2Vec2 anchor;\r
+\r
+ anchor.Set(-2.0f, 1.0f);\r
+ jd.Initialize(b1, b3, anchor);\r
+ jd.collideConnected = true;\r
+ m_world->CreateJoint(&jd);\r
+\r
+ b2Body* b4;\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.25f, 0.25f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-10.0f, 15.0f);\r
+ b4 = m_world->CreateBody(&bd);\r
+ b4->CreateFixture(&shape, 10.0f);\r
+ }\r
+\r
+ anchor.Set(-7.0f, 15.0f);\r
+ jd.Initialize(b2, b4, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ b2Body* b5;\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(6.5f, 3.0f);\r
+ b5 = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ b2FixtureDef fd;\r
+\r
+ fd.shape = &shape;\r
+ fd.density = 10.0f;\r
+ fd.friction = 0.1f;\r
+\r
+ shape.SetAsBox(1.0f, 0.1f, b2Vec2(0.0f, -0.9f), 0.0f);\r
+ b5->CreateFixture(&fd);\r
+\r
+ shape.SetAsBox(0.1f, 1.0f, b2Vec2(-0.9f, 0.0f), 0.0f);\r
+ b5->CreateFixture(&fd);\r
+\r
+ shape.SetAsBox(0.1f, 1.0f, b2Vec2(0.9f, 0.0f), 0.0f);\r
+ b5->CreateFixture(&fd);\r
+ }\r
+\r
+ anchor.Set(6.0f, 2.0f);\r
+ jd.Initialize(b1, b5, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ b2Body* b6;\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(1.0f, 0.1f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(6.5f, 4.1f);\r
+ b6 = m_world->CreateBody(&bd);\r
+ b6->CreateFixture(&shape, 30.0f);\r
+ }\r
+\r
+ anchor.Set(7.5f, 4.0f);\r
+ jd.Initialize(b5, b6, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ b2Body* b7;\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.1f, 1.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(7.4f, 1.0f);\r
+\r
+ b7 = m_world->CreateBody(&bd);\r
+ b7->CreateFixture(&shape, 10.0f);\r
+ }\r
+\r
+ b2DistanceJointDef djd;\r
+ djd.bodyA = b3;\r
+ djd.bodyB = b7;\r
+ djd.localAnchorA.Set(6.0f, 0.0f);\r
+ djd.localAnchorB.Set(0.0f, -1.0f);\r
+ b2Vec2 d = djd.bodyB->GetWorldPoint(djd.localAnchorB) - djd.bodyA->GetWorldPoint(djd.localAnchorA);\r
+ djd.length = d.Length();\r
+ m_world->CreateJoint(&djd);\r
+\r
+ {\r
+ float32 radius = 0.2f;\r
+\r
+ b2CircleShape shape;\r
+ shape.m_radius = radius;\r
+\r
+ for (int32 i = 0; i < 4; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(5.9f + 2.0f * radius * i, 2.4f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 10.0f);\r
+ }\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Dominos;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef DYNAMIC_TREE_TEST_H\r
+#define DYNAMIC_TREE_TEST_H\r
+\r
+class DynamicTreeTest : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_actorCount = 128\r
+ };\r
+\r
+ DynamicTreeTest()\r
+ {\r
+ m_worldExtent = 15.0f;\r
+ m_proxyExtent = 0.5f;\r
+\r
+ srand(888);\r
+\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ Actor* actor = m_actors + i;\r
+ GetRandomAABB(&actor->aabb);\r
+ actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);\r
+ }\r
+\r
+ m_stepCount = 0;\r
+\r
+ float32 h = m_worldExtent;\r
+ m_queryAABB.lowerBound.Set(-3.0f, -4.0f + h);\r
+ m_queryAABB.upperBound.Set(5.0f, 6.0f + h);\r
+\r
+ m_rayCastInput.p1.Set(-5.0, 5.0f + h);\r
+ m_rayCastInput.p2.Set(7.0f, -4.0f + h);\r
+ //m_rayCastInput.p1.Set(0.0f, 2.0f + h);\r
+ //m_rayCastInput.p2.Set(0.0f, -2.0f + h);\r
+ m_rayCastInput.maxFraction = 1.0f;\r
+\r
+ m_automated = false;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new DynamicTreeTest;\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ B2_NOT_USED(settings);\r
+\r
+ m_rayActor = NULL;\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ m_actors[i].fraction = 1.0f;\r
+ m_actors[i].overlap = false;\r
+ }\r
+\r
+ if (m_automated == true)\r
+ {\r
+ int32 actionCount = b2Max(1, e_actorCount >> 2);\r
+\r
+ for (int32 i = 0; i < actionCount; ++i)\r
+ {\r
+ Action();\r
+ }\r
+ }\r
+\r
+ Query();\r
+ RayCast();\r
+\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ Actor* actor = m_actors + i;\r
+ if (actor->proxyId == b2_nullNode)\r
+ continue;\r
+\r
+ b2Color c(0.9f, 0.9f, 0.9f);\r
+ if (actor == m_rayActor && actor->overlap)\r
+ {\r
+ c.Set(0.9f, 0.6f, 0.6f);\r
+ }\r
+ else if (actor == m_rayActor)\r
+ {\r
+ c.Set(0.6f, 0.9f, 0.6f);\r
+ }\r
+ else if (actor->overlap)\r
+ {\r
+ c.Set(0.6f, 0.6f, 0.9f);\r
+ }\r
+\r
+ m_debugDraw.DrawAABB(&actor->aabb, c);\r
+ }\r
+\r
+ b2Color c(0.7f, 0.7f, 0.7f);\r
+ m_debugDraw.DrawAABB(&m_queryAABB, c);\r
+\r
+ m_debugDraw.DrawSegment(m_rayCastInput.p1, m_rayCastInput.p2, c);\r
+\r
+ b2Color c1(0.2f, 0.9f, 0.2f);\r
+ b2Color c2(0.9f, 0.2f, 0.2f);\r
+ m_debugDraw.DrawPoint(m_rayCastInput.p1, 6.0f, c1);\r
+ m_debugDraw.DrawPoint(m_rayCastInput.p2, 6.0f, c2);\r
+\r
+ if (m_rayActor)\r
+ {\r
+ b2Color cr(0.2f, 0.2f, 0.9f);\r
+ b2Vec2 p = m_rayCastInput.p1 + m_rayActor->fraction * (m_rayCastInput.p2 - m_rayCastInput.p1);\r
+ m_debugDraw.DrawPoint(p, 6.0f, cr);\r
+ }\r
+\r
+ {\r
+ int32 height = m_tree.GetHeight();\r
+ m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d", height);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ ++m_stepCount;\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'a':\r
+ m_automated = !m_automated;\r
+ break;\r
+\r
+ case 'c':\r
+ CreateProxy();\r
+ break;\r
+\r
+ case 'd':\r
+ DestroyProxy();\r
+ break;\r
+\r
+ case 'm':\r
+ MoveProxy();\r
+ break;\r
+ }\r
+ }\r
+\r
+ bool QueryCallback(int32 proxyId)\r
+ {\r
+ Actor* actor = (Actor*)m_tree.GetUserData(proxyId);\r
+ actor->overlap = b2TestOverlap(m_queryAABB, actor->aabb);\r
+ return true;\r
+ }\r
+\r
+ float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)\r
+ {\r
+ Actor* actor = (Actor*)m_tree.GetUserData(proxyId);\r
+\r
+ b2RayCastOutput output;\r
+ bool hit = actor->aabb.RayCast(&output, input);\r
+\r
+ if (hit)\r
+ {\r
+ m_rayCastOutput = output;\r
+ m_rayActor = actor;\r
+ m_rayActor->fraction = output.fraction;\r
+ return output.fraction;\r
+ }\r
+\r
+ return input.maxFraction;\r
+ }\r
+\r
+private:\r
+\r
+ struct Actor\r
+ {\r
+ b2AABB aabb;\r
+ float32 fraction;\r
+ bool overlap;\r
+ int32 proxyId;\r
+ };\r
+\r
+ void GetRandomAABB(b2AABB* aabb)\r
+ {\r
+ b2Vec2 w; w.Set(2.0f * m_proxyExtent, 2.0f * m_proxyExtent);\r
+ //aabb->lowerBound.x = -m_proxyExtent;\r
+ //aabb->lowerBound.y = -m_proxyExtent + m_worldExtent;\r
+ aabb->lowerBound.x = RandomFloat(-m_worldExtent, m_worldExtent);\r
+ aabb->lowerBound.y = RandomFloat(0.0f, 2.0f * m_worldExtent);\r
+ aabb->upperBound = aabb->lowerBound + w;\r
+ }\r
+\r
+ void MoveAABB(b2AABB* aabb)\r
+ {\r
+ b2Vec2 d;\r
+ d.x = RandomFloat(-0.5f, 0.5f);\r
+ d.y = RandomFloat(-0.5f, 0.5f);\r
+ //d.x = 2.0f;\r
+ //d.y = 0.0f;\r
+ aabb->lowerBound += d;\r
+ aabb->upperBound += d;\r
+\r
+ b2Vec2 c0 = 0.5f * (aabb->lowerBound + aabb->upperBound);\r
+ b2Vec2 min; min.Set(-m_worldExtent, 0.0f);\r
+ b2Vec2 max; max.Set(m_worldExtent, 2.0f * m_worldExtent);\r
+ b2Vec2 c = b2Clamp(c0, min, max);\r
+\r
+ aabb->lowerBound += c - c0;\r
+ aabb->upperBound += c - c0;\r
+ }\r
+\r
+ void CreateProxy()\r
+ {\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ int32 j = rand() % e_actorCount;\r
+ Actor* actor = m_actors + j;\r
+ if (actor->proxyId == b2_nullNode)\r
+ {\r
+ GetRandomAABB(&actor->aabb);\r
+ actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ void DestroyProxy()\r
+ {\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ int32 j = rand() % e_actorCount;\r
+ Actor* actor = m_actors + j;\r
+ if (actor->proxyId != b2_nullNode)\r
+ {\r
+ m_tree.DestroyProxy(actor->proxyId);\r
+ actor->proxyId = b2_nullNode;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ void MoveProxy()\r
+ {\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ int32 j = rand() % e_actorCount;\r
+ Actor* actor = m_actors + j;\r
+ if (actor->proxyId == b2_nullNode)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2AABB aabb0 = actor->aabb;\r
+ MoveAABB(&actor->aabb);\r
+ b2Vec2 displacement = actor->aabb.GetCenter() - aabb0.GetCenter();\r
+ m_tree.MoveProxy(actor->proxyId, actor->aabb, displacement);\r
+ return;\r
+ }\r
+ }\r
+\r
+ void Action()\r
+ {\r
+ int32 choice = rand() % 20;\r
+\r
+ switch (choice)\r
+ {\r
+ case 0:\r
+ CreateProxy();\r
+ break;\r
+\r
+ case 1:\r
+ DestroyProxy();\r
+ break;\r
+\r
+ default:\r
+ MoveProxy();\r
+ }\r
+ }\r
+\r
+ void Query()\r
+ {\r
+ m_tree.Query(this, m_queryAABB);\r
+\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ if (m_actors[i].proxyId == b2_nullNode)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ bool overlap = b2TestOverlap(m_queryAABB, m_actors[i].aabb);\r
+ B2_NOT_USED(overlap);\r
+ b2Assert(overlap == m_actors[i].overlap);\r
+ }\r
+ }\r
+\r
+ void RayCast()\r
+ {\r
+ m_rayActor = NULL;\r
+\r
+ b2RayCastInput input = m_rayCastInput;\r
+\r
+ // Ray cast against the dynamic tree.\r
+ m_tree.RayCast(this, input);\r
+\r
+ // Brute force ray cast.\r
+ Actor* bruteActor = NULL;\r
+ b2RayCastOutput bruteOutput;\r
+ for (int32 i = 0; i < e_actorCount; ++i)\r
+ {\r
+ if (m_actors[i].proxyId == b2_nullNode)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2RayCastOutput output;\r
+ bool hit = m_actors[i].aabb.RayCast(&output, input);\r
+ if (hit)\r
+ {\r
+ bruteActor = m_actors + i;\r
+ bruteOutput = output;\r
+ input.maxFraction = output.fraction;\r
+ }\r
+ }\r
+\r
+ if (bruteActor != NULL)\r
+ {\r
+ b2Assert(bruteOutput.fraction == m_rayCastOutput.fraction);\r
+ }\r
+ }\r
+\r
+ float32 m_worldExtent;\r
+ float32 m_proxyExtent;\r
+\r
+ b2DynamicTree m_tree;\r
+ b2AABB m_queryAABB;\r
+ b2RayCastInput m_rayCastInput;\r
+ b2RayCastOutput m_rayCastOutput;\r
+ Actor* m_rayActor;\r
+ Actor m_actors[e_actorCount];\r
+ int32 m_stepCount;\r
+ bool m_automated;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef EDGE_SHAPES_H\r
+#define EDGE_SHAPES_H\r
+\r
+class EdgeShapesCallback : public b2RayCastCallback\r
+{\r
+public:\r
+ EdgeShapesCallback()\r
+ {\r
+ m_fixture = NULL;\r
+ }\r
+\r
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,\r
+ const b2Vec2& normal, float32 fraction)\r
+ {\r
+ m_fixture = fixture;\r
+ m_point = point;\r
+ m_normal = normal;\r
+\r
+ return fraction;\r
+ }\r
+\r
+ b2Fixture* m_fixture;\r
+ b2Vec2 m_point;\r
+ b2Vec2 m_normal;\r
+};\r
+\r
+class EdgeShapes : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_maxBodies = 256\r
+ };\r
+\r
+ EdgeShapes()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ float32 x1 = -20.0f;\r
+ float32 y1 = 2.0f * cosf(x1 / 10.0f * b2_pi);\r
+ for (int32 i = 0; i < 80; ++i)\r
+ {\r
+ float32 x2 = x1 + 0.5f;\r
+ float32 y2 = 2.0f * cosf(x2 / 10.0f * b2_pi);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(x1, y1), b2Vec2(x2, y2));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ x1 = x2;\r
+ y1 = y2;\r
+ }\r
+ }\r
+\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.5f, 0.0f);\r
+ vertices[1].Set(0.5f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+ m_polygons[0].Set(vertices, 3);\r
+ }\r
+\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.1f, 0.0f);\r
+ vertices[1].Set(0.1f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+ m_polygons[1].Set(vertices, 3);\r
+ }\r
+\r
+ {\r
+ float32 w = 1.0f;\r
+ float32 b = w / (2.0f + b2Sqrt(2.0f));\r
+ float32 s = b2Sqrt(2.0f) * b;\r
+\r
+ b2Vec2 vertices[8];\r
+ vertices[0].Set(0.5f * s, 0.0f);\r
+ vertices[1].Set(0.5f * w, b);\r
+ vertices[2].Set(0.5f * w, b + s);\r
+ vertices[3].Set(0.5f * s, w);\r
+ vertices[4].Set(-0.5f * s, w);\r
+ vertices[5].Set(-0.5f * w, b + s);\r
+ vertices[6].Set(-0.5f * w, b);\r
+ vertices[7].Set(-0.5f * s, 0.0f);\r
+\r
+ m_polygons[2].Set(vertices, 8);\r
+ }\r
+\r
+ {\r
+ m_polygons[3].SetAsBox(0.5f, 0.5f);\r
+ }\r
+\r
+ {\r
+ m_circle.m_radius = 0.5f;\r
+ }\r
+\r
+ m_bodyIndex = 0;\r
+ memset(m_bodies, 0, sizeof(m_bodies));\r
+\r
+ m_angle = 0.0f;\r
+ }\r
+\r
+ void Create(int32 index)\r
+ {\r
+ if (m_bodies[m_bodyIndex] != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bodies[m_bodyIndex]);\r
+ m_bodies[m_bodyIndex] = NULL;\r
+ }\r
+\r
+ b2BodyDef bd;\r
+\r
+ float32 x = RandomFloat(-10.0f, 10.0f);\r
+ float32 y = RandomFloat(10.0f, 20.0f);\r
+ bd.position.Set(x, y);\r
+ bd.angle = RandomFloat(-b2_pi, b2_pi);\r
+ bd.type = b2_dynamicBody;\r
+\r
+ if (index == 4)\r
+ {\r
+ bd.angularDamping = 0.02f;\r
+ }\r
+\r
+ m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);\r
+\r
+ if (index < 4)\r
+ {\r
+ b2FixtureDef fd;\r
+ fd.shape = m_polygons + index;\r
+ fd.friction = 0.3f;\r
+ fd.density = 20.0f;\r
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);\r
+ }\r
+ else\r
+ {\r
+ b2FixtureDef fd;\r
+ fd.shape = &m_circle;\r
+ fd.friction = 0.3f;\r
+ fd.density = 20.0f;\r
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);\r
+ }\r
+\r
+ m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;\r
+ }\r
+\r
+ void DestroyBody()\r
+ {\r
+ for (int32 i = 0; i < e_maxBodies; ++i)\r
+ {\r
+ if (m_bodies[i] != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bodies[i]);\r
+ m_bodies[i] = NULL;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case '1':\r
+ case '2':\r
+ case '3':\r
+ case '4':\r
+ case '5':\r
+ Create(key - '1');\r
+ break;\r
+\r
+ case 'd':\r
+ DestroyBody();\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ bool advanceRay = settings->pause == 0 || settings->singleStep;\r
+\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");\r
+ m_textLine += 15;\r
+\r
+ float32 L = 25.0f;\r
+ b2Vec2 point1(0.0f, 10.0f);\r
+ b2Vec2 d(L * cosf(m_angle), -L * b2Abs(sinf(m_angle)));\r
+ b2Vec2 point2 = point1 + d;\r
+\r
+ EdgeShapesCallback callback;\r
+\r
+ m_world->RayCast(&callback, point1, point2);\r
+\r
+ if (callback.m_fixture)\r
+ {\r
+ m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));\r
+\r
+ m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));\r
+\r
+ b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;\r
+ m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));\r
+ }\r
+ else\r
+ {\r
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));\r
+ }\r
+\r
+ if (advanceRay)\r
+ {\r
+ m_angle += 0.25f * b2_pi / 180.0f;\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new EdgeShapes;\r
+ }\r
+\r
+ int32 m_bodyIndex;\r
+ b2Body* m_bodies[e_maxBodies];\r
+ b2PolygonShape m_polygons[4];\r
+ b2CircleShape m_circle;\r
+\r
+ float32 m_angle;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef EDGE_TEST_H\r
+#define EDGE_TEST_H\r
+\r
+class EdgeTest : public Test\r
+{\r
+public:\r
+\r
+ EdgeTest()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2Vec2 v1(-10.0f, 0.0f), v2(-7.0f, -2.0f), v3(-4.0f, 0.0f);\r
+ b2Vec2 v4(0.0f, 0.0f), v5(4.0f, 0.0f), v6(7.0f, 2.0f), v7(10.0f, 0.0f);\r
+\r
+ b2EdgeShape shape;\r
+\r
+ shape.Set(v1, v2);\r
+ shape.m_hasVertex3 = true;\r
+ shape.m_vertex3 = v3;\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(v2, v3);\r
+ shape.m_hasVertex0 = true;\r
+ shape.m_hasVertex3 = true;\r
+ shape.m_vertex0 = v1;\r
+ shape.m_vertex3 = v4;\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(v3, v4);\r
+ shape.m_hasVertex0 = true;\r
+ shape.m_hasVertex3 = true;\r
+ shape.m_vertex0 = v2;\r
+ shape.m_vertex3 = v5;\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(v4, v5);\r
+ shape.m_hasVertex0 = true;\r
+ shape.m_hasVertex3 = true;\r
+ shape.m_vertex0 = v3;\r
+ shape.m_vertex3 = v6;\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(v5, v6);\r
+ shape.m_hasVertex0 = true;\r
+ shape.m_hasVertex3 = true;\r
+ shape.m_vertex0 = v4;\r
+ shape.m_vertex3 = v7;\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(v6, v7);\r
+ shape.m_hasVertex0 = true;\r
+ shape.m_vertex0 = v5;\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-0.5f, 0.6f);\r
+ bd.allowSleep = false;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.5f;\r
+\r
+ body->CreateFixture(&shape, 1.0f);\r
+ }\r
+\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(1.0f, 0.6f);\r
+ bd.allowSleep = false;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.5f);\r
+\r
+ body->CreateFixture(&shape, 1.0f);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new EdgeTest;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef GEARS_H\r
+#define GEARS_H\r
+\r
+class Gears : public Test\r
+{\r
+public:\r
+ Gears()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2CircleShape circle1;\r
+ circle1.m_radius = 1.0f;\r
+\r
+ b2CircleShape circle2;\r
+ circle2.m_radius = 2.0f;\r
+ \r
+ b2PolygonShape box;\r
+ box.SetAsBox(0.5f, 5.0f);\r
+\r
+ b2BodyDef bd1;\r
+ bd1.type = b2_dynamicBody;\r
+ bd1.position.Set(-3.0f, 12.0f);\r
+ b2Body* body1 = m_world->CreateBody(&bd1);\r
+ body1->CreateFixture(&circle1, 5.0f);\r
+\r
+ b2RevoluteJointDef jd1;\r
+ jd1.bodyA = ground;\r
+ jd1.bodyB = body1;\r
+ jd1.localAnchorA = ground->GetLocalPoint(bd1.position);\r
+ jd1.localAnchorB = body1->GetLocalPoint(bd1.position);\r
+ jd1.referenceAngle = body1->GetAngle() - ground->GetAngle();\r
+ m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd1);\r
+\r
+ b2BodyDef bd2;\r
+ bd2.type = b2_dynamicBody;\r
+ bd2.position.Set(0.0f, 12.0f);\r
+ b2Body* body2 = m_world->CreateBody(&bd2);\r
+ body2->CreateFixture(&circle2, 5.0f);\r
+\r
+ b2RevoluteJointDef jd2;\r
+ jd2.Initialize(ground, body2, bd2.position);\r
+ m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd2);\r
+\r
+ b2BodyDef bd3;\r
+ bd3.type = b2_dynamicBody;\r
+ bd3.position.Set(2.5f, 12.0f);\r
+ b2Body* body3 = m_world->CreateBody(&bd3);\r
+ body3->CreateFixture(&box, 5.0f);\r
+\r
+ b2PrismaticJointDef jd3;\r
+ jd3.Initialize(ground, body3, bd3.position, b2Vec2(0.0f, 1.0f));\r
+ jd3.lowerTranslation = -5.0f;\r
+ jd3.upperTranslation = 5.0f;\r
+ jd3.enableLimit = true;\r
+\r
+ m_joint3 = (b2PrismaticJoint*)m_world->CreateJoint(&jd3);\r
+\r
+ b2GearJointDef jd4;\r
+ jd4.bodyA = body1;\r
+ jd4.bodyB = body2;\r
+ jd4.joint1 = m_joint1;\r
+ jd4.joint2 = m_joint2;\r
+ jd4.ratio = circle2.m_radius / circle1.m_radius;\r
+ m_joint4 = (b2GearJoint*)m_world->CreateJoint(&jd4);\r
+\r
+ b2GearJointDef jd5;\r
+ jd5.bodyA = body2;\r
+ jd5.bodyB = body3;\r
+ jd5.joint1 = m_joint2;\r
+ jd5.joint2 = m_joint3;\r
+ jd5.ratio = -1.0f / circle2.m_radius;\r
+ m_joint5 = (b2GearJoint*)m_world->CreateJoint(&jd5);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 0:\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ float32 ratio, value;\r
+ \r
+ ratio = m_joint4->GetRatio();\r
+ value = m_joint1->GetJointAngle() + ratio * m_joint2->GetJointAngle();\r
+ m_debugDraw.DrawString(5, m_textLine, "theta1 + %4.2f * theta2 = %4.2f", (float) ratio, (float) value);\r
+ m_textLine += 15;\r
+\r
+ ratio = m_joint5->GetRatio();\r
+ value = m_joint2->GetJointAngle() + ratio * m_joint3->GetJointTranslation();\r
+ m_debugDraw.DrawString(5, m_textLine, "theta2 + %4.2f * delta = %4.2f", (float) ratio, (float) value);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Gears;\r
+ }\r
+\r
+ b2RevoluteJoint* m_joint1;\r
+ b2RevoluteJoint* m_joint2;\r
+ b2PrismaticJoint* m_joint3;\r
+ b2GearJoint* m_joint4;\r
+ b2GearJoint* m_joint5;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef LINE_JOINT_H\r
+#define LINE_JOINT_H\r
+\r
+// A line joint with a limit and friction.\r
+class LineJoint : public Test\r
+{\r
+public:\r
+ LineJoint()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsEdge(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 2.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 7.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 1.0f);\r
+\r
+ b2LineJointDef jd;\r
+ b2Vec2 axis(2.0f, 1.0f);\r
+ axis.Normalize();\r
+ jd.Initialize(ground, body, b2Vec2(0.0f, 8.5f), axis);\r
+ jd.motorSpeed = 0.0f;\r
+ jd.maxMotorForce = 100.0f;\r
+ jd.enableMotor = true;\r
+ jd.lowerTranslation = -4.0f;\r
+ jd.upperTranslation = 4.0f;\r
+ jd.enableLimit = true;\r
+ m_world->CreateJoint(&jd);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new LineJoint;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef ONE_SIDED_PLATFORM_H\r
+#define ONE_SIDED_PLATFORM_H\r
+\r
+class OneSidedPlatform : public Test\r
+{\r
+public:\r
+\r
+ enum State\r
+ {\r
+ e_unknown,\r
+ e_above,\r
+ e_below\r
+ };\r
+\r
+ OneSidedPlatform()\r
+ {\r
+ // Ground\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Platform\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(0.0f, 10.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(3.0f, 0.5f);\r
+ m_platform = body->CreateFixture(&shape, 0.0f);\r
+\r
+ m_bottom = 10.0f - 0.5f;\r
+ m_top = 10.0f + 0.5f;\r
+ }\r
+\r
+ // Actor\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 12.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ m_radius = 0.5f;\r
+ b2CircleShape shape;\r
+ shape.m_radius = m_radius;\r
+ m_character = body->CreateFixture(&shape, 20.0f);\r
+\r
+ body->SetLinearVelocity(b2Vec2(0.0f, -50.0f));\r
+\r
+ m_state = e_unknown;\r
+ }\r
+ }\r
+\r
+ void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)\r
+ {\r
+ Test::PreSolve(contact, oldManifold);\r
+\r
+ b2Fixture* fixtureA = contact->GetFixtureA();\r
+ b2Fixture* fixtureB = contact->GetFixtureB();\r
+\r
+ if (fixtureA != m_platform && fixtureA != m_character)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (fixtureB != m_platform && fixtureB != m_character)\r
+ {\r
+ return;\r
+ }\r
+\r
+ b2Vec2 position = m_character->GetBody()->GetPosition();\r
+\r
+ if (position.y < m_top + m_radius - 3.0f * b2_linearSlop)\r
+ {\r
+ contact->SetEnabled(false);\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new OneSidedPlatform;\r
+ }\r
+\r
+ float32 m_radius, m_top, m_bottom;\r
+ State m_state;\r
+ b2Fixture* m_platform;\r
+ b2Fixture* m_character;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef PINBALL_H\r
+#define PINBALL_H\r
+\r
+/// This tests bullet collision and provides an example of a gameplay scenario.\r
+/// This also uses a loop shape.\r
+class Pinball : public Test\r
+{\r
+public:\r
+ Pinball()\r
+ {\r
+ // Ground body\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2Vec2 vs[5];\r
+ vs[0].Set(0.0f, -2.0f);\r
+ vs[1].Set(8.0f, 6.0f);\r
+ vs[2].Set(8.0f, 20.0f);\r
+ vs[3].Set(-8.0f, 20.0f);\r
+ vs[4].Set(-8.0f, 6.0f);\r
+\r
+ b2LoopShape loop;\r
+ loop.Create(vs, 5);\r
+ b2FixtureDef fd;\r
+ fd.shape = &loop;\r
+ fd.density = 0.0f;\r
+ ground->CreateFixture(&fd);\r
+ }\r
+\r
+ // Flippers\r
+ {\r
+ b2Vec2 p1(-2.0f, 0.0f), p2(2.0f, 0.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ bd.position = p1;\r
+ b2Body* leftFlipper = m_world->CreateBody(&bd);\r
+\r
+ bd.position = p2;\r
+ b2Body* rightFlipper = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape box;\r
+ box.SetAsBox(1.75f, 0.1f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &box;\r
+ fd.density = 1.0f;\r
+\r
+ leftFlipper->CreateFixture(&fd);\r
+ rightFlipper->CreateFixture(&fd);\r
+\r
+ b2RevoluteJointDef jd;\r
+ jd.bodyA = ground;\r
+ jd.localAnchorB.SetZero();\r
+ jd.enableMotor = true;\r
+ jd.maxMotorTorque = 1000.0f;\r
+ jd.enableLimit = true;\r
+\r
+ jd.motorSpeed = 0.0f;\r
+ jd.localAnchorA = p1;\r
+ jd.bodyB = leftFlipper;\r
+ jd.lowerAngle = -30.0f * b2_pi / 180.0f;\r
+ jd.upperAngle = 5.0f * b2_pi / 180.0f;\r
+ m_leftJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);\r
+\r
+ jd.motorSpeed = 0.0f;\r
+ jd.localAnchorA = p2;\r
+ jd.bodyB = rightFlipper;\r
+ jd.lowerAngle = -5.0f * b2_pi / 180.0f;\r
+ jd.upperAngle = 30.0f * b2_pi / 180.0f;\r
+ m_rightJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ // Circle character\r
+ {\r
+ b2BodyDef bd;\r
+ bd.position.Set(1.0f, 15.0f);\r
+ bd.type = b2_dynamicBody;\r
+ bd.bullet = true;\r
+\r
+ m_ball = m_world->CreateBody(&bd);\r
+\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.2f;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+ m_ball->CreateFixture(&fd);\r
+ }\r
+\r
+ m_button = false;\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ if (m_button)\r
+ {\r
+ m_leftJoint->SetMotorSpeed(20.0f);\r
+ m_rightJoint->SetMotorSpeed(-20.0f);\r
+ }\r
+ else\r
+ {\r
+ m_leftJoint->SetMotorSpeed(-10.0f);\r
+ m_rightJoint->SetMotorSpeed(10.0f);\r
+ }\r
+\r
+ Test::Step(settings);\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 'a' to control the flippers");\r
+ m_textLine += 15;\r
+\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'a':\r
+ case 'A':\r
+ m_button = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ void KeyboardUp(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'a':\r
+ case 'A':\r
+ m_button = false;\r
+ break;\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Pinball;\r
+ }\r
+\r
+ b2RevoluteJoint* m_leftJoint;\r
+ b2RevoluteJoint* m_rightJoint;\r
+ b2Body* m_ball;\r
+ bool m_button;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef POLYCOLLISION_H\r
+#define POLYCOLLISION_H\r
+\r
+class PolyCollision : public Test\r
+{\r
+public:\r
+ PolyCollision()\r
+ {\r
+ {\r
+ m_polygonA.SetAsBox(0.2f, 0.4f);\r
+ m_transformA.Set(b2Vec2(0.0f, 0.0f), 0.0f);\r
+ }\r
+\r
+ {\r
+ m_polygonB.SetAsBox(0.5f, 0.5f);\r
+ m_positionB.Set(19.345284f, 1.5632932f);\r
+ m_angleB = 1.9160721f;\r
+ m_transformB.Set(m_positionB, m_angleB);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new PolyCollision;\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ B2_NOT_USED(settings);\r
+\r
+ b2Manifold manifold;\r
+ b2CollidePolygons(&manifold, &m_polygonA, m_transformA, &m_polygonB, m_transformB);\r
+\r
+ b2WorldManifold worldManifold;\r
+ worldManifold.Initialize(&manifold, m_transformA, m_polygonA.m_radius, m_transformB, m_polygonB.m_radius);\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "point count = %d", manifold.pointCount);\r
+ m_textLine += 15;\r
+\r
+ {\r
+ b2Color color(0.9f, 0.9f, 0.9f);\r
+ b2Vec2 v[b2_maxPolygonVertices];\r
+ for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i)\r
+ {\r
+ v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color);\r
+\r
+ for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i)\r
+ {\r
+ v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color);\r
+ }\r
+\r
+ for (int32 i = 0; i < manifold.pointCount; ++i)\r
+ {\r
+ m_debugDraw.DrawPoint(worldManifold.points[i], 4.0f, b2Color(0.9f, 0.3f, 0.3f));\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'a':\r
+ m_positionB.x -= 0.1f;\r
+ break;\r
+\r
+ case 'd':\r
+ m_positionB.x += 0.1f;\r
+ break;\r
+\r
+ case 's':\r
+ m_positionB.y -= 0.1f;\r
+ break;\r
+\r
+ case 'w':\r
+ m_positionB.y += 0.1f;\r
+ break;\r
+\r
+ case 'q':\r
+ m_angleB += 0.1f * b2_pi;\r
+ break;\r
+\r
+ case 'e':\r
+ m_angleB -= 0.1f * b2_pi;\r
+ break;\r
+ }\r
+\r
+ m_transformB.Set(m_positionB, m_angleB);\r
+ }\r
+\r
+ b2PolygonShape m_polygonA;\r
+ b2PolygonShape m_polygonB;\r
+\r
+ b2Transform m_transformA;\r
+ b2Transform m_transformB;\r
+\r
+ b2Vec2 m_positionB;\r
+ float32 m_angleB;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef POLY_SHAPES_H\r
+#define POLY_SHAPES_H\r
+\r
+/// This tests stacking. It also shows how to use b2World::Query\r
+/// and b2TestOverlap.\r
+\r
+const int32 k_maxBodies = 256;\r
+\r
+/// This callback is called by b2World::QueryAABB. We find all the fixtures\r
+/// that overlap an AABB. Of those, we use b2TestOverlap to determine which fixtures\r
+/// overlap a circle. Up to 4 overlapped fixtures will be highlighted with a yellow border.\r
+class PolyShapesCallback : public b2QueryCallback\r
+{\r
+public:\r
+ \r
+ enum\r
+ {\r
+ e_maxCount = 4\r
+ };\r
+\r
+ PolyShapesCallback()\r
+ {\r
+ m_count = 0;\r
+ }\r
+\r
+ void DrawFixture(b2Fixture* fixture)\r
+ {\r
+ b2Color color(0.95f, 0.95f, 0.6f);\r
+ const b2Transform& xf = fixture->GetBody()->GetTransform();\r
+\r
+ switch (fixture->GetType())\r
+ {\r
+ case b2Shape::e_circle:\r
+ {\r
+ b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();\r
+\r
+ b2Vec2 center = b2Mul(xf, circle->m_p);\r
+ float32 radius = circle->m_radius;\r
+\r
+ m_debugDraw->DrawCircle(center, radius, color);\r
+ }\r
+ break;\r
+\r
+ case b2Shape::e_polygon:\r
+ {\r
+ b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();\r
+ int32 vertexCount = poly->m_vertexCount;\r
+ b2Assert(vertexCount <= b2_maxPolygonVertices);\r
+ b2Vec2 vertices[b2_maxPolygonVertices];\r
+\r
+ for (int32 i = 0; i < vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(xf, poly->m_vertices[i]);\r
+ }\r
+\r
+ m_debugDraw->DrawPolygon(vertices, vertexCount, color);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ /// Called for each fixture found in the query AABB.\r
+ /// @return false to terminate the query.\r
+ bool ReportFixture(b2Fixture* fixture)\r
+ {\r
+ if (m_count == e_maxCount)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ b2Body* body = fixture->GetBody();\r
+ b2Shape* shape = fixture->GetShape();\r
+\r
+ bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform);\r
+\r
+ if (overlap)\r
+ {\r
+ DrawFixture(fixture);\r
+ ++m_count;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ b2CircleShape m_circle;\r
+ b2Transform m_transform;\r
+ b2Draw* m_debugDraw;\r
+ int32 m_count;\r
+};\r
+\r
+class PolyShapes : public Test\r
+{\r
+public:\r
+ PolyShapes()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.5f, 0.0f);\r
+ vertices[1].Set(0.5f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+ m_polygons[0].Set(vertices, 3);\r
+ }\r
+ \r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.1f, 0.0f);\r
+ vertices[1].Set(0.1f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+ m_polygons[1].Set(vertices, 3);\r
+ }\r
+\r
+ {\r
+ float32 w = 1.0f;\r
+ float32 b = w / (2.0f + b2Sqrt(2.0f));\r
+ float32 s = b2Sqrt(2.0f) * b;\r
+\r
+ b2Vec2 vertices[8];\r
+ vertices[0].Set(0.5f * s, 0.0f);\r
+ vertices[1].Set(0.5f * w, b);\r
+ vertices[2].Set(0.5f * w, b + s);\r
+ vertices[3].Set(0.5f * s, w);\r
+ vertices[4].Set(-0.5f * s, w);\r
+ vertices[5].Set(-0.5f * w, b + s);\r
+ vertices[6].Set(-0.5f * w, b);\r
+ vertices[7].Set(-0.5f * s, 0.0f);\r
+\r
+ m_polygons[2].Set(vertices, 8);\r
+ }\r
+\r
+ {\r
+ m_polygons[3].SetAsBox(0.5f, 0.5f);\r
+ }\r
+\r
+ {\r
+ m_circle.m_radius = 0.5f;\r
+ }\r
+\r
+ m_bodyIndex = 0;\r
+ memset(m_bodies, 0, sizeof(m_bodies));\r
+ }\r
+\r
+ void Create(int32 index)\r
+ {\r
+ if (m_bodies[m_bodyIndex] != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bodies[m_bodyIndex]);\r
+ m_bodies[m_bodyIndex] = NULL;\r
+ }\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ float32 x = RandomFloat(-2.0f, 2.0f);\r
+ bd.position.Set(x, 10.0f);\r
+ bd.angle = RandomFloat(-b2_pi, b2_pi);\r
+\r
+ if (index == 4)\r
+ {\r
+ bd.angularDamping = 0.02f;\r
+ }\r
+\r
+ m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);\r
+\r
+ if (index < 4)\r
+ {\r
+ b2FixtureDef fd;\r
+ fd.shape = m_polygons + index;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.3f;\r
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);\r
+ }\r
+ else\r
+ {\r
+ b2FixtureDef fd;\r
+ fd.shape = &m_circle;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.3f;\r
+\r
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);\r
+ }\r
+\r
+ m_bodyIndex = (m_bodyIndex + 1) % k_maxBodies;\r
+ }\r
+\r
+ void DestroyBody()\r
+ {\r
+ for (int32 i = 0; i < k_maxBodies; ++i)\r
+ {\r
+ if (m_bodies[i] != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bodies[i]);\r
+ m_bodies[i] = NULL;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case '1':\r
+ case '2':\r
+ case '3':\r
+ case '4':\r
+ case '5':\r
+ Create(key - '1');\r
+ break;\r
+\r
+ case 'a':\r
+ for (int32 i = 0; i < k_maxBodies; i += 2)\r
+ {\r
+ if (m_bodies[i])\r
+ {\r
+ bool active = m_bodies[i]->IsActive();\r
+ m_bodies[i]->SetActive(!active);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case 'd':\r
+ DestroyBody();\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ PolyShapesCallback callback;\r
+ callback.m_circle.m_radius = 2.0f;\r
+ callback.m_circle.m_p.Set(0.0f, 2.1f);\r
+ callback.m_transform.SetIdentity();\r
+ callback.m_debugDraw = &m_debugDraw;\r
+\r
+ b2AABB aabb;\r
+ callback.m_circle.ComputeAABB(&aabb, callback.m_transform, 0);\r
+\r
+ m_world->QueryAABB(&callback, aabb);\r
+\r
+ b2Color color(0.4f, 0.7f, 0.8f);\r
+ m_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color);\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 'a' to (de)activate some bodies");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 'd' to destroy a body");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new PolyShapes;\r
+ }\r
+\r
+ int32 m_bodyIndex;\r
+ b2Body* m_bodies[k_maxBodies];\r
+ b2PolygonShape m_polygons[4];\r
+ b2CircleShape m_circle;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef PRISMATIC_H\r
+#define PRISMATIC_H\r
+\r
+class Prismatic : public Test\r
+{\r
+public:\r
+ Prismatic()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(2.0f, 0.5f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-10.0f, 10.0f);\r
+ bd.angle = 0.5f * b2_pi;\r
+ bd.allowSleep = false;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 5.0f);\r
+\r
+ b2PrismaticJointDef pjd;\r
+\r
+ // Bouncy limit\r
+ b2Vec2 axis(2.0f, 1.0f);\r
+ axis.Normalize();\r
+ pjd.Initialize(ground, body, b2Vec2(0.0f, 0.0f), axis);\r
+\r
+ // Non-bouncy limit\r
+ //pjd.Initialize(ground, body, b2Vec2(-10.0f, 10.0f), b2Vec2(1.0f, 0.0f));\r
+\r
+ pjd.motorSpeed = 10.0f;\r
+ pjd.maxMotorForce = 10000.0f;\r
+ pjd.enableMotor = true;\r
+ pjd.lowerTranslation = 0.0f;\r
+ pjd.upperTranslation = 20.0f;\r
+ pjd.enableLimit = true;\r
+\r
+ m_joint = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'l':\r
+ m_joint->EnableLimit(!m_joint->IsLimitEnabled());\r
+ break;\r
+\r
+ case 'm':\r
+ m_joint->EnableMotor(!m_joint->IsMotorEnabled());\r
+ break;\r
+\r
+ case 's':\r
+ m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed());\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motors, (s) speed");\r
+ m_textLine += 15;\r
+ float32 force = m_joint->GetMotorForce(settings->hz);\r
+ m_debugDraw.DrawString(5, m_textLine, "Motor Force = %4.0f", (float) force);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Prismatic;\r
+ }\r
+\r
+ b2PrismaticJoint* m_joint;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef PULLEYS_H\r
+#define PULLEYS_H\r
+\r
+class Pulleys : public Test\r
+{\r
+public:\r
+ Pulleys()\r
+ {\r
+ float32 y = 16.0f;\r
+ float32 L = 12.0f;\r
+ float32 a = 1.0f;\r
+ float32 b = 2.0f;\r
+\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape edge;\r
+ edge.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ //ground->CreateFixture(&shape, 0.0f);\r
+\r
+ b2CircleShape circle;\r
+ circle.m_radius = 2.0f;\r
+\r
+ circle.m_p.Set(-10.0f, y + b + L);\r
+ ground->CreateFixture(&circle, 0.0f);\r
+\r
+ circle.m_p.Set(10.0f, y + b + L);\r
+ ground->CreateFixture(&circle, 0.0f);\r
+ }\r
+\r
+ {\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(a, b);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ //bd.fixedRotation = true;\r
+ bd.position.Set(-10.0f, y);\r
+ b2Body* body1 = m_world->CreateBody(&bd);\r
+ body1->CreateFixture(&shape, 5.0f);\r
+\r
+ bd.position.Set(10.0f, y);\r
+ b2Body* body2 = m_world->CreateBody(&bd);\r
+ body2->CreateFixture(&shape, 5.0f);\r
+\r
+ b2PulleyJointDef pulleyDef;\r
+ b2Vec2 anchor1(-10.0f, y + b);\r
+ b2Vec2 anchor2(10.0f, y + b);\r
+ b2Vec2 groundAnchor1(-10.0f, y + b + L);\r
+ b2Vec2 groundAnchor2(10.0f, y + b + L);\r
+ pulleyDef.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 1.5f);\r
+\r
+ m_joint1 = (b2PulleyJoint*)m_world->CreateJoint(&pulleyDef);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 0:\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ float32 ratio = m_joint1->GetRatio();\r
+ float32 L = m_joint1->GetLength1() + ratio * m_joint1->GetLength2();\r
+ m_debugDraw.DrawString(5, m_textLine, "L1 + %4.2f * L2 = %4.2f", (float) ratio, (float) L);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Pulleys;\r
+ }\r
+\r
+ b2PulleyJoint* m_joint1;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef PYRAMID_H\r
+#define PYRAMID_H\r
+\r
+class Pyramid : public Test\r
+{\r
+public:\r
+ enum\r
+ {\r
+ e_count = 20\r
+ };\r
+\r
+ Pyramid()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ float32 a = 0.5f;\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(a, a);\r
+\r
+ b2Vec2 x(-7.0f, 0.75f);\r
+ b2Vec2 y;\r
+ b2Vec2 deltaX(0.5625f, 1.25f);\r
+ b2Vec2 deltaY(1.125f, 0.0f);\r
+\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ y = x;\r
+\r
+ for (int32 j = i; j < e_count; ++j)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position = y;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 5.0f);\r
+\r
+ y += deltaY;\r
+ }\r
+\r
+ x += deltaX;\r
+ }\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ //b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;\r
+\r
+ //if (m_stepCount == 400)\r
+ //{\r
+ // tree->RebuildBottomUp();\r
+ //}\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Pyramid;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef RAY_CAST_H\r
+#define RAY_CAST_H\r
+\r
+// This test demonstrates how to use the world ray-cast feature.\r
+// NOTE: we are intentionally filtering one of the polygons, therefore\r
+// the ray will always miss one type of polygon.\r
+\r
+// This callback finds the closest hit. Polygon 0 is filtered.\r
+class RayCastClosestCallback : public b2RayCastCallback\r
+{\r
+public:\r
+ RayCastClosestCallback()\r
+ {\r
+ m_hit = false;\r
+ }\r
+\r
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,\r
+ const b2Vec2& normal, float32 fraction)\r
+ {\r
+ b2Body* body = fixture->GetBody();\r
+ void* userData = body->GetUserData();\r
+ if (userData)\r
+ {\r
+ int32 index = *(int32*)userData;\r
+ if (index == 0)\r
+ {\r
+ // filter\r
+ return -1.0f;\r
+ }\r
+ }\r
+\r
+ m_hit = true;\r
+ m_point = point;\r
+ m_normal = normal;\r
+ return fraction;\r
+ }\r
+ \r
+ bool m_hit;\r
+ b2Vec2 m_point;\r
+ b2Vec2 m_normal;\r
+};\r
+\r
+// This callback finds any hit. Polygon 0 is filtered.\r
+class RayCastAnyCallback : public b2RayCastCallback\r
+{\r
+public:\r
+ RayCastAnyCallback()\r
+ {\r
+ m_hit = false;\r
+ }\r
+\r
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,\r
+ const b2Vec2& normal, float32 fraction)\r
+ {\r
+ b2Body* body = fixture->GetBody();\r
+ void* userData = body->GetUserData();\r
+ if (userData)\r
+ {\r
+ int32 index = *(int32*)userData;\r
+ if (index == 0)\r
+ {\r
+ // filter\r
+ return -1.0f;\r
+ }\r
+ }\r
+\r
+ m_hit = true;\r
+ m_point = point;\r
+ m_normal = normal;\r
+ return 0.0f;\r
+ }\r
+\r
+ bool m_hit;\r
+ b2Vec2 m_point;\r
+ b2Vec2 m_normal;\r
+};\r
+\r
+// This ray cast collects multiple hits along the ray. Polygon 0 is filtered.\r
+class RayCastMultipleCallback : public b2RayCastCallback\r
+{\r
+public:\r
+ enum\r
+ {\r
+ e_maxCount = 3\r
+ };\r
+\r
+ RayCastMultipleCallback()\r
+ {\r
+ m_count = 0;\r
+ }\r
+\r
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,\r
+ const b2Vec2& normal, float32 fraction)\r
+ {\r
+ b2Body* body = fixture->GetBody();\r
+ int32 index = 0;\r
+ void* userData = body->GetUserData();\r
+ if (userData)\r
+ {\r
+ int32 index = *(int32*)userData;\r
+ if (index == 0)\r
+ {\r
+ // filter\r
+ return -1.0f;\r
+ }\r
+ }\r
+\r
+ b2Assert(m_count < e_maxCount);\r
+\r
+ m_points[m_count] = point;\r
+ m_normals[m_count] = normal;\r
+ ++m_count;\r
+\r
+ if (m_count == e_maxCount)\r
+ {\r
+ return 0.0f;\r
+ }\r
+\r
+ return 1.0f;\r
+ }\r
+\r
+ b2Vec2 m_points[e_maxCount];\r
+ b2Vec2 m_normals[e_maxCount];\r
+ int32 m_count;\r
+};\r
+\r
+\r
+class RayCast : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_maxBodies = 256\r
+ };\r
+\r
+ enum Mode\r
+ {\r
+ e_closest,\r
+ e_any,\r
+ e_multiple\r
+ };\r
+\r
+ RayCast()\r
+ {\r
+ // Ground body\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.5f, 0.0f);\r
+ vertices[1].Set(0.5f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+ m_polygons[0].Set(vertices, 3);\r
+ }\r
+\r
+ {\r
+ b2Vec2 vertices[3];\r
+ vertices[0].Set(-0.1f, 0.0f);\r
+ vertices[1].Set(0.1f, 0.0f);\r
+ vertices[2].Set(0.0f, 1.5f);\r
+ m_polygons[1].Set(vertices, 3);\r
+ }\r
+\r
+ {\r
+ float32 w = 1.0f;\r
+ float32 b = w / (2.0f + b2Sqrt(2.0f));\r
+ float32 s = b2Sqrt(2.0f) * b;\r
+\r
+ b2Vec2 vertices[8];\r
+ vertices[0].Set(0.5f * s, 0.0f);\r
+ vertices[1].Set(0.5f * w, b);\r
+ vertices[2].Set(0.5f * w, b + s);\r
+ vertices[3].Set(0.5f * s, w);\r
+ vertices[4].Set(-0.5f * s, w);\r
+ vertices[5].Set(-0.5f * w, b + s);\r
+ vertices[6].Set(-0.5f * w, b);\r
+ vertices[7].Set(-0.5f * s, 0.0f);\r
+\r
+ m_polygons[2].Set(vertices, 8);\r
+ }\r
+\r
+ {\r
+ m_polygons[3].SetAsBox(0.5f, 0.5f);\r
+ }\r
+\r
+ {\r
+ m_circle.m_radius = 0.5f;\r
+ }\r
+\r
+ m_bodyIndex = 0;\r
+ memset(m_bodies, 0, sizeof(m_bodies));\r
+\r
+ m_angle = 0.0f;\r
+\r
+ m_mode = e_closest;\r
+ }\r
+\r
+ void Create(int32 index)\r
+ {\r
+ if (m_bodies[m_bodyIndex] != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bodies[m_bodyIndex]);\r
+ m_bodies[m_bodyIndex] = NULL;\r
+ }\r
+\r
+ b2BodyDef bd;\r
+\r
+ float32 x = RandomFloat(-10.0f, 10.0f);\r
+ float32 y = RandomFloat(0.0f, 20.0f);\r
+ bd.position.Set(x, y);\r
+ bd.angle = RandomFloat(-b2_pi, b2_pi);\r
+\r
+ m_userData[m_bodyIndex] = index;\r
+ bd.userData = m_userData + m_bodyIndex;\r
+\r
+ if (index == 4)\r
+ {\r
+ bd.angularDamping = 0.02f;\r
+ }\r
+\r
+ m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);\r
+\r
+ if (index < 4)\r
+ {\r
+ b2FixtureDef fd;\r
+ fd.shape = m_polygons + index;\r
+ fd.friction = 0.3f;\r
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);\r
+ }\r
+ else\r
+ {\r
+ b2FixtureDef fd;\r
+ fd.shape = &m_circle;\r
+ fd.friction = 0.3f;\r
+\r
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);\r
+ }\r
+\r
+ m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;\r
+ }\r
+\r
+ void DestroyBody()\r
+ {\r
+ for (int32 i = 0; i < e_maxBodies; ++i)\r
+ {\r
+ if (m_bodies[i] != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bodies[i]);\r
+ m_bodies[i] = NULL;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case '1':\r
+ case '2':\r
+ case '3':\r
+ case '4':\r
+ case '5':\r
+ Create(key - '1');\r
+ break;\r
+\r
+ case 'd':\r
+ DestroyBody();\r
+ break;\r
+\r
+ case 'm':\r
+ if (m_mode == e_closest)\r
+ {\r
+ m_mode = e_any;\r
+ }\r
+ else if (m_mode == e_any)\r
+ {\r
+ m_mode = e_multiple;\r
+ }\r
+ else if (m_mode = e_multiple)\r
+ {\r
+ m_mode = e_closest;\r
+ }\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ bool advanceRay = settings->pause == 0 || settings->singleStep;\r
+\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff, m to change the mode");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Mode = %d", m_mode);\r
+ m_textLine += 15;\r
+\r
+ float32 L = 11.0f;\r
+ b2Vec2 point1(0.0f, 10.0f);\r
+ b2Vec2 d(L * cosf(m_angle), L * sinf(m_angle));\r
+ b2Vec2 point2 = point1 + d;\r
+\r
+ if (m_mode == e_closest)\r
+ {\r
+ RayCastClosestCallback callback;\r
+ m_world->RayCast(&callback, point1, point2);\r
+\r
+ if (callback.m_hit)\r
+ {\r
+ m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));\r
+ m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));\r
+ b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;\r
+ m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));\r
+ }\r
+ else\r
+ {\r
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));\r
+ }\r
+ }\r
+ else if (m_mode == e_any)\r
+ {\r
+ RayCastAnyCallback callback;\r
+ m_world->RayCast(&callback, point1, point2);\r
+\r
+ if (callback.m_hit)\r
+ {\r
+ m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));\r
+ m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));\r
+ b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;\r
+ m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));\r
+ }\r
+ else\r
+ {\r
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));\r
+ }\r
+ }\r
+ else if (m_mode == e_multiple)\r
+ {\r
+ RayCastMultipleCallback callback;\r
+ m_world->RayCast(&callback, point1, point2);\r
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));\r
+\r
+ for (int32 i = 0; i < callback.m_count; ++i)\r
+ {\r
+ b2Vec2 p = callback.m_points[i];\r
+ b2Vec2 n = callback.m_normals[i];\r
+ m_debugDraw.DrawPoint(p, 5.0f, b2Color(0.4f, 0.9f, 0.4f));\r
+ m_debugDraw.DrawSegment(point1, p, b2Color(0.8f, 0.8f, 0.8f));\r
+ b2Vec2 head = p + 0.5f * n;\r
+ m_debugDraw.DrawSegment(p, head, b2Color(0.9f, 0.9f, 0.4f));\r
+ }\r
+ }\r
+\r
+ if (advanceRay)\r
+ {\r
+ m_angle += 0.25f * b2_pi / 180.0f;\r
+ }\r
+\r
+#if 0\r
+ // This case was failing.\r
+ {\r
+ b2Vec2 vertices[4];\r
+ //vertices[0].Set(-22.875f, -3.0f);\r
+ //vertices[1].Set(22.875f, -3.0f);\r
+ //vertices[2].Set(22.875f, 3.0f);\r
+ //vertices[3].Set(-22.875f, 3.0f);\r
+\r
+ b2PolygonShape shape;\r
+ //shape.Set(vertices, 4);\r
+ shape.SetAsBox(22.875f, 3.0f);\r
+\r
+ b2RayCastInput input;\r
+ input.p1.Set(10.2725f,1.71372f);\r
+ input.p2.Set(10.2353f,2.21807f);\r
+ //input.maxFraction = 0.567623f;\r
+ input.maxFraction = 0.56762173f;\r
+\r
+ b2Transform xf;\r
+ xf.SetIdentity();\r
+ xf.position.Set(23.0f, 5.0f);\r
+\r
+ b2RayCastOutput output;\r
+ bool hit;\r
+ hit = shape.RayCast(&output, input, xf);\r
+ hit = false;\r
+\r
+ b2Color color(1.0f, 1.0f, 1.0f);\r
+ b2Vec2 vs[4];\r
+ for (int32 i = 0; i < 4; ++i)\r
+ {\r
+ vs[i] = b2Mul(xf, shape.m_vertices[i]);\r
+ }\r
+\r
+ m_debugDraw.DrawPolygon(vs, 4, color);\r
+ m_debugDraw.DrawSegment(input.p1, input.p2, color);\r
+ }\r
+#endif\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new RayCast;\r
+ }\r
+\r
+ int32 m_bodyIndex;\r
+ b2Body* m_bodies[e_maxBodies];\r
+ int32 m_userData[e_maxBodies];\r
+ b2PolygonShape m_polygons[4];\r
+ b2CircleShape m_circle;\r
+\r
+ float32 m_angle;\r
+\r
+ Mode m_mode;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef REVOLUTE_H\r
+#define REVOLUTE_H\r
+\r
+class Revolute : public Test\r
+{\r
+public:\r
+ Revolute()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ //fd.filter.categoryBits = 2;\r
+\r
+ ground->CreateFixture(&fd);\r
+ }\r
+\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.5f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ b2RevoluteJointDef rjd;\r
+\r
+ bd.position.Set(-10.0f, 20.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 5.0f);\r
+\r
+ float32 w = 100.0f;\r
+ body->SetAngularVelocity(w);\r
+ body->SetLinearVelocity(b2Vec2(-8.0f * w, 0.0f));\r
+\r
+ rjd.Initialize(ground, body, b2Vec2(-10.0f, 12.0f));\r
+ rjd.motorSpeed = 1.0f * b2_pi;\r
+ rjd.maxMotorTorque = 10000.0f;\r
+ rjd.enableMotor = false;\r
+ rjd.lowerAngle = -0.25f * b2_pi;\r
+ rjd.upperAngle = 0.5f * b2_pi;\r
+ rjd.enableLimit = true;\r
+ rjd.collideConnected = true;\r
+\r
+ m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);\r
+ }\r
+\r
+ {\r
+ b2CircleShape circle_shape;\r
+ circle_shape.m_radius = 3.0f;\r
+\r
+ b2BodyDef circle_bd;\r
+ circle_bd.type = b2_dynamicBody;\r
+ circle_bd.position.Set(5.0f, 30.0f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.density = 5.0f;\r
+ fd.filter.maskBits = 1;\r
+ fd.shape = &circle_shape;\r
+\r
+ m_ball = m_world->CreateBody(&circle_bd);\r
+ m_ball->CreateFixture(&fd);\r
+\r
+ b2PolygonShape polygon_shape;\r
+ polygon_shape.SetAsBox(10.0f, 0.2f, b2Vec2 (-10.0f, 0.0f), 0.0f);\r
+\r
+ b2BodyDef polygon_bd;\r
+ polygon_bd.position.Set(20.0f, 10.0f);\r
+ polygon_bd.type = b2_dynamicBody;\r
+ polygon_bd.bullet = true;\r
+ b2Body* polygon_body = m_world->CreateBody(&polygon_bd);\r
+ polygon_body->CreateFixture(&polygon_shape, 2.0f);\r
+\r
+ b2RevoluteJointDef rjd;\r
+ rjd.Initialize(ground, polygon_body, b2Vec2(20.0f, 10.0f));\r
+ rjd.lowerAngle = -0.25f * b2_pi;\r
+ rjd.upperAngle = 0.0f * b2_pi;\r
+ rjd.enableLimit = true;\r
+ m_world->CreateJoint(&rjd);\r
+ }\r
+\r
+ // Tests mass computation of a small object far from the origin\r
+ {\r
+ b2BodyDef bodyDef;\r
+ bodyDef.type = b2_dynamicBody;\r
+ b2Body* body = m_world->CreateBody(&bodyDef);\r
+ \r
+ b2PolygonShape polyShape; \r
+ b2Vec2 verts[3];\r
+ verts[0].Set( 17.63f, 36.31f );\r
+ verts[1].Set( 17.52f, 36.69f );\r
+ verts[2].Set( 17.19f, 36.36f );\r
+ polyShape.Set(verts, 3);\r
+ \r
+ b2FixtureDef polyFixtureDef;\r
+ polyFixtureDef.shape = &polyShape;\r
+ polyFixtureDef.density = 1;\r
+\r
+ body->CreateFixture(&polyFixtureDef); //assertion hits inside here\r
+ }\r
+\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'l':\r
+ m_joint->EnableLimit(!m_joint->IsLimitEnabled());\r
+ break;\r
+\r
+ case 'm':\r
+ m_joint->EnableMotor(!m_joint->IsMotorEnabled());\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motor");\r
+ m_textLine += 15;\r
+\r
+ //if (m_stepCount == 360)\r
+ //{\r
+ // m_ball->SetTransform(b2Vec2(0.0f, 0.5f), 0.0f);\r
+ //}\r
+\r
+ //float32 torque1 = m_joint1->GetMotorTorque();\r
+ //m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %4.0f, %4.0f : Motor Force = %4.0f", (float) torque1, (float) torque2, (float) force3);\r
+ //m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Revolute;\r
+ }\r
+\r
+ b2Body* m_ball;\r
+ b2RevoluteJoint* m_joint;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2011 Erin Catto http://box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef ROPE_H\r
+#define ROPE_H\r
+\r
+///\r
+class Rope : public Test\r
+{\r
+public:\r
+ Rope()\r
+ {\r
+ const int32 N = 40;\r
+ b2Vec2 vertices[N];\r
+ float32 masses[N];\r
+\r
+ for (int32 i = 0; i < N; ++i)\r
+ {\r
+ vertices[i].Set(0.0f, 20.0f - 0.25f * i);\r
+ masses[i] = 1.0f;\r
+ }\r
+ masses[0] = 0.0f;\r
+ masses[1] = 0.0f;\r
+\r
+ b2RopeDef def;\r
+ def.vertices = vertices;\r
+ def.count = N;\r
+ def.gravity.Set(0.0f, -10.0f);\r
+ def.masses = masses;\r
+ def.damping = 0.1f;\r
+ def.k2 = 1.0f;\r
+ def.k3 = 0.5f;\r
+\r
+ m_rope.Initialize(&def);\r
+\r
+ m_angle = 0.0f;\r
+ m_rope.SetAngle(m_angle);\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'q':\r
+ m_angle = b2Max(-b2_pi, m_angle - 0.05f * b2_pi);\r
+ m_rope.SetAngle(m_angle);\r
+ break;\r
+\r
+ case 'e':\r
+ m_angle = b2Min(b2_pi, m_angle + 0.05f * b2_pi);\r
+ m_rope.SetAngle(m_angle);\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ float32 dt = settings->hz > 0.0f ? 1.0f / settings->hz : 0.0f;\r
+\r
+ if (settings->pause == 1 && settings->singleStep == 0)\r
+ {\r
+ dt = 0.0f;\r
+ }\r
+\r
+ m_rope.Step(dt, 1);\r
+\r
+ Test::Step(settings);\r
+\r
+ m_rope.Draw(&m_debugDraw);\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "Press (q,e) to adjust target angle");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Target angle = %g degrees", m_angle * 180.0f / b2_pi);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Rope;\r
+ }\r
+\r
+ b2Rope m_rope;\r
+ float32 m_angle;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef ROPE_JOINT_H\r
+#define ROPE_JOINT_H\r
+\r
+/// This test shows how a rope joint can be used to stabilize a chain of\r
+/// bodies with a heavy payload. Notice that the rope joint just prevents\r
+/// excessive stretching and has no other effect.\r
+/// By disabling the rope joint you can see that the Box2D solver has trouble\r
+/// supporting heavy bodies with light bodies. Try playing around with the\r
+/// densities, time step, and iterations to see how they affect stability.\r
+/// This test also shows how to use contact filtering. Filtering is configured\r
+/// so that the payload does not collide with the chain.\r
+class RopeJoint : public Test\r
+{\r
+public:\r
+ RopeJoint()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.125f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ fd.friction = 0.2f;\r
+ fd.filter.categoryBits = 0x0001;\r
+ fd.filter.maskBits = 0xFFFF & ~0x0002;\r
+\r
+ b2RevoluteJointDef jd;\r
+ jd.collideConnected = false;\r
+\r
+ const int32 N = 10;\r
+ const float32 y = 15.0f;\r
+ m_ropeDef.localAnchorA.Set(0.0f, y);\r
+\r
+ b2Body* prevBody = ground;\r
+ for (int32 i = 0; i < N; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.5f + 1.0f * i, y);\r
+ if (i == N - 1)\r
+ {\r
+ shape.SetAsBox(1.5f, 1.5f);\r
+ fd.density = 100.0f;\r
+ fd.filter.categoryBits = 0x0002;\r
+ bd.position.Set(1.0f * i, y);\r
+ bd.angularDamping = 0.4f;\r
+ }\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ body->CreateFixture(&fd);\r
+\r
+ b2Vec2 anchor(float32(i), y);\r
+ jd.Initialize(prevBody, body, anchor);\r
+ m_world->CreateJoint(&jd);\r
+\r
+ prevBody = body;\r
+ }\r
+\r
+ m_ropeDef.localAnchorB.SetZero();\r
+\r
+ float32 extraLength = 0.01f;\r
+ m_ropeDef.maxLength = N - 1.0f + extraLength;\r
+ m_ropeDef.bodyB = prevBody;\r
+ }\r
+\r
+ {\r
+ m_ropeDef.bodyA = ground;\r
+ m_rope = m_world->CreateJoint(&m_ropeDef);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'j':\r
+ if (m_rope)\r
+ {\r
+ m_world->DestroyJoint(m_rope);\r
+ m_rope = NULL;\r
+ }\r
+ else\r
+ {\r
+ m_rope = m_world->CreateJoint(&m_ropeDef);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Press (j) to toggle the rope joint.");\r
+ m_textLine += 15;\r
+ if (m_rope)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "Rope ON");\r
+ }\r
+ else\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "Rope OFF");\r
+ }\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new RopeJoint;\r
+ }\r
+\r
+ b2RopeJointDef m_ropeDef;\r
+ b2Joint* m_rope;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef SENSOR_TEST_H\r
+#define SENSOR_TEST_H\r
+\r
+// This is used to test sensor shapes.\r
+class SensorTest : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_count = 7\r
+ };\r
+\r
+ SensorTest()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ {\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+#if 0\r
+ {\r
+ b2FixtureDef sd;\r
+ sd.SetAsBox(10.0f, 2.0f, b2Vec2(0.0f, 20.0f), 0.0f);\r
+ sd.isSensor = true;\r
+ m_sensor = ground->CreateFixture(&sd);\r
+ }\r
+#else\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 5.0f;\r
+ shape.m_p.Set(0.0f, 10.0f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.isSensor = true;\r
+ m_sensor = ground->CreateFixture(&fd);\r
+ }\r
+#endif\r
+ }\r
+\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 1.0f;\r
+\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-10.0f + 3.0f * i, 20.0f);\r
+ bd.userData = m_touching + i;\r
+\r
+ m_touching[i] = false;\r
+ m_bodies[i] = m_world->CreateBody(&bd);\r
+\r
+ m_bodies[i]->CreateFixture(&shape, 1.0f);\r
+ }\r
+ }\r
+ }\r
+\r
+ // Implement contact listener.\r
+ void BeginContact(b2Contact* contact)\r
+ {\r
+ b2Fixture* fixtureA = contact->GetFixtureA();\r
+ b2Fixture* fixtureB = contact->GetFixtureB();\r
+\r
+ if (fixtureA == m_sensor)\r
+ {\r
+ void* userData = fixtureB->GetBody()->GetUserData();\r
+ if (userData)\r
+ {\r
+ bool* touching = (bool*)userData;\r
+ *touching = true;\r
+ }\r
+ }\r
+\r
+ if (fixtureB == m_sensor)\r
+ {\r
+ void* userData = fixtureA->GetBody()->GetUserData();\r
+ if (userData)\r
+ {\r
+ bool* touching = (bool*)userData;\r
+ *touching = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Implement contact listener.\r
+ void EndContact(b2Contact* contact)\r
+ {\r
+ b2Fixture* fixtureA = contact->GetFixtureA();\r
+ b2Fixture* fixtureB = contact->GetFixtureB();\r
+\r
+ if (fixtureA == m_sensor)\r
+ {\r
+ void* userData = fixtureB->GetBody()->GetUserData();\r
+ if (userData)\r
+ {\r
+ bool* touching = (bool*)userData;\r
+ *touching = false;\r
+ }\r
+ }\r
+\r
+ if (fixtureB == m_sensor)\r
+ {\r
+ void* userData = fixtureA->GetBody()->GetUserData();\r
+ if (userData)\r
+ {\r
+ bool* touching = (bool*)userData;\r
+ *touching = false;\r
+ }\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ // Traverse the contact results. Apply a force on shapes\r
+ // that overlap the sensor.\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ if (m_touching[i] == false)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ b2Body* body = m_bodies[i];\r
+ b2Body* ground = m_sensor->GetBody();\r
+\r
+ b2CircleShape* circle = (b2CircleShape*)m_sensor->GetShape();\r
+ b2Vec2 center = ground->GetWorldPoint(circle->m_p);\r
+\r
+ b2Vec2 position = body->GetPosition();\r
+\r
+ b2Vec2 d = center - position;\r
+ if (d.LengthSquared() < FLT_EPSILON * FLT_EPSILON)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ d.Normalize();\r
+ b2Vec2 F = 100.0f * d;\r
+ body->ApplyForce(F, position);\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new SensorTest;\r
+ }\r
+\r
+ b2Fixture* m_sensor;\r
+ b2Body* m_bodies[e_count];\r
+ bool m_touching[e_count];\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef SHAPE_EDITING_H\r
+#define SHAPE_EDITING_H\r
+\r
+class ShapeEditing : public Test\r
+{\r
+public:\r
+\r
+ ShapeEditing()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 10.0f);\r
+ m_body = m_world->CreateBody(&bd);\r
+\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(4.0f, 4.0f, b2Vec2(0.0f, 0.0f), 0.0f);\r
+ m_fixture1 = m_body->CreateFixture(&shape, 10.0f);\r
+\r
+ m_fixture2 = NULL;\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'c':\r
+ if (m_fixture2 == NULL)\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 3.0f;\r
+ shape.m_p.Set(0.5f, -4.0f);\r
+ m_fixture2 = m_body->CreateFixture(&shape, 10.0f);\r
+ m_body->SetAwake(true);\r
+ }\r
+ break;\r
+\r
+ case 'd':\r
+ if (m_fixture2 != NULL)\r
+ {\r
+ m_body->DestroyFixture(m_fixture2);\r
+ m_fixture2 = NULL;\r
+ m_body->SetAwake(true);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new ShapeEditing;\r
+ }\r
+\r
+ b2Body* m_body;\r
+ b2Fixture* m_fixture1;\r
+ b2Fixture* m_fixture2;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef SLIDER_CRANK_H\r
+#define SLIDER_CRANK_H\r
+\r
+// A motor driven slider crank with joint friction.\r
+\r
+class SliderCrank : public Test\r
+{\r
+public:\r
+ SliderCrank()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2Body* prevBody = ground;\r
+\r
+ // Define crank.\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 2.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 7.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 2.0f);\r
+\r
+ b2RevoluteJointDef rjd;\r
+ rjd.Initialize(prevBody, body, b2Vec2(0.0f, 5.0f));\r
+ rjd.motorSpeed = 1.0f * b2_pi;\r
+ rjd.maxMotorTorque = 10000.0f;\r
+ rjd.enableMotor = true;\r
+ m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);\r
+\r
+ prevBody = body;\r
+ }\r
+\r
+ // Define follower.\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 4.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 13.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 2.0f);\r
+\r
+ b2RevoluteJointDef rjd;\r
+ rjd.Initialize(prevBody, body, b2Vec2(0.0f, 9.0f));\r
+ rjd.enableMotor = false;\r
+ m_world->CreateJoint(&rjd);\r
+\r
+ prevBody = body;\r
+ }\r
+\r
+ // Define piston\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(1.5f, 1.5f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.fixedRotation = true;\r
+ bd.position.Set(0.0f, 17.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 2.0f);\r
+\r
+ b2RevoluteJointDef rjd;\r
+ rjd.Initialize(prevBody, body, b2Vec2(0.0f, 17.0f));\r
+ m_world->CreateJoint(&rjd);\r
+\r
+ b2PrismaticJointDef pjd;\r
+ pjd.Initialize(ground, body, b2Vec2(0.0f, 17.0f), b2Vec2(0.0f, 1.0f));\r
+\r
+ pjd.maxMotorForce = 1000.0f;\r
+ pjd.enableMotor = true;\r
+\r
+ m_joint2 = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);\r
+ }\r
+\r
+ // Create a payload\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(1.5f, 1.5f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0f, 23.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 2.0f);\r
+ }\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'f':\r
+ m_joint2->EnableMotor(!m_joint2->IsMotorEnabled());\r
+ m_joint2->GetBodyB()->SetAwake(true);\r
+ break;\r
+\r
+ case 'm':\r
+ m_joint1->EnableMotor(!m_joint1->IsMotorEnabled());\r
+ m_joint1->GetBodyB()->SetAwake(true);\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (f) toggle friction, (m) toggle motor");\r
+ m_textLine += 15;\r
+ float32 torque = m_joint1->GetMotorTorque(settings->hz);\r
+ m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %5.0f", (float) torque);\r
+ m_textLine += 15;\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new SliderCrank;\r
+ }\r
+\r
+ b2RevoluteJoint* m_joint1;\r
+ b2PrismaticJoint* m_joint2;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef SPHERE_STACK_H\r
+#define SPHERE_STACK_H\r
+\r
+class SphereStack : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_count = 10\r
+ };\r
+\r
+ SphereStack()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 1.0f;\r
+\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(0.0, 4.0f + 3.0f * i);\r
+\r
+ m_bodies[i] = m_world->CreateBody(&bd);\r
+\r
+ m_bodies[i]->CreateFixture(&shape, 1.0f);\r
+\r
+ m_bodies[i]->SetLinearVelocity(b2Vec2(0.0f, -50.0f));\r
+ }\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ //for (int32 i = 0; i < e_count; ++i)\r
+ //{\r
+ // printf("%g ", m_bodies[i]->GetWorldCenter().y);\r
+ //}\r
+\r
+ //for (int32 i = 0; i < e_count; ++i)\r
+ //{\r
+ // printf("%g ", m_bodies[i]->GetLinearVelocity().y);\r
+ //}\r
+\r
+ //printf("\n");\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new SphereStack;\r
+ }\r
+\r
+ b2Body* m_bodies[e_count];\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+// Inspired by a contribution by roman_m\r
+// Dimensions scooped from APE (http://www.cove.org/ape/index.htm)\r
+\r
+#ifndef THEO_JANSEN_H\r
+#define THEO_JANSEN_H\r
+\r
+class TheoJansen : public Test\r
+{\r
+public:\r
+\r
+ void CreateLeg(float32 s, const b2Vec2& wheelAnchor)\r
+ {\r
+ b2Vec2 p1(5.4f * s, -6.1f);\r
+ b2Vec2 p2(7.2f * s, -1.2f);\r
+ b2Vec2 p3(4.3f * s, -1.9f);\r
+ b2Vec2 p4(3.1f * s, 0.8f);\r
+ b2Vec2 p5(6.0f * s, 1.5f);\r
+ b2Vec2 p6(2.5f * s, 3.7f);\r
+\r
+ b2FixtureDef fd1, fd2;\r
+ fd1.filter.groupIndex = -1;\r
+ fd2.filter.groupIndex = -1;\r
+ fd1.density = 1.0f;\r
+ fd2.density = 1.0f;\r
+\r
+ b2PolygonShape poly1, poly2;\r
+\r
+ if (s > 0.0f)\r
+ {\r
+ b2Vec2 vertices[3];\r
+\r
+ vertices[0] = p1;\r
+ vertices[1] = p2;\r
+ vertices[2] = p3;\r
+ poly1.Set(vertices, 3);\r
+\r
+ vertices[0] = b2Vec2_zero;\r
+ vertices[1] = p5 - p4;\r
+ vertices[2] = p6 - p4;\r
+ poly2.Set(vertices, 3);\r
+ }\r
+ else\r
+ {\r
+ b2Vec2 vertices[3];\r
+\r
+ vertices[0] = p1;\r
+ vertices[1] = p3;\r
+ vertices[2] = p2;\r
+ poly1.Set(vertices, 3);\r
+\r
+ vertices[0] = b2Vec2_zero;\r
+ vertices[1] = p6 - p4;\r
+ vertices[2] = p5 - p4;\r
+ poly2.Set(vertices, 3);\r
+ }\r
+\r
+ fd1.shape = &poly1;\r
+ fd2.shape = &poly2;\r
+\r
+ b2BodyDef bd1, bd2;\r
+ bd1.type = b2_dynamicBody;\r
+ bd2.type = b2_dynamicBody;\r
+ bd1.position = m_offset;\r
+ bd2.position = p4 + m_offset;\r
+\r
+ bd1.angularDamping = 10.0f;\r
+ bd2.angularDamping = 10.0f;\r
+\r
+ b2Body* body1 = m_world->CreateBody(&bd1);\r
+ b2Body* body2 = m_world->CreateBody(&bd2);\r
+\r
+ body1->CreateFixture(&fd1);\r
+ body2->CreateFixture(&fd2);\r
+\r
+ b2DistanceJointDef djd;\r
+\r
+ // Using a soft distance constraint can reduce some jitter.\r
+ // It also makes the structure seem a bit more fluid by\r
+ // acting like a suspension system.\r
+ djd.dampingRatio = 0.5f;\r
+ djd.frequencyHz = 10.0f;\r
+\r
+ djd.Initialize(body1, body2, p2 + m_offset, p5 + m_offset);\r
+ m_world->CreateJoint(&djd);\r
+\r
+ djd.Initialize(body1, body2, p3 + m_offset, p4 + m_offset);\r
+ m_world->CreateJoint(&djd);\r
+\r
+ djd.Initialize(body1, m_wheel, p3 + m_offset, wheelAnchor + m_offset);\r
+ m_world->CreateJoint(&djd);\r
+\r
+ djd.Initialize(body2, m_wheel, p6 + m_offset, wheelAnchor + m_offset);\r
+ m_world->CreateJoint(&djd);\r
+\r
+ b2RevoluteJointDef rjd;\r
+\r
+ rjd.Initialize(body2, m_chassis, p4 + m_offset);\r
+ m_world->CreateJoint(&rjd);\r
+ }\r
+\r
+ TheoJansen()\r
+ {\r
+ m_offset.Set(0.0f, 8.0f);\r
+ m_motorSpeed = 2.0f;\r
+ m_motorOn = true;\r
+ b2Vec2 pivot(0.0f, 0.8f);\r
+\r
+ // Ground\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(-50.0f, 10.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(50.0f, 10.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ // Balls\r
+ for (int32 i = 0; i < 40; ++i)\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.25f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-40.0f + 2.0f * i, 0.5f);\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 1.0f);\r
+ }\r
+\r
+ // Chassis\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(2.5f, 1.0f);\r
+\r
+ b2FixtureDef sd;\r
+ sd.density = 1.0f;\r
+ sd.shape = &shape;\r
+ sd.filter.groupIndex = -1;\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position = pivot + m_offset;\r
+ m_chassis = m_world->CreateBody(&bd);\r
+ m_chassis->CreateFixture(&sd);\r
+ }\r
+\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 1.6f;\r
+\r
+ b2FixtureDef sd;\r
+ sd.density = 1.0f;\r
+ sd.shape = &shape;\r
+ sd.filter.groupIndex = -1;\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position = pivot + m_offset;\r
+ m_wheel = m_world->CreateBody(&bd);\r
+ m_wheel->CreateFixture(&sd);\r
+ }\r
+\r
+ {\r
+ b2RevoluteJointDef jd;\r
+ jd.Initialize(m_wheel, m_chassis, pivot + m_offset);\r
+ jd.collideConnected = false;\r
+ jd.motorSpeed = m_motorSpeed;\r
+ jd.maxMotorTorque = 400.0f;\r
+ jd.enableMotor = m_motorOn;\r
+ m_motorJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);\r
+ }\r
+\r
+ b2Vec2 wheelAnchor;\r
+ \r
+ wheelAnchor = pivot + b2Vec2(0.0f, -0.8f);\r
+\r
+ CreateLeg(-1.0f, wheelAnchor);\r
+ CreateLeg(1.0f, wheelAnchor);\r
+\r
+ m_wheel->SetTransform(m_wheel->GetPosition(), 120.0f * b2_pi / 180.0f);\r
+ CreateLeg(-1.0f, wheelAnchor);\r
+ CreateLeg(1.0f, wheelAnchor);\r
+\r
+ m_wheel->SetTransform(m_wheel->GetPosition(), -120.0f * b2_pi / 180.0f);\r
+ CreateLeg(-1.0f, wheelAnchor);\r
+ CreateLeg(1.0f, wheelAnchor);\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, toggle motor = m");\r
+ m_textLine += 15;\r
+\r
+ Test::Step(settings);\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'a':\r
+ m_motorJoint->SetMotorSpeed(-m_motorSpeed);\r
+ break;\r
+\r
+ case 's':\r
+ m_motorJoint->SetMotorSpeed(0.0f);\r
+ break;\r
+\r
+ case 'd':\r
+ m_motorJoint->SetMotorSpeed(m_motorSpeed);\r
+ break;\r
+\r
+ case 'm':\r
+ m_motorJoint->EnableMotor(!m_motorJoint->IsMotorEnabled());\r
+ break;\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new TheoJansen;\r
+ }\r
+\r
+ b2Vec2 m_offset;\r
+ b2Body* m_chassis;\r
+ b2Body* m_wheel;\r
+ b2RevoluteJoint* m_motorJoint;\r
+ bool m_motorOn;\r
+ float32 m_motorSpeed;\r
+};\r
+\r
+#endif // THEO_JANSEN_H\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef TILES_H\r
+#define TILES_H\r
+\r
+/// This stress tests the dynamic tree broad-phase. This also shows that tile\r
+/// based collision is _not_ smooth due to Box2D not knowing about adjacency.\r
+class Tiles : public Test\r
+{\r
+public:\r
+ enum\r
+ {\r
+ e_count = 20\r
+ };\r
+\r
+ Tiles()\r
+ {\r
+ m_fixtureCount = 0;\r
+ b2Timer timer;\r
+\r
+ {\r
+ float32 a = 0.5f;\r
+ b2BodyDef bd;\r
+ bd.position.y = -a;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+#if 1\r
+ int32 N = 200;\r
+ int32 M = 10;\r
+ b2Vec2 position;\r
+ position.y = 0.0f;\r
+ for (int32 j = 0; j < M; ++j)\r
+ {\r
+ position.x = -N * a;\r
+ for (int32 i = 0; i < N; ++i)\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(a, a, position, 0.0f);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ ++m_fixtureCount;\r
+ position.x += 2.0f * a;\r
+ }\r
+ position.y -= 2.0f * a;\r
+ }\r
+#else\r
+ int32 N = 200;\r
+ int32 M = 10;\r
+ b2Vec2 position;\r
+ position.x = -N * a;\r
+ for (int32 i = 0; i < N; ++i)\r
+ {\r
+ position.y = 0.0f;\r
+ for (int32 j = 0; j < M; ++j)\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(a, a, position, 0.0f);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ position.y -= 2.0f * a;\r
+ }\r
+ position.x += 2.0f * a;\r
+ }\r
+#endif\r
+ }\r
+\r
+ {\r
+ float32 a = 0.5f;\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(a, a);\r
+\r
+ b2Vec2 x(-7.0f, 0.75f);\r
+ b2Vec2 y;\r
+ b2Vec2 deltaX(0.5625f, 1.25f);\r
+ b2Vec2 deltaY(1.125f, 0.0f);\r
+\r
+ for (int32 i = 0; i < e_count; ++i)\r
+ {\r
+ y = x;\r
+\r
+ for (int32 j = i; j < e_count; ++j)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position = y;\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+ body->CreateFixture(&shape, 5.0f);\r
+ ++m_fixtureCount;\r
+ y += deltaY;\r
+ }\r
+\r
+ x += deltaX;\r
+ }\r
+ }\r
+\r
+ m_createTime = timer.GetMilliseconds();\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ const b2ContactManager& cm = m_world->GetContactManager();\r
+ int32 height = cm.m_broadPhase.GetTreeHeight();\r
+ int32 leafCount = cm.m_broadPhase.GetProxyCount();\r
+ int32 minimumNodeCount = 2 * leafCount - 1;\r
+ float32 minimumHeight = ceilf(logf(float32(minimumNodeCount)) / logf(2.0f));\r
+ m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d, min = %d", height, int32(minimumHeight));\r
+ m_textLine += 15;\r
+\r
+ Test::Step(settings);\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "create time = %6.2f ms, fixture count = %d",\r
+ m_createTime, m_fixtureCount);\r
+ m_textLine += 15;\r
+\r
+ //b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;\r
+\r
+ //if (m_stepCount == 400)\r
+ //{\r
+ // tree->RebuildBottomUp();\r
+ //}\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Tiles;\r
+ }\r
+\r
+ int32 m_fixtureCount;\r
+ float32 m_createTime;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef TIME_OF_IMPACT_H\r
+#define TIME_OF_IMPACT_H\r
+\r
+class TimeOfImpact : public Test\r
+{\r
+public:\r
+ TimeOfImpact()\r
+ {\r
+ m_shapeA.SetAsBox(25.0f, 5.0f);\r
+ m_shapeB.SetAsBox(2.5f, 2.5f);\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new TimeOfImpact;\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+\r
+ b2Sweep sweepA;\r
+ sweepA.c0.Set(24.0f, -60.0f);\r
+ sweepA.a0 = 2.95f;\r
+ sweepA.c = sweepA.c0;\r
+ sweepA.a = sweepA.a0;\r
+ sweepA.localCenter.SetZero();\r
+\r
+ b2Sweep sweepB;\r
+ sweepB.c0.Set(53.474274f, -50.252514f);\r
+ sweepB.a0 = 513.36676f; // - 162.0f * b2_pi;\r
+ sweepB.c.Set(54.595478f, -51.083473f);\r
+ sweepB.a = 513.62781f; // - 162.0f * b2_pi;\r
+ sweepB.localCenter.SetZero();\r
+\r
+ //sweepB.a0 -= 300.0f * b2_pi;\r
+ //sweepB.a -= 300.0f * b2_pi;\r
+\r
+ b2TOIInput input;\r
+ input.proxyA.Set(&m_shapeA, 0);\r
+ input.proxyB.Set(&m_shapeB, 0);\r
+ input.sweepA = sweepA;\r
+ input.sweepB = sweepB;\r
+ input.tMax = 1.0f;\r
+\r
+ b2TOIOutput output;\r
+\r
+ b2TimeOfImpact(&output, &input);\r
+\r
+ m_debugDraw.DrawString(5, m_textLine, "toi = %g", output.t);\r
+ m_textLine += 15;\r
+\r
+ extern int32 b2_toiMaxIters, b2_toiMaxRootIters;\r
+ m_debugDraw.DrawString(5, m_textLine, "max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters);\r
+ m_textLine += 15;\r
+\r
+ b2Vec2 vertices[b2_maxPolygonVertices];\r
+\r
+ b2Transform transformA;\r
+ sweepA.GetTransform(&transformA, 0.0f);\r
+ for (int32 i = 0; i < m_shapeA.m_vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(transformA, m_shapeA.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(vertices, m_shapeA.m_vertexCount, b2Color(0.9f, 0.9f, 0.9f));\r
+\r
+ b2Transform transformB;\r
+ sweepB.GetTransform(&transformB, 0.0f);\r
+ \r
+ b2Vec2 localPoint(2.0f, -0.1f);\r
+ b2Vec2 rB = b2Mul(transformB, localPoint) - sweepB.c0;\r
+ float32 wB = sweepB.a - sweepB.a0;\r
+ b2Vec2 vB = sweepB.c - sweepB.c0;\r
+ b2Vec2 v = vB + b2Cross(wB, rB);\r
+\r
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.9f, 0.5f));\r
+\r
+ sweepB.GetTransform(&transformB, output.t);\r
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.7f, 0.9f));\r
+\r
+ sweepB.GetTransform(&transformB, 1.0f);\r
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f));\r
+\r
+#if 0\r
+ for (float32 t = 0.0f; t < 1.0f; t += 0.1f)\r
+ {\r
+ sweepB.GetTransform(&transformB, t);\r
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)\r
+ {\r
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);\r
+ }\r
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f));\r
+ }\r
+#endif\r
+ }\r
+\r
+ b2PolygonShape m_shapeA;\r
+ b2PolygonShape m_shapeB;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef VARYING_FRICTION_H\r
+#define VARYING_FRICTION_H\r
+\r
+class VaryingFriction : public Test\r
+{\r
+public:\r
+\r
+ VaryingFriction()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(13.0f, 0.25f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(-4.0f, 22.0f);\r
+ bd.angle = -0.25f;\r
+\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.25f, 1.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(10.5f, 19.0f);\r
+\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(13.0f, 0.25f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(4.0f, 14.0f);\r
+ bd.angle = 0.25f;\r
+\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.25f, 1.0f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(-10.5f, 11.0f);\r
+\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(13.0f, 0.25f);\r
+\r
+ b2BodyDef bd;\r
+ bd.position.Set(-4.0f, 6.0f);\r
+ bd.angle = -0.25f;\r
+\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.5f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 25.0f;\r
+\r
+ float friction[5] = {0.75f, 0.5f, 0.35f, 0.1f, 0.0f};\r
+\r
+ for (int i = 0; i < 5; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-15.0f + 4.0f * i, 28.0f);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ fd.friction = friction[i];\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new VaryingFriction;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef VARYING_RESTITUTION_H\r
+#define VARYING_RESTITUTION_H\r
+\r
+// Note: even with a restitution of 1.0, there is some energy change\r
+// due to position correction.\r
+class VaryingRestitution : public Test\r
+{\r
+public:\r
+\r
+ VaryingRestitution()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 1.0f;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+\r
+ float32 restitution[7] = {0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f};\r
+\r
+ for (int32 i = 0; i < 7; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.position.Set(-10.0f + 3.0f * i, 20.0f);\r
+\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ fd.restitution = restitution[i];\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new VaryingRestitution;\r
+ }\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef VERTICAL_STACK_H\r
+#define VERTICAL_STACK_H\r
+\r
+class VerticalStack : public Test\r
+{\r
+public:\r
+\r
+ enum\r
+ {\r
+ e_columnCount = 5,\r
+ e_rowCount = 16\r
+ //e_columnCount = 1,\r
+ //e_rowCount = 1\r
+ };\r
+\r
+ VerticalStack()\r
+ {\r
+ {\r
+ b2BodyDef bd;\r
+ b2Body* ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+\r
+ shape.Set(b2Vec2(20.0f, 0.0f), b2Vec2(20.0f, 20.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ float32 xs[5] = {0.0f, -10.0f, -5.0f, 5.0f, 10.0f};\r
+\r
+ for (int32 j = 0; j < e_columnCount; ++j)\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.5f);\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 1.0f;\r
+ fd.friction = 0.3f;\r
+\r
+ for (int i = 0; i < e_rowCount; ++i)\r
+ {\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ int32 n = j * e_rowCount + i;\r
+ b2Assert(n < e_rowCount * e_columnCount);\r
+ m_indices[n] = n;\r
+ bd.userData = m_indices + n;\r
+\r
+ float32 x = 0.0f;\r
+ //float32 x = RandomFloat(-0.02f, 0.02f);\r
+ //float32 x = i % 2 == 0 ? -0.025f : 0.025f;\r
+ bd.position.Set(xs[j] + x, 0.752f + 1.54f * i);\r
+ b2Body* body = m_world->CreateBody(&bd);\r
+\r
+ m_bodies[n] = body;\r
+\r
+ body->CreateFixture(&fd);\r
+ }\r
+ }\r
+\r
+ m_bullet = NULL;\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case ',':\r
+ if (m_bullet != NULL)\r
+ {\r
+ m_world->DestroyBody(m_bullet);\r
+ m_bullet = NULL;\r
+ }\r
+\r
+ {\r
+ b2CircleShape shape;\r
+ shape.m_radius = 0.25f;\r
+\r
+ b2FixtureDef fd;\r
+ fd.shape = &shape;\r
+ fd.density = 20.0f;\r
+ fd.restitution = 0.05f;\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+ bd.bullet = true;\r
+ bd.position.Set(-31.0f, 5.0f);\r
+\r
+ m_bullet = m_world->CreateBody(&bd);\r
+ m_bullet->CreateFixture(&fd);\r
+\r
+ m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "Press: (,) to launch a bullet.");\r
+ m_textLine += 15;\r
+\r
+ //if (m_stepCount == 300)\r
+ //{\r
+ // if (m_bullet != NULL)\r
+ // {\r
+ // m_world->DestroyBody(m_bullet);\r
+ // m_bullet = NULL;\r
+ // }\r
+\r
+ // {\r
+ // b2CircleShape shape;\r
+ // shape.m_radius = 0.25f;\r
+\r
+ // b2FixtureDef fd;\r
+ // fd.shape = &shape;\r
+ // fd.density = 20.0f;\r
+ // fd.restitution = 0.05f;\r
+\r
+ // b2BodyDef bd;\r
+ // bd.type = b2_dynamicBody;\r
+ // bd.bullet = true;\r
+ // bd.position.Set(-31.0f, 5.0f);\r
+\r
+ // m_bullet = m_world->CreateBody(&bd);\r
+ // m_bullet->CreateFixture(&fd);\r
+\r
+ // m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));\r
+ // }\r
+ //}\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new VerticalStack;\r
+ }\r
+\r
+ b2Body* m_bullet;\r
+ b2Body* m_bodies[e_rowCount * e_columnCount];\r
+ int32 m_indices[e_rowCount * e_columnCount];\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org\r
+*\r
+* This software is provided 'as-is', without any express or implied\r
+* warranty. In no event will the authors be held liable for any damages\r
+* arising from the use of this software.\r
+* Permission is granted to anyone to use this software for any purpose,\r
+* including commercial applications, and to alter it and redistribute it\r
+* freely, subject to the following restrictions:\r
+* 1. The origin of this software must not be misrepresented; you must not\r
+* claim that you wrote the original software. If you use this software\r
+* in a product, an acknowledgment in the product documentation would be\r
+* appreciated but is not required.\r
+* 2. Altered source versions must be plainly marked as such, and must not be\r
+* misrepresented as being the original software.\r
+* 3. This notice may not be removed or altered from any source distribution.\r
+*/\r
+\r
+#ifndef WEB_H\r
+#define WEB_H\r
+\r
+// This tests distance joints, body destruction, and joint destruction.\r
+class Web : public Test\r
+{\r
+public:\r
+ Web()\r
+ {\r
+ b2Body* ground = NULL;\r
+ {\r
+ b2BodyDef bd;\r
+ ground = m_world->CreateBody(&bd);\r
+\r
+ b2EdgeShape shape;\r
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));\r
+ ground->CreateFixture(&shape, 0.0f);\r
+ }\r
+\r
+ {\r
+ b2PolygonShape shape;\r
+ shape.SetAsBox(0.5f, 0.5f);\r
+\r
+ b2BodyDef bd;\r
+ bd.type = b2_dynamicBody;\r
+\r
+ bd.position.Set(-5.0f, 5.0f);\r
+ m_bodies[0] = m_world->CreateBody(&bd);\r
+ m_bodies[0]->CreateFixture(&shape, 5.0f);\r
+\r
+ bd.position.Set(5.0f, 5.0f);\r
+ m_bodies[1] = m_world->CreateBody(&bd);\r
+ m_bodies[1]->CreateFixture(&shape, 5.0f);\r
+\r
+ bd.position.Set(5.0f, 15.0f);\r
+ m_bodies[2] = m_world->CreateBody(&bd);\r
+ m_bodies[2]->CreateFixture(&shape, 5.0f);\r
+\r
+ bd.position.Set(-5.0f, 15.0f);\r
+ m_bodies[3] = m_world->CreateBody(&bd);\r
+ m_bodies[3]->CreateFixture(&shape, 5.0f);\r
+\r
+ b2DistanceJointDef jd;\r
+ b2Vec2 p1, p2, d;\r
+\r
+ jd.frequencyHz = 2.0f;\r
+ jd.dampingRatio = 0.0f;\r
+\r
+ jd.bodyA = ground;\r
+ jd.bodyB = m_bodies[0];\r
+ jd.localAnchorA.Set(-10.0f, 0.0f);\r
+ jd.localAnchorB.Set(-0.5f, -0.5f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[0] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = ground;\r
+ jd.bodyB = m_bodies[1];\r
+ jd.localAnchorA.Set(10.0f, 0.0f);\r
+ jd.localAnchorB.Set(0.5f, -0.5f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[1] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = ground;\r
+ jd.bodyB = m_bodies[2];\r
+ jd.localAnchorA.Set(10.0f, 20.0f);\r
+ jd.localAnchorB.Set(0.5f, 0.5f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[2] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = ground;\r
+ jd.bodyB = m_bodies[3];\r
+ jd.localAnchorA.Set(-10.0f, 20.0f);\r
+ jd.localAnchorB.Set(-0.5f, 0.5f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[3] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = m_bodies[0];\r
+ jd.bodyB = m_bodies[1];\r
+ jd.localAnchorA.Set(0.5f, 0.0f);\r
+ jd.localAnchorB.Set(-0.5f, 0.0f);;\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[4] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = m_bodies[1];\r
+ jd.bodyB = m_bodies[2];\r
+ jd.localAnchorA.Set(0.0f, 0.5f);\r
+ jd.localAnchorB.Set(0.0f, -0.5f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[5] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = m_bodies[2];\r
+ jd.bodyB = m_bodies[3];\r
+ jd.localAnchorA.Set(-0.5f, 0.0f);\r
+ jd.localAnchorB.Set(0.5f, 0.0f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[6] = m_world->CreateJoint(&jd);\r
+\r
+ jd.bodyA = m_bodies[3];\r
+ jd.bodyB = m_bodies[0];\r
+ jd.localAnchorA.Set(0.0f, -0.5f);\r
+ jd.localAnchorB.Set(0.0f, 0.5f);\r
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);\r
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);\r
+ d = p2 - p1;\r
+ jd.length = d.Length();\r
+ m_joints[7] = m_world->CreateJoint(&jd);\r
+ }\r
+ }\r
+\r
+ void Keyboard(unsigned char key)\r
+ {\r
+ switch (key)\r
+ {\r
+ case 'b':\r
+ for (int32 i = 0; i < 4; ++i)\r
+ {\r
+ if (m_bodies[i])\r
+ {\r
+ m_world->DestroyBody(m_bodies[i]);\r
+ m_bodies[i] = NULL;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case 'j':\r
+ for (int32 i = 0; i < 8; ++i)\r
+ {\r
+ if (m_joints[i])\r
+ {\r
+ m_world->DestroyJoint(m_joints[i]);\r
+ m_joints[i] = NULL;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ void Step(Settings* settings)\r
+ {\r
+ Test::Step(settings);\r
+ m_debugDraw.DrawString(5, m_textLine, "This demonstrates a soft distance joint.");\r
+ m_textLine += 15;\r
+ m_debugDraw.DrawString(5, m_textLine, "Press: (b) to delete a body, (j) to delete a joint");\r
+ m_textLine += 15;\r
+ }\r
+\r
+ void JointDestroyed(b2Joint* joint)\r
+ {\r
+ for (int32 i = 0; i < 8; ++i)\r
+ {\r
+ if (m_joints[i] == joint)\r
+ {\r
+ m_joints[i] = NULL;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ static Test* Create()\r
+ {\r
+ return new Web;\r
+ }\r
+\r
+ b2Body* m_bodies[4];\r
+ b2Joint* m_joints[8];\r
+};\r
+\r
+#endif\r