Hipmunk 0.2.2 → 5.0.0
raw patch · 88 files changed
+6855/−5092 lines, 88 filesdep ~arraydep ~basedep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: array, base, containers
API changes (from Hackage documentation)
- Physics.Hipmunk.Body: dampedSpring :: (Body, Position) -> (Body, Position) -> CpFloat -> CpFloat -> CpFloat -> Time -> IO ()
- Physics.Hipmunk.Common: getJointBiasCoef :: IO CpFloat
- Physics.Hipmunk.Common: setJointBiasCoef :: CpFloat -> IO ()
- Physics.Hipmunk.Joint: Groove :: (Position, Position) -> Position -> JointType
- Physics.Hipmunk.Joint: Pin :: Position -> Position -> JointType
- Physics.Hipmunk.Joint: Pivot :: Position -> JointType
- Physics.Hipmunk.Joint: Slide :: Position -> Position -> CpFloat -> CpFloat -> JointType
- Physics.Hipmunk.Joint: anchor1 :: JointType -> Position
- Physics.Hipmunk.Joint: anchor2 :: JointType -> Position
- Physics.Hipmunk.Joint: data Joint
- Physics.Hipmunk.Joint: data JointType
- Physics.Hipmunk.Joint: groove1 :: JointType -> (Position, Position)
- Physics.Hipmunk.Joint: instance Eq JointType
- Physics.Hipmunk.Joint: instance Ord JointType
- Physics.Hipmunk.Joint: instance Show JointType
- Physics.Hipmunk.Joint: maxDist :: JointType -> CpFloat
- Physics.Hipmunk.Joint: minDist :: JointType -> CpFloat
- Physics.Hipmunk.Joint: newJoint :: Body -> Body -> JointType -> IO Joint
- Physics.Hipmunk.Joint: pivot :: JointType -> Position
- Physics.Hipmunk.Joint: pivot2 :: JointType -> Position
- Physics.Hipmunk.Shape: shapeQuery :: Shape -> Position -> IO Bool
- Physics.Hipmunk.Space: ActiveHash :: QueryType
- Physics.Hipmunk.Space: Both :: QueryType
- Physics.Hipmunk.Space: StaticHash :: QueryType
- Physics.Hipmunk.Space: data QueryType
- Physics.Hipmunk.Space: instance Entity Joint
- Physics.Hipmunk.Space: type Damping = CpFloat
+ Physics.Hipmunk.Body: applyDampedSpring :: (Body, Position) -> (Body, Position) -> Distance -> CpFloat -> Damping -> Time -> IO ()
+ Physics.Hipmunk.Common: getConstraintBiasCoef :: IO BiasCoef
+ Physics.Hipmunk.Common: setConstraintBiasCoef :: BiasCoef -> IO ()
+ Physics.Hipmunk.Common: type BiasCoef = CpFloat
+ Physics.Hipmunk.Common: type Damping = CpFloat
+ Physics.Hipmunk.Common: type Distance = CpFloat
+ Physics.Hipmunk.Constraint: DampedRotarySpring :: !Angle -> !CpFloat -> !Damping -> DampedRotarySpring
+ Physics.Hipmunk.Constraint: DampedSpring :: !Position -> !Position -> !Distance -> !CpFloat -> !Damping -> DampedSpring
+ Physics.Hipmunk.Constraint: Gear :: !Angle -> !CpFloat -> Gear
+ Physics.Hipmunk.Constraint: Groove :: !(Position, Position) -> !Position -> Groove
+ Physics.Hipmunk.Constraint: Pin :: !Position -> !Position -> Pin
+ Physics.Hipmunk.Constraint: Pivot1 :: !Position -> Pivot
+ Physics.Hipmunk.Constraint: Pivot2 :: !Position -> !Position -> Pivot
+ Physics.Hipmunk.Constraint: RotaryLimit :: Distance -> Distance -> RotaryLimit
+ Physics.Hipmunk.Constraint: SimpleMotor :: CpFloat -> SimpleMotor
+ Physics.Hipmunk.Constraint: Slide :: !Position -> !Position -> !Distance -> !Distance -> Slide
+ Physics.Hipmunk.Constraint: dampedAnchor1 :: DampedSpring -> !Position
+ Physics.Hipmunk.Constraint: dampedAnchor2 :: DampedSpring -> !Position
+ Physics.Hipmunk.Constraint: dampedDamping :: DampedSpring -> !Damping
+ Physics.Hipmunk.Constraint: dampedRestLength :: DampedSpring -> !Distance
+ Physics.Hipmunk.Constraint: dampedRotDamping :: DampedRotarySpring -> !Damping
+ Physics.Hipmunk.Constraint: dampedRotRestAngle :: DampedRotarySpring -> !Angle
+ Physics.Hipmunk.Constraint: dampedRotStiffness :: DampedRotarySpring -> !CpFloat
+ Physics.Hipmunk.Constraint: dampedStiffness :: DampedSpring -> !CpFloat
+ Physics.Hipmunk.Constraint: data Constraint a
+ Physics.Hipmunk.Constraint: data DampedRotarySpring
+ Physics.Hipmunk.Constraint: data DampedSpring
+ Physics.Hipmunk.Constraint: data Gear
+ Physics.Hipmunk.Constraint: data Groove
+ Physics.Hipmunk.Constraint: data Pin
+ Physics.Hipmunk.Constraint: data Pivot
+ Physics.Hipmunk.Constraint: data RotaryLimit
+ Physics.Hipmunk.Constraint: data SimpleMotor
+ Physics.Hipmunk.Constraint: data Slide
+ Physics.Hipmunk.Constraint: data Unknown
+ Physics.Hipmunk.Constraint: forgetC :: Constraint a -> Constraint Unknown
+ Physics.Hipmunk.Constraint: gearPhase :: Gear -> !Angle
+ Physics.Hipmunk.Constraint: gearRatio :: Gear -> !CpFloat
+ Physics.Hipmunk.Constraint: groovePivot :: Groove -> !Position
+ Physics.Hipmunk.Constraint: groovePoints :: Groove -> !(Position, Position)
+ Physics.Hipmunk.Constraint: instance ConstraintType DampedRotarySpring
+ Physics.Hipmunk.Constraint: instance ConstraintType DampedSpring
+ Physics.Hipmunk.Constraint: instance ConstraintType Gear
+ Physics.Hipmunk.Constraint: instance ConstraintType Groove
+ Physics.Hipmunk.Constraint: instance ConstraintType Pin
+ Physics.Hipmunk.Constraint: instance ConstraintType Pivot
+ Physics.Hipmunk.Constraint: instance ConstraintType RotaryLimit
+ Physics.Hipmunk.Constraint: instance ConstraintType SimpleMotor
+ Physics.Hipmunk.Constraint: instance ConstraintType Slide
+ Physics.Hipmunk.Constraint: instance Eq DampedRotarySpring
+ Physics.Hipmunk.Constraint: instance Eq DampedSpring
+ Physics.Hipmunk.Constraint: instance Eq Gear
+ Physics.Hipmunk.Constraint: instance Eq Groove
+ Physics.Hipmunk.Constraint: instance Eq Pin
+ Physics.Hipmunk.Constraint: instance Eq Pivot
+ Physics.Hipmunk.Constraint: instance Eq RotaryLimit
+ Physics.Hipmunk.Constraint: instance Eq SimpleMotor
+ Physics.Hipmunk.Constraint: instance Eq Slide
+ Physics.Hipmunk.Constraint: instance Ord DampedRotarySpring
+ Physics.Hipmunk.Constraint: instance Ord DampedSpring
+ Physics.Hipmunk.Constraint: instance Ord Gear
+ Physics.Hipmunk.Constraint: instance Ord Groove
+ Physics.Hipmunk.Constraint: instance Ord Pin
+ Physics.Hipmunk.Constraint: instance Ord Pivot
+ Physics.Hipmunk.Constraint: instance Ord RotaryLimit
+ Physics.Hipmunk.Constraint: instance Ord SimpleMotor
+ Physics.Hipmunk.Constraint: instance Ord Slide
+ Physics.Hipmunk.Constraint: instance Show DampedRotarySpring
+ Physics.Hipmunk.Constraint: instance Show DampedSpring
+ Physics.Hipmunk.Constraint: instance Show Gear
+ Physics.Hipmunk.Constraint: instance Show Groove
+ Physics.Hipmunk.Constraint: instance Show Pin
+ Physics.Hipmunk.Constraint: instance Show Pivot
+ Physics.Hipmunk.Constraint: instance Show RotaryLimit
+ Physics.Hipmunk.Constraint: instance Show SimpleMotor
+ Physics.Hipmunk.Constraint: instance Show Slide
+ Physics.Hipmunk.Constraint: newConstraint :: (ConstraintType a) => Body -> Body -> a -> IO (Constraint a)
+ Physics.Hipmunk.Constraint: pinAnchor1 :: Pin -> !Position
+ Physics.Hipmunk.Constraint: pinAnchor2 :: Pin -> !Position
+ Physics.Hipmunk.Constraint: pivotAnchor1 :: Pivot -> !Position
+ Physics.Hipmunk.Constraint: pivotAnchor2 :: Pivot -> !Position
+ Physics.Hipmunk.Constraint: pivotPos :: Pivot -> !Position
+ Physics.Hipmunk.Constraint: redefineC :: (ConstraintType a) => Constraint a -> a -> IO ()
+ Physics.Hipmunk.Constraint: rotaryMaxDist :: RotaryLimit -> Distance
+ Physics.Hipmunk.Constraint: rotaryMinDist :: RotaryLimit -> Distance
+ Physics.Hipmunk.Constraint: setBiasCoefC :: BiasCoef -> Constraint a -> IO ()
+ Physics.Hipmunk.Constraint: simpleMotorRate :: SimpleMotor -> CpFloat
+ Physics.Hipmunk.Constraint: slideAnchor1 :: Slide -> !Position
+ Physics.Hipmunk.Constraint: slideAnchor2 :: Slide -> !Position
+ Physics.Hipmunk.Constraint: slideMaxDist :: Slide -> !Distance
+ Physics.Hipmunk.Constraint: slideMinDist :: Slide -> !Distance
+ Physics.Hipmunk.Shape: moment :: Mass -> ShapeType -> Position -> Moment
+ Physics.Hipmunk.Shape: momentForSegment :: Mass -> Position -> Position -> Moment
+ Physics.Hipmunk.Shape: shapePointQuery :: Shape -> Position -> Layers -> Group -> IO Bool
+ Physics.Hipmunk.Shape: shapeSegmentQuery :: Shape -> Position -> Position -> Layers -> Group -> IO (Maybe (CpFloat, Vector))
+ Physics.Hipmunk.Space: instance Entity (Constraint a)
+ Physics.Hipmunk.Unsafe: unsafeRememberC :: (ConstraintType a) => Constraint Unknown -> Constraint a
+ Physics.Hipmunk.Unsafe: unsafeShapeRedefine :: Shape -> ShapeType -> Position -> IO ()
- Physics.Hipmunk.Body: newBody :: CpFloat -> CpFloat -> IO Body
+ Physics.Hipmunk.Body: newBody :: Mass -> Moment -> IO Body
- Physics.Hipmunk.Body: updateVelocity :: Body -> Vector -> CpFloat -> Time -> IO ()
+ Physics.Hipmunk.Body: updateVelocity :: Body -> Vector -> Damping -> Time -> IO ()
- Physics.Hipmunk.Common: getBiasCoef :: IO CpFloat
+ Physics.Hipmunk.Common: getBiasCoef :: IO BiasCoef
- Physics.Hipmunk.Common: getContactPersistence :: IO Int32
+ Physics.Hipmunk.Common: getContactPersistence :: IO CInt
- Physics.Hipmunk.Common: setBiasCoef :: CpFloat -> IO ()
+ Physics.Hipmunk.Common: setBiasCoef :: BiasCoef -> IO ()
- Physics.Hipmunk.Common: setContactPersistence :: Int32 -> IO ()
+ Physics.Hipmunk.Common: setContactPersistence :: CInt -> IO ()
- Physics.Hipmunk.Shape: Circle :: !CpFloat -> ShapeType
+ Physics.Hipmunk.Shape: Circle :: !Distance -> ShapeType
- Physics.Hipmunk.Shape: LineSegment :: !Position -> !Position -> !CpFloat -> ShapeType
+ Physics.Hipmunk.Shape: LineSegment :: !Position -> !Position -> !Distance -> ShapeType
- Physics.Hipmunk.Shape: momentForCircle :: CpFloat -> (CpFloat, CpFloat) -> Position -> CpFloat
+ Physics.Hipmunk.Shape: momentForCircle :: Mass -> (Distance, Distance) -> Position -> Moment
- Physics.Hipmunk.Shape: momentForPoly :: CpFloat -> [Position] -> Position -> CpFloat
+ Physics.Hipmunk.Shape: momentForPoly :: Mass -> [Position] -> Position -> Moment
- Physics.Hipmunk.Shape: polyReduce :: CpFloat -> [Position] -> [Position]
+ Physics.Hipmunk.Shape: polyReduce :: Distance -> [Position] -> [Position]
- Physics.Hipmunk.Shape: radius :: ShapeType -> !CpFloat
+ Physics.Hipmunk.Shape: radius :: ShapeType -> !Distance
- Physics.Hipmunk.Shape: thickness :: ShapeType -> !CpFloat
+ Physics.Hipmunk.Shape: thickness :: ShapeType -> !Distance
- Physics.Hipmunk.Space: resizeActiveHash :: Space -> CpFloat -> Int32 -> IO ()
+ Physics.Hipmunk.Space: resizeActiveHash :: Space -> Distance -> CInt -> IO ()
- Physics.Hipmunk.Space: resizeStaticHash :: Space -> CpFloat -> Int32 -> IO ()
+ Physics.Hipmunk.Space: resizeStaticHash :: Space -> Distance -> CInt -> IO ()
- Physics.Hipmunk.Space: spaceQuery :: Space -> QueryType -> Position -> (Shape -> IO ()) -> IO ()
+ Physics.Hipmunk.Space: spaceQuery :: Space -> Position -> Layers -> Group -> (Shape -> IO ()) -> IO ()
- Physics.Hipmunk.Space: spaceQueryList :: Space -> QueryType -> Position -> IO [Shape]
+ Physics.Hipmunk.Space: spaceQueryList :: Space -> Position -> Layers -> Group -> IO [Shape]
- Physics.Hipmunk.Space: type ElasticIterations = Int32
+ Physics.Hipmunk.Space: type ElasticIterations = CInt
- Physics.Hipmunk.Space: type Iterations = Int32
+ Physics.Hipmunk.Space: type Iterations = CInt
- Physics.Hipmunk.Space: type TimeStamp = Int32
+ Physics.Hipmunk.Space: type TimeStamp = CInt
Files
- Hipmunk.cabal +72/−37
- NEWS +7/−0
- Physics/Hipmunk.hs +3/−3
- Physics/Hipmunk/Body.hsc +12/−13
- Physics/Hipmunk/Common.hsc +79/−44
- Physics/Hipmunk/Constraint.hsc +315/−0
- Physics/Hipmunk/Internal.hsc +44/−25
- Physics/Hipmunk/Joint.hsc +0/−113
- Physics/Hipmunk/Shape.hsc +78/−217
- Physics/Hipmunk/Space.hsc +48/−61
- Physics/Hipmunk/Unsafe.hsc +87/−0
- Physics/Hipmunk/wrapper.c +60/−24
- Physics/Hipmunk/wrapper.h +34/−33
- chipmunk-5.0/chipmunk.c +78/−0
- chipmunk-5.0/chipmunk.h +104/−0
- chipmunk-5.0/chipmunk_types.h +26/−0
- chipmunk-5.0/chipmunk_unsafe.h +54/−0
- chipmunk-5.0/constraints/cpConstraint.c +60/−0
- chipmunk-5.0/constraints/cpConstraint.h +90/−0
- chipmunk-5.0/constraints/cpDampedRotarySpring.c +106/−0
- chipmunk-5.0/constraints/cpDampedRotarySpring.h +45/−0
- chipmunk-5.0/constraints/cpDampedSpring.c +117/−0
- chipmunk-5.0/constraints/cpDampedSpring.h +53/−0
- chipmunk-5.0/constraints/cpGearJoint.c +104/−0
- chipmunk-5.0/constraints/cpGearJoint.h +39/−0
- chipmunk-5.0/constraints/cpGrooveJoint.c +138/−0
- chipmunk-5.0/constraints/cpGrooveJoint.h +44/−0
- chipmunk-5.0/constraints/cpPinJoint.c +117/−0
- chipmunk-5.0/constraints/cpPinJoint.h +43/−0
- chipmunk-5.0/constraints/cpPivotJoint.c +116/−0
- chipmunk-5.0/constraints/cpPivotJoint.h +42/−0
- chipmunk-5.0/constraints/cpRotaryLimitJoint.c +122/−0
- chipmunk-5.0/constraints/cpRotaryLimitJoint.h +39/−0
- chipmunk-5.0/constraints/cpSimpleMotor.c +99/−0
- chipmunk-5.0/constraints/cpSimpleMotor.h +37/−0
- chipmunk-5.0/constraints/cpSlideJoint.c +131/−0
- chipmunk-5.0/constraints/cpSlideJoint.h +44/−0
- chipmunk-5.0/constraints/util.h +110/−0
- chipmunk-5.0/cpArbiter.c +254/−0
- chipmunk-5.0/cpArbiter.h +85/−0
- chipmunk-5.0/cpArray.c +114/−0
- chipmunk-5.0/cpArray.h +45/−0
- chipmunk-5.0/cpBB.c +47/−0
- chipmunk-5.0/cpBB.h +53/−0
- chipmunk-5.0/cpBody.c +179/−0
- chipmunk-5.0/cpBody.h +153/−0
- chipmunk-5.0/cpCollision.c +403/−0
- chipmunk-5.0/cpCollision.h +23/−0
- chipmunk-5.0/cpHashSet.c +225/−0
- chipmunk-5.0/cpHashSet.h +79/−0
- chipmunk-5.0/cpPolyShape.c +219/−0
- chipmunk-5.0/cpPolyShape.h +100/−0
- chipmunk-5.0/cpShape.c +401/−0
- chipmunk-5.0/cpShape.h +155/−0
- chipmunk-5.0/cpSpace.c +571/−0
- chipmunk-5.0/cpSpace.h +120/−0
- chipmunk-5.0/cpSpaceHash.c +460/−0
- chipmunk-5.0/cpSpaceHash.h +100/−0
- chipmunk-5.0/cpVect.c +51/−0
- chipmunk-5.0/cpVect.h +153/−0
- chipmunk-5.0/prime.h +68/−0
- chipmunk/chipmunk.c +0/−69
- chipmunk/chipmunk.h +0/−91
- chipmunk/cpArbiter.c +0/−263
- chipmunk/cpArbiter.h +0/−85
- chipmunk/cpArray.c +0/−114
- chipmunk/cpArray.h +0/−45
- chipmunk/cpBB.c +0/−46
- chipmunk/cpBB.h +0/−53
- chipmunk/cpBody.c +0/−180
- chipmunk/cpBody.h +0/−132
- chipmunk/cpCollision.c +0/−390
- chipmunk/cpCollision.h +0/−23
- chipmunk/cpHashSet.c +0/−219
- chipmunk/cpHashSet.h +0/−79
- chipmunk/cpJoint.c +0/−553
- chipmunk/cpJoint.h +0/−122
- chipmunk/cpPolyShape.c +0/−139
- chipmunk/cpPolyShape.h +0/−92
- chipmunk/cpShape.c +0/−244
- chipmunk/cpShape.h +0/−141
- chipmunk/cpSpace.c +0/−530
- chipmunk/cpSpace.h +0/−120
- chipmunk/cpSpaceHash.c +0/−455
- chipmunk/cpSpaceHash.h +0/−100
- chipmunk/cpVect.c +0/−63
- chipmunk/cpVect.h +0/−106
- chipmunk/prime.h +0/−68
Hipmunk.cabal view
@@ -3,39 +3,61 @@ Tested-With: GHC Category: Physics, Game Name: Hipmunk-Version: 0.2.2+Version: 5.0.0 Stability: provisional License: OtherLicense License-File: LICENSE-Copyright: (c) 2008 Felipe A. Lessa+Copyright: (c) 2008-2009 Felipe A. Lessa Author: Felipe A. Lessa <felipe.lessa@gmail.com> Maintainer: Felipe A. Lessa <felipe.lessa@gmail.com> Synopsis: A Haskell binding for Chipmunk. Description: Chipmunk is a fast, simple, portable, 2D physics engine (<http://wiki.slembcke.net/main/published/Chipmunk>). This- package contains the Chipmunk 4.1.0 source (see- <http://www.slembcke.net/forums/viewtopic.php?f=4&t=276>)+ package contains a prerelease Chipmunk 5.0 source and Haskell bindings to all of its functions. It is- completely self-contained.+ completely self-contained. Please see+ <http://hackage.haskell.org/package/HipmunkPlayground>+ for a demonstration of this library. .+ New in version 5.0.0:+ .+ * Updated for a prerelease of Chipmunk 5.0 from subversion+ revision 192. Besides bugfixes this new version brings+ the long awaited new constraints type, doubling the+ number of different joint from four to nine.+ .+ * Tighter dependencies following the versioning policies.+ . Licensed under the MIT license (like Chipmunk itself). Extra-Source-Files: NEWS,- chipmunk/chipmunk.h,- chipmunk/cpArbiter.h,- chipmunk/cpArray.h,- chipmunk/cpBB.h,- chipmunk/cpBody.h,- chipmunk/cpCollision.h,- chipmunk/cpHashSet.h,- chipmunk/cpJoint.h,- chipmunk/cpPolyShape.h,- chipmunk/cpShape.h,- chipmunk/cpSpace.h,- chipmunk/cpSpaceHash.h,- chipmunk/cpVect.h,- chipmunk/prime.h,+ chipmunk-5.0/chipmunk.h,+ chipmunk-5.0/chipmunk_types.h,+ chipmunk-5.0/chipmunk_unsafe.h,+ chipmunk-5.0/cpArbiter.h,+ chipmunk-5.0/cpArray.h,+ chipmunk-5.0/cpBB.h,+ chipmunk-5.0/cpBody.h,+ chipmunk-5.0/cpCollision.h,+ chipmunk-5.0/cpHashSet.h,+ chipmunk-5.0/cpPolyShape.h,+ chipmunk-5.0/cpShape.h,+ chipmunk-5.0/cpSpace.h,+ chipmunk-5.0/cpSpaceHash.h,+ chipmunk-5.0/cpVect.h,+ chipmunk-5.0/prime.h,+ chipmunk-5.0/constraints/cpConstraint.h,+ chipmunk-5.0/constraints/cpDampedRotarySpring.h,+ chipmunk-5.0/constraints/cpDampedSpring.h,+ chipmunk-5.0/constraints/cpGearJoint.h,+ chipmunk-5.0/constraints/cpGrooveJoint.h,+ chipmunk-5.0/constraints/cpPinJoint.h,+ chipmunk-5.0/constraints/cpPivotJoint.h,+ chipmunk-5.0/constraints/cpRotaryLimitJoint.h,+ chipmunk-5.0/constraints/cpSimpleMotor.h,+ chipmunk-5.0/constraints/cpSlideJoint.h,+ chipmunk-5.0/constraints/util.h, Physics/Hipmunk/wrapper.h Flag small_base@@ -48,33 +70,46 @@ Physics.Hipmunk.Common, Physics.Hipmunk.Body, Physics.Hipmunk.Shape,- Physics.Hipmunk.Joint,- Physics.Hipmunk.Space+ Physics.Hipmunk.Constraint,+ Physics.Hipmunk.Space,+ Physics.Hipmunk.Unsafe Other-Modules: Physics.Hipmunk.Internal Include-Dirs: Physics/Hipmunk,- chipmunk+ chipmunk-5.0 Includes: wrapper.h C-Sources:- chipmunk/chipmunk.c,- chipmunk/cpArbiter.c,- chipmunk/cpArray.c,- chipmunk/cpBB.c,- chipmunk/cpBody.c,- chipmunk/cpCollision.c,- chipmunk/cpHashSet.c,- chipmunk/cpJoint.c,- chipmunk/cpPolyShape.c,- chipmunk/cpShape.c,- chipmunk/cpSpace.c,- chipmunk/cpSpaceHash.c,- chipmunk/cpVect.c,+ chipmunk-5.0/chipmunk.c,+ chipmunk-5.0/cpArbiter.c,+ chipmunk-5.0/cpArray.c,+ chipmunk-5.0/cpBB.c,+ chipmunk-5.0/cpBody.c,+ chipmunk-5.0/cpCollision.c,+ chipmunk-5.0/cpHashSet.c,+ chipmunk-5.0/cpPolyShape.c,+ chipmunk-5.0/cpShape.c,+ chipmunk-5.0/cpSpace.c,+ chipmunk-5.0/cpSpaceHash.c,+ chipmunk-5.0/cpVect.c,+ chipmunk-5.0/constraints/cpConstraint.c,+ chipmunk-5.0/constraints/cpDampedRotarySpring.c,+ chipmunk-5.0/constraints/cpDampedSpring.c,+ chipmunk-5.0/constraints/cpGearJoint.c,+ chipmunk-5.0/constraints/cpGrooveJoint.c,+ chipmunk-5.0/constraints/cpPinJoint.c,+ chipmunk-5.0/constraints/cpPivotJoint.c,+ chipmunk-5.0/constraints/cpRotaryLimitJoint.c,+ chipmunk-5.0/constraints/cpSimpleMotor.c,+ chipmunk-5.0/constraints/cpSlideJoint.c, Physics/Hipmunk/wrapper.c- Build-Depends: base if flag(small_base)- Build-Depends: array, containers+ Build-Depends: base >= 3 && < 5,+ array >= 0.1 && < 0.3,+ containers >= 0.1 && < 0.3+ else+ Build-Depends: base == 2 Extensions: CPP, ForeignFunctionInterface Build-Tools: hsc2hs GHC-Options: -Wall
NEWS view
@@ -1,3 +1,10 @@+Version 5.0.0+================+ - Updated for a prerelease of Chipmunk 5.0 from subversion+ revision 192. Besides bugfixes this new version brings the+ long awaited new constraints type, doubling the number of+ different joint from four to nine.+ Version 0.2.2 ============= - Update Chipmunk to version 4.1.0.
Physics/Hipmunk.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Physics/Hipmunk/Hipmunk.hs--- Copyright : (c) Felipe A. Lessa 2008+-- Copyright : (c) Felipe A. Lessa 2008-2009 -- License : MIT (see LICENSE) -- -- Maintainer : felipe.lessa@gmail.com@@ -23,7 +23,7 @@ (module Physics.Hipmunk.Common, module Physics.Hipmunk.Body, module Physics.Hipmunk.Shape,- module Physics.Hipmunk.Joint,+ module Physics.Hipmunk.Constraint, module Physics.Hipmunk.Space ) where@@ -31,5 +31,5 @@ import Physics.Hipmunk.Common import Physics.Hipmunk.Body import Physics.Hipmunk.Shape-import Physics.Hipmunk.Joint+import Physics.Hipmunk.Constraint import Physics.Hipmunk.Space
Physics/Hipmunk/Body.hsc view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Physics/Hipmunk/Body.hsc--- Copyright : (c) Felipe A. Lessa 2008+-- Copyright : (c) 2008-2009 Felipe A. Lessa -- License : MIT (see LICENSE) -- -- Maintainer : felipe.lessa@gmail.com@@ -62,7 +62,7 @@ applyForce, applyOnlyForce, applyImpulse,- dampedSpring,+ applyDampedSpring, -- * Utilities localToWorld,@@ -80,7 +80,7 @@ -- the given mass and moment of inertia. -- -- It is recommended to call 'setPosition' afterwards.-newBody :: CpFloat -> CpFloat -> IO Body+newBody :: Mass -> Moment -> IO Body newBody mass inertia = do b <- mallocForeignPtrBytes #{size cpBody} withForeignPtr b $ \ptr -> do@@ -227,7 +227,7 @@ -- -- Note that this function only needs to be called if you -- are not adding the body to a space.-updateVelocity :: Body -> Vector -> CpFloat -> Time -> IO ()+updateVelocity :: Body -> Vector -> Damping -> Time -> IO () updateVelocity (B b) g d dt = withForeignPtr b $ \b_ptr -> with g $ \g_ptr -> do@@ -306,21 +306,20 @@ -- is the time step to apply the force over. Both anchors are -- in body coordinates. ----- Note: not solving the damping forces in the impulse solver--- causes problems with large damping values. This function--- will eventually be replaced by a new constraint (joint) type.-dampedSpring :: (Body,Position) -> (Body,Position) -> CpFloat- -> CpFloat -> CpFloat -> Time -> IO ()-dampedSpring (B b1,a1) (B b2, a2) rlen k dmp dt =+-- Note: large damping values can be unstable, you should use+-- the damped spring constraint instead.+applyDampedSpring :: (Body,Position) -> (Body,Position) -> Distance+ -> CpFloat -> Damping -> Time -> IO ()+applyDampedSpring (B b1,a1) (B b2, a2) rlen k dmp dt = withForeignPtr b1 $ \b1_ptr -> withForeignPtr b2 $ \b2_ptr -> with a1 $ \a1_ptr -> with a2 $ \a2_ptr -> do- wrDampedSpring b1_ptr b2_ptr a1_ptr a2_ptr rlen k dmp dt+ wrApplyDampedSpring b1_ptr b2_ptr a1_ptr a2_ptr rlen k dmp dt foreign import ccall unsafe "wrapper.h"- wrDampedSpring :: BodyPtr -> BodyPtr -> VectorPtr -> VectorPtr- -> CpFloat -> CpFloat -> CpFloat -> Time -> IO ()+ wrApplyDampedSpring :: BodyPtr -> BodyPtr -> VectorPtr -> VectorPtr+ -> CpFloat -> CpFloat -> CpFloat -> Time -> IO () -- | For a vector @p@ in body @b@'s coordinates,
Physics/Hipmunk/Common.hsc view
@@ -1,23 +1,32 @@ {-# CFILES- chipmunk/chipmunk.c- chipmunk/cpArbiter.c- chipmunk/cpArray.c- chipmunk/cpBB.c- chipmunk/cpBody.c- chipmunk/cpCollision.c- chipmunk/cpHashSet.c- chipmunk/cpJoint.c- chipmunk/cpPolyShape.c- chipmunk/cpShape.c- chipmunk/cpSpace.c- chipmunk/cpSpaceHash.c- chipmunk/cpVect.c+ chipmunk-5.0/chipmunk.c,+ chipmunk-5.0/cpArbiter.c,+ chipmunk-5.0/cpArray.c,+ chipmunk-5.0/cpBB.c,+ chipmunk-5.0/cpBody.c,+ chipmunk-5.0/cpCollision.c,+ chipmunk-5.0/cpHashSet.c,+ chipmunk-5.0/cpPolyShape.c,+ chipmunk-5.0/cpShape.c,+ chipmunk-5.0/cpSpace.c,+ chipmunk-5.0/cpSpaceHash.c,+ chipmunk-5.0/cpVect.c,+ chipmunk-5.0/constraints/cpConstraint.c,+ chipmunk-5.0/constraints/cpDampedRotaryString.c,+ chipmunk-5.0/constraints/cpDampedString.c,+ chipmunk-5.0/constraints/cpGearJoint.c,+ chipmunk-5.0/constraints/cpGrooveJoint.c,+ chipmunk-5.0/constraints/cpPinJoint.c,+ chipmunk-5.0/constraints/cpPivotJoint.c,+ chipmunk-5.0/constraints/cpRotaryLimitJoint.c,+ chipmunk-5.0/constraints/cpSimpleMotor.c,+ chipmunk-5.0/constraints/cpSlideJoint.c, Physics/Hipmunk/wrapper.c #-} ----------------------------------------------------------------------------- -- | -- Module : Physics/Hipmunk/Common.hsc--- Copyright : (c) Felipe A. Lessa 2008+-- Copyright : (c) 2008-2009 Felipe A. Lessa -- License : MIT (see LICENSE) -- -- Maintainer : felipe.lessa@gmail.com@@ -38,6 +47,8 @@ infinity, Time, Angle,+ Distance,+ Damping, -- * Global variables -- $global_vars@@ -58,13 +69,14 @@ -- ** Bias coefficient -- $bias_coef+ BiasCoef, getBiasCoef, setBiasCoef, - -- ** Joint bias coefficient- -- $joint_bias_coef- getJointBiasCoef,- setJointBiasCoef,+ -- ** Constraint bias coefficient+ -- $constraint_bias_coef+ getConstraintBiasCoef,+ setConstraintBiasCoef, -- * Vectors Vector(..),@@ -84,6 +96,7 @@ where import Foreign hiding (rotate)+import Foreign.C.Types (CInt) #include "wrapper.h" error' :: String -> a@@ -114,25 +127,36 @@ -- represents an angle in radians. type Angle = CpFloat +-- | Type synonym used to hint that the argument or result+-- represents a distance.+type Distance = CpFloat +-- | Type synonym used to hint that the argument or result+-- represents a damping constant.+type Damping = CpFloat++ -- $global_vars--- Chipmunk tries to maintein a very few number of global--- variables to allow multiple 'Physics.Hipmunk.Space.Space's--- to be used simultaneously, however there are some.+-- Chipmunk tries to maintain a very few number of global+-- variables to allow multiple @Space@s to be used+-- simultaneously, however there are some. -- $shape_counter -- The shape counter is a global counter used for creating -- unique hash identifiers to the shapes. --- | @resetShapeCounter@ reset the shape counter to its default value.--- This is used to add determinism to a simulation. As the ids--- created with this counter may affect the order in which the--- collisions happen, there may be very slight differences in--- different simulations.+-- | @resetShapeCounter@ reset the shape counter to its default+-- value. This is used to add determinism to a simulation. As+-- the ids created with this counter may affect the order in+-- which the collisions happen, there may be very slight+-- differences in different simulations. It may be very useful+-- to call @resetShapeCounter@ everytime you start a new+-- simulation. -- -- However, be careful as you should not use shapes created--- before a call to @resetCounter@ with shapes created after--- it as they may have the same id.+-- before a call to @resetCounter@ with shapes created after it+-- as they may have the same id. This means that can't add+-- shapes created after the call to a space created before it. resetShapeCounter :: IO () resetShapeCounter = cpResetShapeIdCounter @@ -145,14 +169,14 @@ -- It should be small as the cached contacts will only be -- close for a short time. (default is 3) -getContactPersistence :: IO #{type int}+getContactPersistence :: IO CInt getContactPersistence = peek cp_contact_persistence -setContactPersistence :: #{type int} -> IO ()+setContactPersistence :: CInt -> IO () setContactPersistence = poke cp_contact_persistence foreign import ccall unsafe "wrapper.h &cp_contact_persistence"- cp_contact_persistence :: Ptr #{type int}+ cp_contact_persistence :: Ptr CInt -- $collision_slop@@ -175,35 +199,35 @@ -- The amount of penetration to reduce in each step. Values should -- range from 0 to 1. Using large values will eliminate penetration in -- fewer steps, but can cause vibration. (default is 0.1)+type BiasCoef = CpFloat -getBiasCoef :: IO CpFloat+getBiasCoef :: IO BiasCoef getBiasCoef = peek cp_bias_coef -setBiasCoef :: CpFloat -> IO ()+setBiasCoef :: BiasCoef -> IO () setBiasCoef = poke cp_bias_coef foreign import ccall unsafe "wrapper.h &cp_bias_coef" cp_bias_coef :: Ptr CpFloat --- $joint_bias_coef--- Similar to the bias coefficient, but for all joints. In the--- future, joints might have their own bias coefficient--- instead. (default is 0.1)+-- $constraint_bias_coef+-- Similar to the bias coefficient, but sets the default bias+-- for all constraints. (default is 0.1) -getJointBiasCoef :: IO CpFloat-getJointBiasCoef = peek cp_joint_bias_coef+getConstraintBiasCoef :: IO BiasCoef+getConstraintBiasCoef = peek cp_constraint_bias_coef -setJointBiasCoef :: CpFloat -> IO ()-setJointBiasCoef = poke cp_joint_bias_coef+setConstraintBiasCoef :: BiasCoef -> IO ()+setConstraintBiasCoef = poke cp_constraint_bias_coef -foreign import ccall unsafe "wrapper.h &cp_joint_bias_coef"- cp_joint_bias_coef :: Ptr CpFloat+foreign import ccall unsafe "wrapper.h &cp_constraint_bias_coef"+ cp_constraint_bias_coef :: Ptr CpFloat -- | A two-dimensional vector. It is an instance of 'Num'--- however the operations 'signum' and '(*)' are not+-- however the operations 'signum' and @(*)@ are not -- supported. data Vector = Vector !CpFloat !CpFloat deriving (Eq, Show, Ord)@@ -238,42 +262,51 @@ -- angle (in radians). fromAngle :: Angle -> Vector fromAngle theta = Vector (cos theta) (sin theta)+{-# INLINE fromAngle #-} -- | The length of a vector. len :: Vector -> CpFloat len (Vector x y) = sqrt $ x*x + y*y+{-# INLINE len #-} -- | Normalizes the vector (i.e. divides it by its length). normalize :: Vector -> Vector normalize v = v `scale` (recip $ len v)+{-# INLINE normalize #-} -- | Scales the components of a vector by the same amount. scale :: Vector -> CpFloat -> Vector scale (Vector x y) s = Vector (x*s) (y*s)+{-# INLINE scale #-} -- | @toAngle v@ is the angle that @v@ has -- with the vector @Vector 1 0@ (modulo @2*pi@). toAngle :: Vector -> Angle toAngle (Vector x y) = atan2 y x+{-# INLINE toAngle #-} -- | @v1 \`dot\` v2@ computes the familiar dot operation. dot :: Vector -> Vector -> CpFloat dot (Vector x1 y1) (Vector x2 y2) = x1*x2 + y1*y2+{-# INLINE dot #-} -- | @v1 \`cross\` v2@ computes the familiar cross operation. cross :: Vector -> Vector -> CpFloat cross (Vector x1 y1) (Vector x2 y2) = x1*y2 - y1*x2+{-# INLINE cross #-} -- | @perp v@ is a vector of same length as @v@ but perpendicular -- to @v@ (i.e. @toAngle (perp v) - toAngle v@ equals @pi\/2@ -- modulo @2*pi@). perp :: Vector -> Vector perp (Vector x y) = Vector (-y) x+{-# INLINE perp #-} -- | @v1 \`project\` v2@ is the vector projection of @v1@ onto @v2@. project :: Vector -> Vector -> Vector project v1 v2 = v2 `scale` s where s = (v1 `dot` v2) / (v2 `dot` v2)+{-# INLINE project #-} -- | @v1 \`rotate\` v2@ uses complex multiplication -- to rotate (and scale) @v1@ by @v2@.@@ -281,6 +314,7 @@ rotate (Vector x1 y1) (Vector x2 y2) = Vector x3 y3 where x3 = x1*x2 - y1*y2 y3 = x1*y2 + y1*x2+{-# INLINE rotate #-} -- | The inverse operation of @rotate@, such that -- @unrotate (rotate v1 v2) v2@ equals @v1@.@@ -288,3 +322,4 @@ unrotate (Vector x1 y1) (Vector x2 y2) = Vector x3 y3 where x3 = x1*x2 + y1*y2 y3 = y1*x2 - x1*y2+{-# INLINE unrotate #-}
+ Physics/Hipmunk/Constraint.hsc view
@@ -0,0 +1,315 @@+-----------------------------------------------------------------------------+-- |+-- Module : Physics/Hipmunk/Constraint.hsc+-- Copyright : (c) 2008-2009 Felipe A. Lessa+-- License : MIT (see LICENSE)+--+-- Maintainer : felipe.lessa@gmail.com+-- Stability : provisional+-- Portability : portable (needs FFI)+--+-- Constraints that restrict the bodies' movement.+--+-----------------------------------------------------------------------------++module Physics.Hipmunk.Constraint+ (-- * Common interface+ newConstraint,+ redefineC,+ setBiasCoefC,+ Constraint,+ -- ** Forgetting the phantom type+ -- $phantom+ Unknown,+ forgetC,++ -- * Constraint types+ -- $constraintTypes++ -- ** Pin joint+ Pin(..),+ -- ** Slide joint+ Slide(..),+ -- ** Pivot joint+ Pivot(..),+ -- ** Groove joint+ Groove(..),+ -- ** Gear joint+ Gear(..),+ -- ** Damped spring+ DampedSpring(..),+ -- ** Damped rotary spring+ DampedRotarySpring(..),+ -- ** Rotary limit+ RotaryLimit(..),+ -- ** Simple motor+ SimpleMotor(..),+ )+ where++import Foreign+#include "wrapper.h"++import Physics.Hipmunk.Common+import Physics.Hipmunk.Internal+import Physics.Hipmunk.Body (worldToLocal)+++-- | @newConstraint b1 b2 type_@ connects the two bodies @b1@ and @b2@+-- with a constraint of the given type. Note that you should+-- add the 'Constraint' to a space.+--+-- The 'ConstraintType' type class is implemented by all+-- constraint types to allow them to be manipulated by the same+-- framework while retaining type-safety, consequently it isn't+-- exported.+newConstraint :: ConstraintType a => Body -> Body -> a -> IO (Constraint a)+newConstraint body1@(B b1) body2@(B b2) type_ =+ withForeignPtr b1 $ \b1_ptr ->+ withForeignPtr b2 $ \b2_ptr ->+ mallocForeignPtrBytes (size type_) >>= \constraint ->+ withForeignPtr constraint $ \constraint_ptr -> do+ init_ type_ constraint_ptr b1_ptr b2_ptr+ return (C constraint body1 body2)+{-# SPECIALISE newConstraint :: Body -> Body -> Pin -> IO (Constraint Pin) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> Slide -> IO (Constraint Slide) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> Pivot -> IO (Constraint Pivot) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> Groove -> IO (Constraint Groove) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> Gear -> IO (Constraint Gear) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> DampedSpring -> IO (Constraint DampedSpring) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> DampedRotarySpring -> IO (Constraint DampedRotarySpring) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> RotaryLimit -> IO (Constraint RotaryLimit) #-}+{-# SPECIALISE newConstraint :: Body -> Body -> SimpleMotor -> IO (Constraint SimpleMotor) #-}++-- | @redefine constr type_@ redefines @constr@'s parameters+-- on-the-fly, allowing you to dynamically change the+-- constraint's behaviour.+redefineC :: ConstraintType a => Constraint a -> a -> IO ()+redefineC (C c b1 b2) t = withForeignPtr c $ \c_ptr -> redef c_ptr b1 b2 t+{-# SPECIALISE redefineC :: Constraint Pin -> Pin -> IO () #-}+{-# SPECIALISE redefineC :: Constraint Slide -> Slide -> IO () #-}+{-# SPECIALISE redefineC :: Constraint Pivot -> Pivot -> IO () #-}+{-# SPECIALISE redefineC :: Constraint Groove -> Groove -> IO () #-}+{-# SPECIALISE redefineC :: Constraint Gear -> Gear -> IO () #-}+{-# SPECIALISE redefineC :: Constraint DampedSpring -> DampedSpring -> IO () #-}+{-# SPECIALISE redefineC :: Constraint DampedRotarySpring -> DampedRotarySpring -> IO () #-}+{-# SPECIALISE redefineC :: Constraint RotaryLimit -> RotaryLimit -> IO () #-}+{-# SPECIALISE redefineC :: Constraint SimpleMotor -> SimpleMotor -> IO () #-}++-- | Sets the constraint's bias coefficient. By default it is+-- equal to the last value set globally with+-- 'setConstraintBiasCoef', which initially is @0.1@+setBiasCoefC :: BiasCoef -> Constraint a -> IO ()+setBiasCoefC b (C c _ _) = withForeignPtr c $ flip #{poke cpConstraint, biasCoef} b++-- $phantom+-- These functions discard the phantom type of the constraint.+-- They're useful, for example, if you want to put different+-- constraints in a homogeneous data structure (such as a+-- list).++-- | Completely safe function that discards the constraint type+-- (which is a phantom type). You can \"remember\" it again by+-- using @unsafeRemember@ from the @Unsafe@ module.+forgetC :: Constraint a -> Constraint Unknown+forgetC (C c b1 b2) = C c b1 b2+{-# INLINE forgetC #-}++++-- $constraintTypes+-- There are currently nine types of constraints. When+-- appending a number to a property, we hint that it refer to+-- one of the bodies that the constraint is intercting with+-- (e.g. \"Second anchor\" is the position of the anchor on the+-- second body in its coordinates).++-- | A pin joint connects the bodies with a solid pin.+-- The anchor points are kept at a fixed distance.+data Pin = Pin {pinAnchor1 :: !Position {-^ First anchor. -}+ ,pinAnchor2 :: !Position {-^ Second anchor. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType Pin where+ size _ = #{size cpPinJoint}+ init_ (Pin a1 a2) = with2 a1 a2 $ wrPinJointInit+ redef ptr _ _ (Pin a1 a2) = do+ #{poke cpPinJoint, anchr1} ptr a1+ #{poke cpPinJoint, anchr2} ptr a2++-- | A slide joint is similar to a pin joint, however+-- it has a minimum and a maximum distance.+data Slide = Slide {slideAnchor1 :: !Position {-^ First anchor. -}+ ,slideAnchor2 :: !Position {-^ Second anchor. -}+ ,slideMinDist :: !Distance {-^ Minimum distance. -}+ ,slideMaxDist :: !Distance {-^ Maximum distance. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType Slide where+ size _ = #{size cpSlideJoint}+ init_ (Slide a1 a2 mn mx) = with2 a1 a2 $ wrSlideJointInit mn mx+ redef ptr _ _ (Slide a1 a2 mn mx) = do+ #{poke cpSlideJoint, anchr1} ptr a1+ #{poke cpSlideJoint, anchr2} ptr a2+ #{poke cpSlideJoint, min} ptr mn+ #{poke cpSlideJoint, max} ptr mx++-- | A pivot joint allows the bodies to pivot around+-- a single point.+data Pivot =+ -- | You may specify the pivot point in world's coordinates+ -- (so both bodies should be already in place).+ Pivot1 {pivotPos :: !Position {-^ Pivot point in world's coordinates. -}}+ -- | Or you may specify the joint as two anchors (on each+ -- body's coordinates), removing the need having the bodies+ -- already in place.+ | Pivot2 {pivotAnchor1 :: !Position {-^ First anchor. -}+ ,pivotAnchor2 :: !Position {-^ Second anchor. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType Pivot where+ size _ = #{size cpPivotJoint}+ init_ (Pivot1 pos) = with1 pos $ wrPivot1JointInit+ init_ (Pivot2 a1 a2) = with2 a1 a2 $ wrPivot2JointInit+ redef ptr b1 b2 (Pivot1 pos) = do+ worldToLocal b1 pos >>= #{poke cpPivotJoint, anchr1} ptr+ worldToLocal b2 pos >>= #{poke cpPivotJoint, anchr2} ptr+ redef ptr _ _ (Pivot2 a1 a2) = do+ #{poke cpPivotJoint, anchr1} ptr a1+ #{poke cpPivotJoint, anchr2} ptr a2++-- | A groove joint attaches a point on the second body+-- to a groove in the first one.+data Groove = Groove {+ groovePoints :: !(Position,Position) {-^ Groove, in first body's coordinates. -}+ ,groovePivot :: !Position {-^ Pivot, in second body's coordinates. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType Groove where+ size _ = #{size cpGrooveJoint}+ init_ (Groove (g1,g2) anchor) = with3 g1 g2 anchor $ wrGrooveJointInit+ redef ptr _ _ (Groove (g1,g2) anchor) = do+ #{poke cpGrooveJoint, grv_a} ptr g1+ #{poke cpGrooveJoint, grv_b} ptr g2+ #{poke cpGrooveJoint, grv_n} ptr $ perp $ normalize $ g1 - g2+ #{poke cpGrooveJoint, anchr2} ptr anchor++-- | A gear joint restricts the bodies movement to be+-- coordinated as if they were attached like dented gears.+data Gear = Gear {gearPhase :: !Angle {-^ Phase of the movement. -}+ ,gearRatio :: !CpFloat {-^ Ratio between the gears. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType Gear where+ size _ = #{size cpGearJoint}+ init_ (Gear p r) = wrGearJointInit p r+ redef ptr _ _ (Gear p r) = do+ #{poke cpGearJoint, phase} ptr p+ #{poke cpGearJoint, ratio} ptr r++-- | A simple damped spring. Generally this constraint+-- should be used instead of @applyDampedSpring@.+data DampedSpring = DampedSpring {+ dampedAnchor1 :: !Position {-^ First anchor. -}+ ,dampedAnchor2 :: !Position {-^ Second anchor. -}+ ,dampedRestLength :: !Distance {-^ Rest length. -}+ ,dampedStiffness :: !CpFloat {-^ Stiffness. -}+ ,dampedDamping :: !Damping {-^ Damping. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType DampedSpring where+ size _ = #{size cpDampedSpring}+ init_ (DampedSpring a1 a2 r s d) = with2 a1 a2 $ wrDampedSpringInit r s d+ redef ptr _ _ (DampedSpring a1 a2 r s d) = do+ #{poke cpDampedSpring, anchr1} ptr a1+ #{poke cpDampedSpring, anchr2} ptr a2+ #{poke cpDampedSpring, restLength} ptr r+ #{poke cpDampedSpring, stiffness} ptr s+ #{poke cpDampedSpring, damping} ptr d++-- | A damped rotary spring constraint.+data DampedRotarySpring = DampedRotarySpring {+ dampedRotRestAngle :: !Angle {-^ Rest angle. -}+ ,dampedRotStiffness :: !CpFloat {-^ Stiffness. -}+ ,dampedRotDamping :: !Damping {-^ Damping. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType DampedRotarySpring where+ size _ = #{size cpDampedRotarySpring}+ init_ (DampedRotarySpring r s d) = wrDampedRotarySpringInit r s d+ redef ptr _ _ (DampedRotarySpring r s d) = do+ #{poke cpDampedRotarySpring, restAngle} ptr r+ #{poke cpDampedRotarySpring, stiffness} ptr s+ #{poke cpDampedRotarySpring, damping} ptr d++-- | A rotary limit constraints the difference of angle+-- between two bodies.+data RotaryLimit = RotaryLimit {+ rotaryMinDist :: Distance {-^ Minimum distance. -}+ ,rotaryMaxDist :: Distance {-^ Maximum distance. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType RotaryLimit where+ size _ = #{size cpRotaryLimitJoint}+ init_ (RotaryLimit mn mx) = wrRotaryLimitJointInit mn mx+ redef ptr _ _ (RotaryLimit mn mx) = do+ #{poke cpRotaryLimitJoint, min} ptr mn+ #{poke cpRotaryLimitJoint, max} ptr mx++-- | A simple motor that applies opposite impulses to each+-- body. The rate is used to compute the torque.+data SimpleMotor = SimpleMotor {+ simpleMotorRate :: CpFloat {-^ Rate. -}}+ deriving (Eq, Ord, Show)++instance ConstraintType SimpleMotor where+ size _ = #{size cpSimpleMotor}+ init_ (SimpleMotor r) = wrSimpleMotorInit r+ redef ptr _ _ (SimpleMotor r) = do+ #{poke cpSimpleMotor, rate} ptr r+++++++-- | Helper functions similar to 'with'.+with1 :: (Storable a) => a -> (Ptr a -> ConstraintInit) -> ConstraintInit+with1 x f c b1 b2 =+ with x $ \x_ptr ->+ f x_ptr c b1 b2+with2 :: (Storable a, Storable b) => a -> b+ -> (Ptr a -> Ptr b -> ConstraintInit) -> ConstraintInit+with2 x y f c b1 b2 =+ with x $ \x_ptr ->+ with y $ \y_ptr ->+ f x_ptr y_ptr c b1 b2+with3 :: (Storable a, Storable b, Storable c) => a -> b -> c+ -> (Ptr a -> Ptr b -> Ptr c -> ConstraintInit) -> ConstraintInit+with3 x y z f c b1 b2 =+ with x $ \x_ptr ->+ with y $ \y_ptr ->+ with z $ \z_ptr ->+ f x_ptr y_ptr z_ptr c b1 b2++-- Boring imports+foreign import ccall unsafe "wrapper.h"+ wrPinJointInit :: VectorPtr -> VectorPtr -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrSlideJointInit :: CpFloat -> CpFloat -> VectorPtr -> VectorPtr -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrPivot1JointInit :: VectorPtr -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrPivot2JointInit :: VectorPtr -> VectorPtr -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrGearJointInit :: CpFloat -> CpFloat -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrGrooveJointInit :: VectorPtr -> VectorPtr -> VectorPtr -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrDampedSpringInit :: CpFloat -> CpFloat -> CpFloat -> VectorPtr -> VectorPtr -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrDampedRotarySpringInit :: CpFloat -> CpFloat -> CpFloat -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrRotaryLimitJointInit :: CpFloat -> CpFloat -> ConstraintInit+foreign import ccall unsafe "wrapper.h"+ wrSimpleMotorInit :: CpFloat -> ConstraintInit
Physics/Hipmunk/Internal.hsc view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Physics/Hipmunk/Internal.hsc--- Copyright : (c) Felipe A. Lessa 2008+-- Copyright : (c) 2008-2009 Felipe A. Lessa -- License : MIT (see LICENSE) -- -- Maintainer : felipe.lessa@gmail.com@@ -21,9 +21,12 @@ Shape(..), unS, - JointPtr,- Joint(..),- unJ,+ ConstraintPtr,+ Constraint(..),+ unC,+ Unknown(..),+ ConstraintInit,+ ConstraintType(..), SpacePtr, Space(..),@@ -46,9 +49,9 @@ --- | A rigid body representing the physical properties of an object,--- but without a shape. It may help to think as a particle that--- is able to rotate.+-- | A rigid body representing the physical properties of an+-- object, but without a shape. It may help to think of it as a+-- particle that is able to rotate. newtype Body = B (ForeignPtr Body) type BodyPtr = Ptr Body @@ -63,7 +66,7 @@ --- | A collision shape is attached to a @Body@ to define its+-- | A collision shape is attached to a 'Body' to define its -- shape. Multiple shapes may be attached, including -- overlapping ones (shapes of a body don't generate collisions -- with each other).@@ -95,24 +98,39 @@ --- | A joint represents a constrain between two bodies. Don't--- forget to add the bodies and the joint to the space.-data Joint = J !(ForeignPtr Joint) !Body !Body-type JointPtr = Ptr Joint+-- | Represents a constraint between two bodies. Don't forget to+-- add the bodies and the constraint itself to the space.+-- The phantom type indicates the type of the constraint.+data Constraint a = C !(ForeignPtr (Constraint ())) !Body !Body+type ConstraintPtr = Ptr (Constraint ()) -unJ :: Joint -> ForeignPtr Joint-unJ (J j _ _) = j+unC :: Constraint a -> ForeignPtr (Constraint ())+unC (C j _ _) = j -instance Eq Joint where- J j1 _ _ == J j2 _ _ = j1 == j2+instance Eq (Constraint a) where+ C j1 _ _ == C j2 _ _ = j1 == j2 -instance Ord Joint where- J j1 _ _ `compare` J j2 _ _ = j1 `compare` j2+instance Ord (Constraint a) where+ C j1 _ _ `compare` C j2 _ _ = j1 `compare` j2 +-- | An unknown constraint \"type\". Note that this isn't a+-- 'ConstraintType' because you can't create a constraint of+-- @Unknown@ type.+data Unknown = Unknown +-- | Type of generic constraint initializar.+type ConstraintInit = ConstraintPtr -> BodyPtr -> BodyPtr -> IO () +-- | Class implemented by all constraint types.+class ConstraintType a where+ size :: a -> Int+ init_ :: a -> ConstraintInit+ redef :: ConstraintPtr -> Body -> Body -> a -> IO ()+++ -- | A space is where the simulation really occurs. You add--- bodies, shapes and joints to a space and then step it+-- bodies, shapes and constraints to a space and then step it -- to update it as whole. data Space = P !(ForeignPtr Space) !(IORef Entities) -- Active and static entities@@ -120,8 +138,9 @@ type SpacePtr = Ptr Space type Entities = Map (Ptr ()) (Either (ForeignPtr ()) Shape) type Callbacks = (Maybe (FunPtr ()), -- Default- Map (#{type unsigned int}, #{type unsigned int})- (FunPtr ()))+ Map (CollisionType_, CollisionType_) (FunPtr ()))+type CollisionType_ = #{type cpCollisionType}+-- Duplicated to avoid bringing the documentation from Shape module. unP :: Space -> ForeignPtr Space unP (P sp _ _) = sp@@ -147,10 +166,10 @@ -- contains garbage), and by extension you can only know -- the impulse sum after @step@ returns as well. ----- /IMPORTANT:/ You may maintain a reference to an array--- of @Contact@s that was passed to a callback to do any other--- processing later. However, /a new call to /@step@/ will--- invalidate any of those arrays/! Be careful.+-- /IMPORTANT:/ You may maintain a reference to an array of+-- @Contact@s that was passed to a callback to do any other+-- processing later. However, /a new call to/ @step@ /will/+-- /invalidate any of those arrays!/ Be careful. data Contact = Contact { ctPos :: Position, -- ^ Position of the collision in world's coordinates.
− Physics/Hipmunk/Joint.hsc
@@ -1,113 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Physics/Hipmunk/Joint.hsc--- Copyright : (c) Felipe A. Lessa 2008--- License : MIT (see LICENSE)------ Maintainer : felipe.lessa@gmail.com--- Stability : provisional--- Portability : portable (needs FFI)------ Joints that constrain bodies.-----------------------------------------------------------------------------------module Physics.Hipmunk.Joint- (-- * Joints- Joint,- JointType(..),- newJoint- )- where--import Foreign-#include "wrapper.h"--import Physics.Hipmunk.Common-import Physics.Hipmunk.Internal----- | There are currently four types of joints. When appending--- a number to a property, we hint that it refer to one of--- the bodies that the joint is contraining (e.g. @anchor2@--- is the position of the anchor on the second body in its--- coordinates).-data JointType =- -- | A pin joint connects the bodies with a solid pin.- -- The anchor points are kept at a fixed distance.- Pin {anchor1, anchor2 :: Position}-- -- | A slide joint is similar to a pin joint, however- -- it has a minimum and a maximum distance.- | Slide {anchor1, anchor2 :: Position,- minDist, maxDist :: CpFloat}-- -- | A pivot joint allows the bodies to pivot around- -- a single point in world's coordinates. Both should- -- be already in place.- | Pivot {pivot :: Position}-- -- | A groove joint attaches a point on the second body- -- to a groove in the first one.- | Groove {groove1 :: (Position, Position),- pivot2 :: Position}- deriving (Eq, Ord, Show)----- | @newJoint b1 b2 type@ connects the two bodies @b1@ and @b2@--- with a joint of the given type. Note that you should--- add the 'Joint' to a space.-newJoint :: Body -> Body -> JointType -> IO Joint-newJoint body1@(B b1) body2@(B b2) (Pin a1 a2) =- withForeignPtr b1 $ \b1_ptr ->- withForeignPtr b2 $ \b2_ptr ->- with a1 $ \a1_ptr ->- with a2 $ \a2_ptr ->- mallocForeignPtrBytes #{size cpPinJoint} >>= \joint ->- withForeignPtr joint $ \joint_ptr -> do- wrPinJointInit joint_ptr b1_ptr b2_ptr a1_ptr a2_ptr- return (J joint body1 body2)--newJoint body1@(B b1) body2@(B b2) (Slide a1 a2 mn mx) =- withForeignPtr b1 $ \b1_ptr ->- withForeignPtr b2 $ \b2_ptr ->- with a1 $ \a1_ptr ->- with a2 $ \a2_ptr ->- mallocForeignPtrBytes #{size cpSlideJoint} >>= \joint ->- withForeignPtr joint $ \joint_ptr -> do- wrSlideJointInit joint_ptr b1_ptr b2_ptr a1_ptr a2_ptr mn mx- return (J joint body1 body2)--newJoint body1@(B b1) body2@(B b2) (Pivot pos) =- withForeignPtr b1 $ \b1_ptr ->- withForeignPtr b2 $ \b2_ptr ->- with pos $ \pos_ptr ->- mallocForeignPtrBytes #{size cpPivotJoint} >>= \joint ->- withForeignPtr joint $ \joint_ptr -> do- wrPivotJointInit joint_ptr b1_ptr b2_ptr pos_ptr- return (J joint body1 body2)--newJoint body1@(B b1) body2@(B b2) (Groove (g1,g2) anchor) =- withForeignPtr b1 $ \b1_ptr ->- withForeignPtr b2 $ \b2_ptr ->- with g1 $ \g1_ptr ->- with g2 $ \g2_ptr ->- with anchor $ \anchor_ptr ->- mallocForeignPtrBytes #{size cpGrooveJoint} >>= \joint ->- withForeignPtr joint $ \joint_ptr -> do- wrGrooveJointInit joint_ptr b1_ptr b2_ptr g1_ptr g2_ptr anchor_ptr- return (J joint body1 body2)--foreign import ccall unsafe "wrapper.h"- wrPinJointInit :: JointPtr -> BodyPtr -> BodyPtr- -> VectorPtr -> VectorPtr -> IO ()-foreign import ccall unsafe "wrapper.h"- wrSlideJointInit :: JointPtr -> BodyPtr -> BodyPtr -> VectorPtr- -> VectorPtr -> CpFloat -> CpFloat -> IO ()-foreign import ccall unsafe "wrapper.h"- wrPivotJointInit :: JointPtr -> BodyPtr -> BodyPtr- -> VectorPtr -> IO ()-foreign import ccall unsafe "wrapper.h"- wrGrooveJointInit :: JointPtr -> BodyPtr -> BodyPtr- -> VectorPtr -> VectorPtr -> VectorPtr -> IO ()-
Physics/Hipmunk/Shape.hsc view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Physics/Hipmunk/Shape.hsc--- Copyright : (c) Felipe A. Lessa 2008+-- Copyright : (c) 2008-2009 Felipe A. Lessa -- License : MIT (see LICENSE) -- -- Maintainer : felipe.lessa@gmail.com@@ -47,9 +47,12 @@ -- * Utilities getBody,+ moment, momentForCircle,+ momentForSegment, momentForPoly,- shapeQuery,+ shapePointQuery,+ shapeSegmentQuery, -- ** For polygons -- $polygon_util@@ -74,13 +77,14 @@ import Physics.Hipmunk.Common import Physics.Hipmunk.Internal+import Physics.Hipmunk.Body (Mass, Moment) -- | There are three types of shapes that can be attached -- to bodies: data ShapeType = -- | A circle is the fastest collision type. It also -- rolls smoothly.- Circle {radius :: !CpFloat}+ Circle {radius :: !Distance} -- | A line segment is meant to be used as a static -- shape. (It can be used with moving bodies, however@@ -88,7 +92,7 @@ -- each other.) | LineSegment {start :: !Position, end :: !Position,- thickness :: !CpFloat}+ thickness :: !Distance} -- | Polygons are the slowest of all shapes but -- the most flexible. The list of vertices must form@@ -146,17 +150,17 @@ -- | @getBody s@ is the body that this shape is associated--- to. Useful especially in 'Physics.Hipmunk.Space.Callback'.+-- to. Useful especially in a space callback. getBody :: Shape -> Body getBody (S _ b) = b -- | The collision type is used to determine which collision--- 'Physics.Hipmunk.Space.Callback' will be called. Its--- actual value doesn't have a meaning for Chipmunk other--- than the correspondence between shapes and the collision--- pair functions you add. (default is zero)-type CollisionType = #{type unsigned int}+-- callback will be called. Its actual value doesn't have a+-- meaning for Chipmunk other than the correspondence between+-- shapes and the collision pair functions you add. (default is+-- zero)+type CollisionType = #{type cpCollisionType} getCollisionType :: Shape -> IO CollisionType getCollisionType (S shape _) = withForeignPtr shape #{peek cpShape, collision_type}@@ -175,7 +179,7 @@ -- objects such as ragdolls. It may be thought as a lightweight -- alternative to creating a callback that filters the -- collisions.-type Group = #{type unsigned int}+type Group = #{type cpGroup} getGroup :: Shape -> IO Group getGroup (S shape _) = withForeignPtr shape #{peek cpShape, group}@@ -187,11 +191,11 @@ -- | Layers are similar to groups, but use a bitmask. For a collision -- to occur, two shapes must have at least one layer in common. -- In other words, @layer1 .&. layer2@ should be non-zero.--- (default is @0xFFFF@)+-- (default is @-1@, meaning all bits set) -- -- Note that although this type may have more than 32 bits, -- for portability you should only rely on the lower 32 bits.-type Layers = #{type unsigned int}+type Layers = #{type cpLayers} getLayers :: Shape -> IO Layers getLayers (S shape _) = withForeignPtr shape #{peek cpShape, layers}@@ -208,12 +212,11 @@ -- calculated by multiplying the elasticity of both shapes. -- (default is zero) ----- /IMPORTANT:/ by default no elastic iterations are done--- when the space 'Physics.Hipmunk.Space.step's. This means--- that all shapes react as they had zero elasticity.--- So, if you want some elasticity, remember to call--- 'Physics.Hipmunk.Space.setElasticIterations' to something--- greater than zero, maybe @10@.+-- /IMPORTANT:/ by default old-style elastic iterations are+-- done when the space @step@s, which may result in a+-- not-so-good simulation. It may be a good idea to use+-- @setElasticIterations@ with something greater than zero,+-- maybe @10@. type Elasticity = CpFloat getElasticity :: Shape -> IO Elasticity getElasticity (S shape _) =@@ -256,21 +259,42 @@ ++-- | @moment m s off@ is a convenience function that calculates+-- the moment of inertia for shape @s@ with mass @m@ and at a+-- offset @off@ of the body's center. Uses 'momentForCircle',+-- 'momentForSegment' and 'momentForPoly' internally.+moment :: Mass -> ShapeType -> Position -> Moment+moment m (Circle r) off = m*(r*r + (off `dot` off))+moment m (LineSegment p1 p2 _) off = momentForSegment m (p1+off) (p2+off)+moment m (Polygon verts) off = momentForPoly m verts off+ -- | @momentForCircle m (ri,ro) off@ is the moment of inertia -- of a circle of @m@ mass, inner radius of @ri@, outer radius -- of @ro@ and at an offset @off@ from the center of the body.-momentForCircle :: CpFloat -> (CpFloat, CpFloat) -> Position -> CpFloat+momentForCircle :: Mass -> (Distance, Distance) -> Position -> Moment momentForCircle m (ri,ro) off = (m/2)*(ri*ri + ro*ro) + m*(off `dot` off) -- We recoded the C function to avoid FFI and unsafePerformIO -- on this simple function. +-- | @momentForSegment m p1 p2@ is the moment of inertia of a+-- segment of mass @m@ going from point @p1@ to point @p2@.+momentForSegment :: Mass -> Position -> Position -> Moment+momentForSegment m p1 p2 =+ let len' = len (p2 - p1)+ offset = scale (p1 + p2) (recip 2)+ in m * len' * len' / 12 + m * offset `dot` offset+-- We recoded the C function to avoid FFI and unsafePerformIO+-- on this simple function.++ -- | @momentForPoly m verts off@ is the moment of inertia of a -- polygon of @m@ mass, at offset @off@ from the center of -- the body and comprised of @verts@ vertices. This is similar--- to 'shapePoly' (and the same restrictions for the vertices+-- to 'Polygon' (and the same restrictions for the vertices -- apply as well).-momentForPoly :: CpFloat -> [Position] -> Position -> CpFloat+momentForPoly :: Mass -> [Position] -> Position -> Moment momentForPoly m verts off = (m*sum1)/(6*sum2) where verts' = if off /= 0 then map (+off) verts else verts@@ -290,21 +314,45 @@ pairs :: (a -> a -> b) -> [a] -> [b] pairs f l = zipWith f l (tail $ cycle l) --- | @shapeQuery shape p@ returns @True@ iff the point in--- position @p@ (in world's coordinates) lies within--- the shape @shape@.-shapeQuery :: Shape -> Position -> IO Bool-shapeQuery (S shape _) p =+-- | @shapePointQuery shape p l g@ returns @True@ iff the point+-- in position @p@ (in world's coordinates) lies within the+-- shape @shape@, is not of the same group and share at least+-- one layer.+shapePointQuery :: Shape -> Position -> Layers -> Group -> IO Bool+shapePointQuery (S shape _) p layers group = withForeignPtr shape $ \shape_ptr -> with p $ \p_ptr -> do- i <- wrShapePointQuery shape_ptr p_ptr+ i <- wrShapePointQuery shape_ptr p_ptr layers group return (i /= 0) foreign import ccall unsafe "wrapper.h"- wrShapePointQuery :: ShapePtr -> VectorPtr -> IO CInt+ wrShapePointQuery :: ShapePtr -> VectorPtr -> Layers -> Group -> IO CInt +-- | @shapeSegmentQuery shape p1 p2 l g@ returns @Just (t,n)@ iff+-- the segment from @p1@ to @p2@ (in world's coordinates)+-- intersects with the shape @shape@, is not of the same group+-- and share at least one layer. In that case, @0 <= t <= 1@+-- indicates that one of the intersections is at point @p1 ++-- (p2 - p1) \`scale\` t@ with normal @n@.+shapeSegmentQuery :: Shape -> Position -> Position -> Layers -> Group+ -> IO (Maybe (CpFloat, Vector))+shapeSegmentQuery (S shape _) p1 p2 layers group =+ withForeignPtr shape $ \shape_ptr ->+ with p1 $ \p1_ptr ->+ with p2 $ \p2_ptr ->+ allocaBytes #{size cpSegmentQueryInfo} $ \info_ptr -> do+ i <- wrShapeSegmentQuery shape_ptr p1_ptr p2_ptr layers group info_ptr+ if (i == 0) then return Nothing else do+ t <- #{peek cpSegmentQueryInfo, t} info_ptr+ n <- #{peek cpSegmentQueryInfo, n} info_ptr+ return $ Just (t, n) +foreign import ccall unsafe "wrapper.h"+ wrShapeSegmentQuery :: ShapePtr -> VectorPtr -> VectorPtr+ -> Layers -> Group -> Ptr () -> IO CInt ++ -- $polygon_util -- This section is inspired by @pymunk.util@, -- a Python module made from <http://code.google.com/p/pymunk/>,@@ -429,7 +477,7 @@ -- Note that a very small polygon may be completely \"eaten\" -- if all its vertices are within a @delta@ radius from the -- first.-polyReduce :: CpFloat -> [Position] -> [Position]+polyReduce :: Distance -> [Position] -> [Position] polyReduce delta = go where go (p1:p2:ps) | len (p2-p1) < delta = go (p1:ps)@@ -483,190 +531,3 @@ | otherwise = go min_ (y:acc) ys go min_ acc [] = (min_, acc) ----{----- | /O((n+k)log n)/ [where /k/ is the number of intersections].--- @intersections segs@ is the list of all intersections--- found between the list @segs@ of line segments. Each--- intersection is represented as two integers meant--- to be interpreted as two indexes of @segs@ (zero being--- the first line segment).------ It is a implementation of the Bentley-Ottmann algorithm (see--- <http://geometryalgorithms.com/Archive/algorithm_0108/algorithm_0108.htm>--- for example), however intersection points are \"returned\"--- as soon as they are found. That is, the WHNF of @intersections segs@--- only needs to calculate the necessary to find the first--- intersection, so if you want to know only if there is a--- an intersection or not then you only need /O(n log n)/ time.------ (Note that the @segs@ does not need to be a polygon at all.)-intersections :: [Segment] -> [InterIndexes]-intersections = bentleyOttmann . zip [0..]--type InterIndexes = (Intersection, SegmentIndex, SegmentIndex)------ Basic data types-type SegmentIndex = Int-type SegmentArray = Array SegmentIndex Segment-type IndSeg = (SegmentIndex, Segment)-type Neighbors = (SegmentIndex, SegmentIndex)-data Event = EvStart !Position !SegmentIndex- | EvEnd !Position !SegmentIndex- | EvInter !Position !SegmentIndex !SegmentIndex- deriving (Eq)--instance Ord Event where- e1 `compare` e2 = case evPos e1 `compare` evPos e2 of- EQ -> evIdent e1 `compare` evIdent e2- ot -> ot- where- evIdent (EvStart _ i) = (-2, i)- evIdent (EvEnd _ i) = (-1, i)- evIdent (EvInter _ i j) = (i, j)--evPos :: Event -> Position-evPos (EvStart p _) = p-evPos (EvEnd p _) = p-evPos (EvInter p _ _) = p--interErr :: a-interErr = error . ("Physics.Hipmunk.Shape.intersections: " ++)--interDebug :: Bool -> Bool---interDebug = const False-interDebug = id----- Event queue (a priority queue)-data EventQueue = EQNil- | EQBranch !Event EventQueue EventQueue--eqSingle :: Event -> EventQueue-eqSingle ev = EQBranch ev EQNil EQNil--eqGet :: EventQueue -> (Event, EventQueue)-eqGet EQNil = interErr "[eqGet] never get here"-eqGet (EQBranch ev q1 q2) = (ev, eqMerge q1 q2)--eqMerge :: EventQueue -> EventQueue -> EventQueue-eqMerge EQNil other = other-eqMerge other EQNil = other-eqMerge left@(EQBranch evL _ _) right@(EQBranch evR r1 r2)- = case ev `compare` ev' of- LT -> helper left right- GT -> helper right left- EQ -> eqMerge left (eqMerge r1 r2) -- Discard ev'!- | ev <= ev' = helper left right- | otherwise = helper right left- where- helper (EQBranch ev EQNil q2) r = EQBranch ev r q2- helper (EQBranch ev q1 q2) r = EQBranch ev q2 (eqMerge q1 r)--eqInsert :: Event -> EventQueue -> EventQueue-eqInsert ev q = eqMerge q (eqSingle ev)--eqFromList :: [Event] -> EventQueue-eqFromList evs = foldr eqMerge EQNil . map eqSingle--eqRun :: (Event -> EventQueue -> ([a], EventQueue)) -> EventQueue -> [a]-eqRun _ EQNil = []-eqRun f q = case uncurry f $ eqGet q of- (xs, q') -> xs ++ eqRun f q'----- Sweep line-type SweepElemRef = IORef (Maybe SweepElem)-data SweepElem = SE !SegmentIndex !SweepElemRef !SweepElemRef-type SweepLine = (IM.IntMap Position, SweepElem)--slEmpty :: SweepLine-slEmpty = IM.empty--slInsert :: SegmentIndex -> SweepLine -> IO (SweepLine, [Neighbors])-slInsert s sl = do- newLeft <- newIORef Nothing- newRight <- newIORef Nothing- let newElem = SE s newLeft newRight-- let update _ set | IM.null set = return []- update left set = do- let (extrm, oldElem@(SE _ l r)) = f set- where f = if left then IM.findMax else IM.findMin- let newRef = (if left then newLeft else newRight)- oldRef = (if left then r else l)- old <- readIORef oldRef- writeIORef oldRef newElem- writeIORef newRef oldElem- return [extrm]-- let (ltSet, gtSet) = IM.split s sl- l <- update True ltSet- r <- update False gtSet- return (IM.insert s newElem sl, l ++ r)--slSwap :: Neighbors -> SweepLine -> (SweepLine, [Neighbors])-slSwap (s1,s2) sl =- let (s1L, s1R) = sl IM.! s1- (s2L, s2R) = sl IM.! s2-- newSl = IM.insert s1 (s2L, s2R) $- IM.insert s2 (s1L, s1R) $ sl- changes = (if s1L == siNone then id else ((s1L,s2):))- (if s2R == siNone then [] else [(s1,s2R)])- in if interDebug (s1R /= s2 || s2L /= s1)- then interErr "[slSwap] they're not neighbors!"- else (newSl, changes)------- -- This looks like Data.Set, however with some peculiarities.--- type SLSize = Int--- data SweepLine = SLNil--- | SLBranch !SLSize !SegmentIndex SweepLine SweepLine---- slSize :: SweepLine -> SLSize--- slSize SLNil = 0--- slSize (SLBranch size _ _ _) = size---- slSingle :: SegmentIndex -> SweepLine--- slSingle s = SLBranch 1 s SLNil SLNil---- slInsert :: SegmentIndex -> SweepLine -> SweepLine--- slInsert s SLNil = slSingle s--- slInsert s (SLBranch size t l r) =--- case s `compare` t of--- LT -> slBalance t (slInsert s l) r--- GT -> slBalance t l (slInsert s r)--- EQ -> interErr "[slInsert] segment already on sweepline"---- slRemove :: SegmentIndex -> SweepLine -> SweepLine--- slRemove s SLNil = interErr "[slRemove] segment not on sweepline"--- slRemove s (SLBranch size t l r) =--- case s `compare` t of--- LT -> slBalance t (slRemove s l) r--- GT -> slBalance t l (slRemove s r)---- slBalance----- Bentley-Ottmann functions-boEvents :: IndSeg -> [Event]-boEvents (index, a0,a1) = [EvStart start index, EvEnd end index]- where (start,end) | a0 < a1 = (a0,a1)- | otherwise = (a1,a0)--bentleyOttmann :: [IndSeg] -> [InterIndexes]-bentleyOttmann isegs = eqRun go . eqFromList . concatMap boEvents- where- segArray = array (0, length isegs - 1) isegs-- go EQNil = []- go------------ END OF BENTLEY-OTTMANN ------------}
Physics/Hipmunk/Space.hsc view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Physics/Hipmunk/Space.hsc--- Copyright : (c) Felipe A. Lessa 2008+-- Copyright : (c) 2008-2009 Felipe A. Lessa -- License : MIT (see LICENSE) -- -- Maintainer : felipe.lessa@gmail.com@@ -38,7 +38,6 @@ getGravity, setGravity, -- ** Damping- Damping, getDamping, setDamping, -- ** Time stamp@@ -52,7 +51,6 @@ rehashStatic, -- ** Point query -- $point_query- QueryType(..), spaceQuery, spaceQueryList, @@ -78,6 +76,7 @@ import Data.IORef import qualified Data.Map as M import Foreign hiding (new)+import Foreign.C.Types (CInt) #include "wrapper.h" import Physics.Hipmunk.Common@@ -216,13 +215,13 @@ foreign import ccall unsafe "wrapper.h" cpSpaceRemoveShape :: SpacePtr -> ShapePtr -> IO () -instance Entity Joint where- spaceAdd = spaceAddHelper unJ cpSpaceAddJoint (const Nothing)- spaceRemove = spaceRemoveHelper unJ cpSpaceRemoveJoint+instance Entity (Constraint a) where+ spaceAdd = spaceAddHelper unC cpSpaceAddConstraint (const Nothing)+ spaceRemove = spaceRemoveHelper unC cpSpaceRemoveConstraint foreign import ccall unsafe "wrapper.h"- cpSpaceAddJoint :: SpacePtr -> JointPtr -> IO ()+ cpSpaceAddConstraint :: SpacePtr -> ConstraintPtr -> IO () foreign import ccall unsafe "wrapper.h"- cpSpaceRemoveJoint :: SpacePtr -> JointPtr -> IO ()+ cpSpaceRemoveConstraint :: SpacePtr -> ConstraintPtr -> IO () -- | A 'StaticShape' is a 'Shape' container that, when added@@ -251,7 +250,7 @@ -- | The number of iterations to use when solving constraints. -- (default is 10).-type Iterations = #{type int}+type Iterations = CInt getIterations :: Space -> IO Iterations getIterations (P sp _ _) = withForeignPtr sp #{peek cpSpace, iterations}@@ -260,9 +259,10 @@ withForeignPtr sp $ \sp_ptr -> do #{poke cpSpace, iterations} sp_ptr it --- | The number of elastic iterations to use when solving constraints.--- (default is 0).-type ElasticIterations = #{type int}+-- | The number of elastic iterations to use when solving+-- constraints. (default is 0, meaning old-style elastic code+-- will be used, which probably isn't what you want).+type ElasticIterations = CInt getElasticIterations :: Space -> IO ElasticIterations getElasticIterations (P sp _ _) = withForeignPtr sp #{peek cpSpace, elasticIterations}@@ -283,7 +283,6 @@ -- | The amount of viscous damping applied to the system. -- (default is 1)-type Damping = CpFloat getDamping :: Space -> IO Damping getDamping (P sp _ _) = withForeignPtr sp #{peek cpSpace, damping}@@ -294,7 +293,7 @@ -- | The time stamp of the simulation, increased in 1 -- every time 'step' is called.-type TimeStamp = #{type int}+type TimeStamp = CInt getTimeStamp :: Space -> IO TimeStamp getTimeStamp (P sp _ _) = withForeignPtr sp #{peek cpSpace, stamp}@@ -312,34 +311,34 @@ -- -- Chipmunk's performance is highly sensitive to both -- parameters, which should be hand-tuned to maximize--- performance. It is in general recommended to set--- @dim@ as the average object size and @count@ around--- 10 times the number of objects in the hash. Usually--- bigger numbers are better to @count@, but only to--- point. By default dim is @100.0@ and count is @1000@.+-- performance. It is in general recommended to set @dim@ as+-- the average object size and @count@ around 10 times the+-- number of objects in the hash. Usually bigger numbers are+-- better to @count@, but only to a certain point. By default+-- dim is @100.0@ and count is @1000@. -- -- Note that in the case of the static hash you may try -- larger numbers as the static hash is only rehashed -- when requested by 'rehashStatic', however that will -- use more memory. -resizeStaticHash :: Space -> CpFloat -> #{type int} -> IO ()+resizeStaticHash :: Space -> Distance -> CInt -> IO () resizeStaticHash (P sp _ _) dim count = withForeignPtr sp $ \sp_ptr -> do cpSpaceResizeStaticHash sp_ptr dim count foreign import ccall unsafe "wrapper.h" cpSpaceResizeStaticHash :: SpacePtr -> CpFloat- -> #{type int} -> IO ()+ -> CInt -> IO () -resizeActiveHash :: Space -> CpFloat -> #{type int} -> IO ()+resizeActiveHash :: Space -> Distance -> CInt -> IO () resizeActiveHash (P sp _ _) dim count = withForeignPtr sp $ \sp_ptr -> do cpSpaceResizeActiveHash sp_ptr dim count foreign import ccall unsafe "wrapper.h" cpSpaceResizeActiveHash :: SpacePtr -> CpFloat- -> #{type int} -> IO ()+ -> CInt -> IO () -- | Rehashes the shapes in the static spatial hash. -- You only need to call this if you move one of the@@ -360,32 +359,26 @@ -- for example, to know if a shape was clicked by -- the user. --- | You may query the static hash, the active hash--- or both.-data QueryType = ActiveHash | StaticHash | Both---- | @spaceQuery sp query pos cb@ will call @cb@ for every+-- | @spaceQuery sp pos l g cb@ will call @cb@ for every -- shape that -- -- * Contains point @pos@ (in world's coordinates). ----- * Is in the hash selected by @query@ (see 'QueryType').+-- * Isn't of the same group as @g@. --+-- * Shares at least on layer with @l@.+-- -- The order in which the callback is called is unspecified. -- However it is guaranteed that it will be called once, -- and only once, for each of the shapes described above -- (and never for those who aren't).-spaceQuery :: Space -> QueryType -> Position -> (Shape -> IO ()) -> IO ()-spaceQuery spce@(P sp _ _) query pos callback =+spaceQuery :: Space -> Position -> Layers -> Group -> (Shape -> IO ()) -> IO ()+spaceQuery spce@(P sp _ _) pos layers group callback = withForeignPtr sp $ \sp_ptr -> bracket (makePointQueryFunc cb) freeHaskellFunPtr $ \cb_ptr -> with pos $ \pos_ptr ->- func sp_ptr pos_ptr cb_ptr+ wrSpacePointQuery sp_ptr pos_ptr layers group cb_ptr where- func = case query of- ActiveHash -> wrSpaceActiveShapePointQuery- StaticHash -> wrSpaceStaticShapePointQuery- Both -> wrSpaceBothShapePointQuery cb shape_ptr _ = retriveShape spce shape_ptr >>= callback type PointQueryFunc = ShapePtr -> Ptr () -> IO ()@@ -393,23 +386,17 @@ foreign import ccall "wrapper" makePointQueryFunc :: PointQueryFunc -> IO PointQueryFuncPtr foreign import ccall safe "wrapper.h"- wrSpaceActiveShapePointQuery- :: SpacePtr -> VectorPtr -> PointQueryFuncPtr -> IO ()-foreign import ccall safe "wrapper.h"- wrSpaceStaticShapePointQuery- :: SpacePtr -> VectorPtr -> PointQueryFuncPtr -> IO ()-foreign import ccall safe "wrapper.h"- wrSpaceBothShapePointQuery- :: SpacePtr -> VectorPtr -> PointQueryFuncPtr -> IO ()+ wrSpacePointQuery :: SpacePtr -> VectorPtr -> Layers -> Group+ -> PointQueryFuncPtr -> IO () --- | @spaceQueryList sp query pos@ acts like 'spaceQuery' but+-- | @spaceQueryList sp pos l g@ acts like 'spaceQuery' but -- returns a list of 'Shape's instead of calling a callback. -- This is just a convenience function.-spaceQueryList :: Space -> QueryType -> Position -> IO [Shape]-spaceQueryList spce query pos = do+spaceQueryList :: Space -> Position -> Layers -> Group -> IO [Shape]+spaceQueryList spce pos layers group = do var <- newIORef []- spaceQuery spce query pos $ modifyIORef var . (:)+ spaceQuery spce pos layers group $ modifyIORef var . (:) readIORef var @@ -438,18 +425,18 @@ -- If @False@, then the collision will be ignored. -- -- The callbacks themselves may execute arbitrary operations--- with a simple exception: /callbacks cannot add or remove--- entities from the space/. You can of course create a queue+-- with a simple exception: /callbacks cannot add or remove/+-- /entities from the space/. You can of course create a queue -- of add\/remove actions and then process it after 'step' -- returns. ----- As for the events that trigger collision pair functions,--- the rule is simple. All shapes have a 'CollisionType'.--- When shapes @a@ and @b@ collide, if there was a callback--- associated with @a@'s and @b@'s collision types, then--- it is called. Otherwise the default callback is called.--- By default, the default callback always returns @True@--- (i.e. all collisions are treated).+-- As for the events that trigger collision pair functions, the+-- rule is simple. All shapes have a 'CollisionType'. When+-- shapes @a@ and @b@ collide, if there was a callback+-- associated with @a@'s and @b@'s collision types, then it is+-- called. Otherwise the default callback is called. The+-- default callback always returns @True@ (i.e. all collisions+-- are treated). -- | A 'Callback' function can be of three types:@@ -480,7 +467,7 @@ -- | Internal. Type of callback used by Chipmunk.-type ChipmunkCB = ShapePtr -> ShapePtr -> ContactPtr -> #{type int}+type ChipmunkCB = ShapePtr -> ShapePtr -> ContactPtr -> CInt -> CpFloat -> Ptr () -> IO Int type ChipmunkCBPtr = FunPtr ChipmunkCB @@ -644,7 +631,7 @@ sumImpulses = sumImpulsesInternal wrContactsSumImpulses foreign import ccall unsafe "wrapper.h"- wrContactsSumImpulses :: ContactPtr -> #{type int}+ wrContactsSumImpulses :: ContactPtr -> CInt -> VectorPtr -> IO () -- | Sums the impulses applied to the given contact points.@@ -655,10 +642,10 @@ sumImpulsesInternal wrContactsSumImpulsesWithFriction foreign import ccall unsafe "wrapper.h"- wrContactsSumImpulsesWithFriction :: ContactPtr -> #{type int}+ wrContactsSumImpulsesWithFriction :: ContactPtr -> CInt -> VectorPtr -> IO () -sumImpulsesInternal :: (ContactPtr -> #{type int} -> VectorPtr -> IO ())+sumImpulsesInternal :: (ContactPtr -> CInt -> VectorPtr -> IO ()) -> StorableArray Int Contact -> IO Vector sumImpulsesInternal func sa = do (i1,i2) <- getBounds sa
+ Physics/Hipmunk/Unsafe.hsc view
@@ -0,0 +1,87 @@+-----------------------------------------------------------------------------+-- |+-- Module : Physics/Hipmunk/Unsafe.hsc+-- Copyright : (c) 2008-2009 Felipe A. Lessa+-- License : MIT (see LICENSE)+--+-- Maintainer : felipe.lessa@gmail.com+-- Stability : provisional+-- Portability : portable (needs FFI)+--+-- All functions on this module are /UNSAFE/ in the sense that+-- they may reduce the physical accuracy or numerical stability+-- of the simulation if you use them correctly, or may crash your+-- system if you are not careful enough. Read their+-- documentation carefully and use them only if you really need+-- and know what you are doing.+--+-----------------------------------------------------------------------------++module Physics.Hipmunk.Unsafe+ (-- * Shapes+ unsafeShapeRedefine,+ -- * Constraints+ unsafeRememberC+ )+ where++import Foreign hiding (rotate, new)+import Foreign.C+#include "wrapper.h"++import Physics.Hipmunk.Common+import Physics.Hipmunk.Internal+import Physics.Hipmunk.Shape+import Physics.Hipmunk.Constraint (Unknown)++-- | @unsafeShapeRedefine shape type off@ redefines @shape@ to+-- have new parameters described on @type@ and to be at offset+-- @off@. Be careful, /you should not change the shape type/.+-- For example, it is unsafe to change a circle shape's radius,+-- but it is an error to try to change a circle into a segment+-- or a polygon. Note also that these errors /are not+-- checked/, meaning /they will probably crash Chipmunk/.+unsafeShapeRedefine :: Shape -> ShapeType -> Position -> IO ()+unsafeShapeRedefine (S shape _) (Circle r) off =+ withForeignPtr shape $ \shape_ptr ->+ with off $ \off_ptr -> do+ cpCircleShapeSetRadius shape_ptr r+ wrCircleShapeSetOffset shape_ptr off_ptr++unsafeShapeRedefine (S shape _) (LineSegment p1 p2 r) off =+ withForeignPtr shape $ \shape_ptr ->+ with (p1+off) $ \p1off_ptr ->+ with (p2+off) $ \p2off_ptr -> do+ wrSegmentShapeSetEndpoints shape_ptr p1off_ptr p2off_ptr+ cpSegmentShapeSetRadius shape_ptr r++unsafeShapeRedefine (S shape _) (Polygon verts) off =+ withForeignPtr shape $ \shape_ptr ->+ with off $ \off_ptr ->+ withArrayLen verts $ \verts_len verts_ptr -> do+ let verts_len' = fromIntegral verts_len+ wrPolyShapeSetVerts shape_ptr verts_len' verts_ptr off_ptr++foreign import ccall unsafe "wrapper.h"+ cpCircleShapeSetRadius :: ShapePtr -> CpFloat -> IO ()+foreign import ccall unsafe "wrapper.h"+ wrCircleShapeSetOffset :: ShapePtr -> VectorPtr -> IO ()+foreign import ccall unsafe "wrapper.h"+ wrSegmentShapeSetEndpoints :: ShapePtr -> VectorPtr -> VectorPtr -> IO ()+foreign import ccall unsafe "wrapper.h"+ cpSegmentShapeSetRadius :: ShapePtr -> CpFloat -> IO ()+foreign import ccall unsafe "wrapper.h"+ wrPolyShapeSetVerts :: ShapePtr -> CInt -> VectorPtr -> VectorPtr -> IO ()+++++-- | Unsafe function that changes the constraint type to+-- anything. It is unsafe because you should call 'redefine'+-- only on the same kind of constraint you created, and this+-- function allows you to bypass the type system checks. Note+-- Also that, unlike Chipmunk, we don't check at run-time that+-- 'redefine' is being called on the right type!+unsafeRememberC :: ConstraintType a => Constraint Unknown -> Constraint a+unsafeRememberC (C c b1 b2) = C c b1 b2+{-# INLINE unsafeRememberC #-}
Physics/Hipmunk/wrapper.c view
@@ -14,9 +14,9 @@ void wrBodyApplyImpulse(cpBody *b, cpVect *j, cpVect *r) { cpBodyApplyImpulse(b, *j, *r); }-void wrDampedSpring(cpBody *b1, cpBody *b2, cpVect *a1, cpVect *a2,- cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt) {- cpDampedSpring(b1, b2, *a1, *a2, rlen, k, dmp, dt);+void wrApplyDampedSpring(cpBody *b1, cpBody *b2, cpVect *a1, cpVect *a2,+ cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt) {+ cpApplyDampedSpring(b1, b2, *a1, *a2, rlen, k, dmp, dt); } void wrBodyLocal2World(cpBody *b, cpVect *v) { cpVect ret = cpBodyLocal2World(b, *v);@@ -42,36 +42,67 @@ cpVect *a, cpVect *b, cpFloat r) { cpSegmentShapeInit(seg, body, *a, *b, r); }-int wrShapePointQuery(cpShape *shape, cpVect *p) {- return cpShapePointQuery(shape, *p);+int wrShapePointQuery(cpShape *shape, cpVect *p,+ cpLayers layers, cpGroup group) {+ return cpShapePointQuery(shape, *p, layers, group); } +int cpShapeSegmentQuery(cpShape*, cpVect, cpVect, cpLayers, cpGroup, cpSegmentQueryInfo*);+int wrShapeSegmentQuery(cpShape *shape, cpVect *a, cpVect *b,+ cpLayers layers, cpGroup group,+ cpSegmentQueryInfo *info) {+ return cpShapeSegmentQuery(shape, *a, *b, layers, group, info);+} + // From cpPolyShape.h void wrPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect *offset) { cpPolyShapeInit(poly, body, numVerts, verts, *offset); } -// From cpJoint.h-void wrPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b,- cpVect *anchr1, cpVect *anchr2) {+// From various constraints+void wrPinJointInit(cpVect *anchr1, cpVect *anchr2,+ cpPinJoint *joint, cpBody *a, cpBody *b) { cpPinJointInit(joint, a, b, *anchr1, *anchr2); }-void wrSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b,- cpVect *anchr1, cpVect *anchr2,- cpFloat min, cpFloat max) {+void wrSlideJointInit(cpFloat min, cpFloat max, cpVect *anchr1, cpVect *anchr2,+ cpSlideJoint *joint, cpBody *a, cpBody *b) { cpSlideJointInit(joint, a, b, *anchr1, *anchr2, min, max); }-void wrPivotJointInit(cpPivotJoint *joint, cpBody *a,- cpBody *b, cpVect *pivot) {- cpPivotJointInit(joint, a, b, *pivot);+void wrPivot1JointInit(cpVect *pivot, cpPivotJoint *joint, cpBody *a, cpBody *b) {+ cpPivotJointInit(joint, a, b, cpBodyWorld2Local(a, *pivot),+ cpBodyWorld2Local(b, *pivot)); }-void wrGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b,- cpVect *groove_a, cpVect *groove_b, cpVect *anchr2) {+void wrPivot2JointInit(cpVect *anchr1, cpVect *anchr2,+ cpPivotJoint *joint, cpBody *a, cpBody *b) {+ cpPivotJointInit(joint, a, b, *anchr1, *anchr2);+}+void wrGrooveJointInit(cpVect *groove_a, cpVect *groove_b, cpVect *anchr2,+ cpGrooveJoint *joint, cpBody *a, cpBody *b) { cpGrooveJointInit(joint, a, b, *groove_a, *groove_b, *anchr2); }-+void wrGearJointInit(cpFloat phase, cpFloat ratio,+ cpGearJoint *joint, cpBody *a, cpBody *b) {+ cpGearJointInit(joint, a, b, phase, ratio);+}+void wrDampedSpringInit(cpFloat restLength, cpFloat stiffness, cpFloat damping,+ cpVect *anchr1, cpVect *anchr2,+ cpDampedSpring *joint, cpBody *a, cpBody *b) {+ cpDampedSpringInit(joint, a, b, *anchr1, *anchr2,+ restLength, stiffness, damping);+}+void wrDampedRotarySpringInit(cpFloat restAngle, cpFloat stiffness, cpFloat damping,+ cpDampedRotarySpring *joint, cpBody *a, cpBody *b) {+ cpDampedRotarySpringInit(joint, a, b, restAngle, stiffness, damping);+}+void wrRotaryLimitJointInit(cpFloat min, cpFloat max,+ cpRotaryLimitJoint *joint, cpBody *a, cpBody *b) {+ cpRotaryLimitJointInit(joint, a, b, min, max);+}+void wrSimpleMotorInit(cpFloat rate, cpSimpleMotor *joint, cpBody *a, cpBody *b) {+ cpSimpleMotorInit(joint, a, b, rate);+} // From cpArbiter.h void wrContactsSumImpulses(cpContact *contacts, int numContacts, cpVect *ret) {@@ -83,13 +114,18 @@ } // From cpSpace.h-void wrSpaceActiveShapePointQuery(cpSpace *space, cpVect *point, cpSpacePointQueryFunc func) {- cpSpaceShapePointQuery(space, *point, func, NULL);+void wrSpacePointQuery(cpSpace *space, cpVect *point, cpLayers layers,+ cpGroup group, cpSpacePointQueryFunc func) {+ cpSpacePointQuery(space, *point, layers, group, func, NULL); }-void wrSpaceStaticShapePointQuery(cpSpace *space, cpVect *point, cpSpacePointQueryFunc func) {- cpSpaceStaticShapePointQuery(space, *point, func, NULL);++// From chipmunk_unsafe.h+void wrCircleShapeSetOffset(cpShape *shape, cpVect *offset) {+ cpCircleShapeSetOffset(shape, *offset); }-void wrSpaceBothShapePointQuery(cpSpace *space, cpVect *point, cpSpacePointQueryFunc func) {- cpSpaceShapePointQuery(space, *point, func, NULL);- cpSpaceStaticShapePointQuery(space, *point, func, NULL);+void wrSegmentShapeSetEndpoints(cpShape *shape, cpVect *a, cpVect *b) {+ cpSegmentShapeSetEndpoints(shape, *a, *b);+}+void wrPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect *offset) {+ cpPolyShapeSetVerts(shape, numVerts, verts, *offset); }
Physics/Hipmunk/wrapper.h view
@@ -1,51 +1,52 @@ #ifndef WRAPPER_H #define WRAPPER_H+#include <stdlib.h> #include "chipmunk.h"+#include "chipmunk_unsafe.h" // New functions-int wrConstantCallback(cpShape *a, cpShape *b, cpContact *contacts,- int numContacts, cpFloat normal_coef, void *data);-+int wrConstantCallback(cpShape*, cpShape*, cpContact*, int, cpFloat, void*); // From cpBody.h-void wrBodyUpdateVelocity(cpBody *b, cpVect *g, cpFloat d, cpFloat dt);-void wrBodyApplyImpulse(cpBody *b, cpVect *j, cpVect *r);-void wrDampedSpring(cpBody *b1, cpBody *b2, cpVect *a1, cpVect *a2,- cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);-void wrBodyLocal2World(cpBody *b, cpVect *v);-void wrBodyWorld2Local(cpBody *b, cpVect *v);-void wrBodyApplyForce(cpBody *b, cpVect *f, cpVect *p);+void wrBodyUpdateVelocity(cpBody*, cpVect*, cpFloat, cpFloat);+void wrBodyApplyImpulse(cpBody*, cpVect*, cpVect*);+void wrDampedSpring(cpBody*, cpBody*, cpVect*, cpVect*, cpFloat, cpFloat, cpFloat, cpFloat);+void wrBodyLocal2World(cpBody*, cpVect*);+void wrBodyWorld2Local(cpBody*, cpVect*);+void wrBodyApplyForce(cpBody*, cpVect*, cpVect*); // From cpShape.h-void wrCircleShapeInit(cpCircleShape *circle, cpBody *body,- cpVect *offset, cpFloat radius);-void wrSegmentShapeInit(cpSegmentShape *seg, cpBody *body,- cpVect *a, cpVect *b, cpFloat r);-int wrShapePointQuery(cpShape *shape, cpVect *p);+void wrCircleShapeInit(cpCircleShape*, cpBody*, cpVect*, cpFloat);+void wrSegmentShapeInit(cpSegmentShape*, cpBody*, cpVect*, cpVect*, cpFloat);+int wrShapePointQuery(cpShape*, cpVect*, cpLayers, cpGroup);+int wrShapeSegmentQuery(cpShape*, cpVect*, cpVect*, cpLayers, cpGroup, cpSegmentQueryInfo*); // From cpPolyShape.h-void wrPolyShapeInit(cpPolyShape *poly, cpBody *body,- int numVerts, cpVect *verts, cpVect *offset);+void wrPolyShapeInit(cpPolyShape*, cpBody*, int, cpVect*, cpVect*); -// From cpJoint.h-void wrPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b,- cpVect *anchr1, cpVect *anchr2);-void wrSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b,- cpVect *anchr1, cpVect *anchr2,- cpFloat min, cpFloat max);-void wrPivotJointInit(cpPivotJoint *joint, cpBody *a,- cpBody *b, cpVect *pivot);-void wrGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b,- cpVect *groove_a, cpVect *groove_b, cpVect *anchr2);+// From various constraints+// Note that we change the argument order to allow easy currying on Haskell side.+void wrPinJointInit(cpVect*, cpVect*, cpPinJoint*, cpBody*, cpBody*);+void wrSlideJointInit(cpFloat, cpFloat, cpVect*, cpVect*, cpSlideJoint*, cpBody*, cpBody*);+void wrPivot1JointInit(cpVect*, cpPivotJoint*, cpBody*, cpBody*);+void wrPivot2JointInit(cpVect*, cpVect*, cpPivotJoint*, cpBody*, cpBody*);+void wrGrooveJointInit(cpVect*, cpVect*, cpVect*, cpGrooveJoint*, cpBody*, cpBody*);+void wrGearJointInit(cpFloat, cpFloat, cpGearJoint*, cpBody*, cpBody*);+void wrDampedSpringInit(cpFloat, cpFloat, cpFloat, cpVect*, cpVect*, cpDampedSpring*, cpBody*, cpBody*);+void wrDampedRotarySpringInit(cpFloat, cpFloat, cpFloat, cpDampedRotarySpring*, cpBody*, cpBody*);+void wrRotaryLimitJointInit(cpFloat, cpFloat, cpRotaryLimitJoint*, cpBody*, cpBody*);+void wrSimpleMotorInit(cpFloat, cpSimpleMotor*, cpBody*, cpBody*); // From cpArbiter.h-void wrContactsSumImpulses(cpContact *contacts, int numContacts, cpVect *ret);-void wrContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts,- cpVect *ret);+void wrContactsSumImpulses(cpContact*, int, cpVect*);+void wrContactsSumImpulsesWithFriction(cpContact*, int, cpVect*); // From cpSpace.h-void wrSpaceActiveShapePointQuery(cpSpace *space, cpVect *point, cpSpacePointQueryFunc func);-void wrSpaceStaticShapePointQuery(cpSpace *space, cpVect *point, cpSpacePointQueryFunc func);-void wrSpaceBothShapePointQuery(cpSpace *space, cpVect *point, cpSpacePointQueryFunc func);+void wrSpacePointQuery(cpSpace*, cpVect*, cpLayers, cpGroup, cpSpacePointQueryFunc);++// From chipmunk_unsafe.h+void wrCircleShapeSetOffset(cpShape*, cpVect*);+void wrSegmentShapeSetEndpoints(cpShape*, cpVect*, cpVect*);+void wrPolyShapeSetVerts(cpShape*, int, cpVect*, cpVect*); #endif
+ chipmunk-5.0/chipmunk.c view
@@ -0,0 +1,78 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>++#include "chipmunk.h"++#ifdef __cplusplus+extern "C" {+#endif+ void cpInitCollisionFuncs(void);+#ifdef __cplusplus+}+#endif+++void+cpInitChipmunk(void)+{+ cpInitCollisionFuncs();+}++cpFloat+cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)+{+ return (1.0f/2.0f)*m*(r1*r1 + r2*r2) + m*cpvdot(offset, offset);+}++cpFloat+cpMomentForSegment(cpFloat m, cpVect a, cpVect b)+{+ cpFloat length = cpvlength(cpvsub(b, a));+ cpVect offset = cpvmult(cpvadd(a, b), 1.0f/2.0f);+ + return m*length*length/12.0f + m*cpvdot(offset, offset);+}++cpFloat+cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset)+{+ cpVect *tVerts = (cpVect *)calloc(numVerts, sizeof(cpVect));+ for(int i=0; i<numVerts; i++)+ tVerts[i] = cpvadd(verts[i], offset);+ + cpFloat sum1 = 0.0f;+ cpFloat sum2 = 0.0f;+ for(int i=0; i<numVerts; i++){+ cpVect v1 = tVerts[i];+ cpVect v2 = tVerts[(i+1)%numVerts];+ + cpFloat a = cpvcross(v2, v1);+ cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2);+ + sum1 += a*b;+ sum2 += a;+ }+ + free(tVerts);+ return (m*sum1)/(6.0f*sum2);+}
+ chipmunk-5.0/chipmunk.h view
@@ -0,0 +1,104 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_HEADER+#define CHIPMUNK_HEADER++#ifdef __cplusplus+extern "C" {+#endif++#include "chipmunk_types.h"+ +static inline cpFloat+cpfmax(cpFloat a, cpFloat b)+{+ return (a > b) ? a : b;+}++static inline cpFloat+cpfmin(cpFloat a, cpFloat b)+{+ return (a < b) ? a : b;+}++static inline cpFloat+cpfabs(cpFloat n)+{+ return (n < 0) ? -n : n;+}++static inline cpFloat+cpfclamp(cpFloat f, cpFloat min, cpFloat max){+ return cpfmin(cpfmax(f, min), max);+}++#ifndef INFINITY+ #ifdef _MSC_VER+ union MSVC_EVIL_FLOAT_HACK+ {+ unsigned __int8 Bytes[4];+ float Value;+ };+ static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}};+ #define INFINITY (INFINITY_HACK.Value)+ #else+ #define INFINITY (1e1000)+ #endif+#endif++#include "cpVect.h"+#include "cpBB.h"+#include "cpBody.h"+#include "cpArray.h"+#include "cpHashSet.h"+#include "cpSpaceHash.h"++#include "cpShape.h"+#include "cpPolyShape.h"++#include "cpArbiter.h"+#include "cpCollision.h"+ +#include "constraints/cpConstraint.h"++#include "cpSpace.h"++#define CP_HASH_COEF (3344921057ul)+#define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF)++void cpInitChipmunk(void);++// Calculate the moment of inertia for a circle, r1 and r2 are the inner and outer diameters.+// (A solid circle has an inner diameter of 0)+cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);++// Calculate the moment of inertia for a line segment. (beveling radius not supported)+cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b);++// Calculate the moment of inertia for a solid polygon shape.+cpFloat cpMomentForPoly(cpFloat m, int numVerts, cpVect *verts, cpVect offset);++#ifdef __cplusplus+}+#endif++#endif
+ chipmunk-5.0/chipmunk_types.h view
@@ -0,0 +1,26 @@+typedef double cpFloat;+#define cpfsqrt sqrt+#define cpfsin sin+#define cpfcos cos+#define cpfatan2 atan2+#define cpfmod fmod+#define cpfexp exp+#define cpfpow pow+#define cpffloor floor+#define cpfceil ceil+ +//typedef float cpFloat;+//#define cpfsqrt sqrtf+//#define cpfsin sinf+//#define cpfcos cosf+//#define cpfatan2 atan2f+//#define cpfmod fmodf+//#define cpfexp expf+//#define cpfpow powf+//#define cpffloor floorf+//#define cpfceil ceilf++typedef size_t cpHashValue;+typedef unsigned int cpCollisionType;+typedef unsigned int cpLayers;+typedef unsigned int cpGroup;
+ chipmunk-5.0/chipmunk_unsafe.h view
@@ -0,0 +1,54 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++++/* This header defines a number of "unsafe" operations on Chipmunk objects.+ * In this case "unsafe" is referring to operations which may reduce the+ * physical accuracy or numerical stability of the simulation, but will not+ * cause crashes.+ *+ * The prime example is mutating collision shapes. Chipmunk does not support+ * this directly. Mutating shapes using this API will caused objects in contact+ * to be pushed apart using Chipmunk's overlap solver, but not using real+ * persistent velocities. Probably not what you meant, but perhaps close enough.+ */++#ifndef CHIPMUNK_UNSAFE_HEADER+#define CHIPMUNK_UNSAFE_HEADER++#ifdef __cplusplus+extern "C" {+#endif++void cpCircleShapeSetRadius(cpShape *shape, cpFloat radius);+void cpCircleShapeSetOffset(cpShape *shape, cpVect offset);++void cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b);+void cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius);++void cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset);++#ifdef __cplusplus+}+#endif++#endif
+ chipmunk-5.0/constraints/cpConstraint.c view
@@ -0,0 +1,60 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>+#include <assert.h>++#include "../chipmunk.h"+#include "util.h"++// TODO: Comment me!++cpFloat cp_constraint_bias_coef = 0.1f;++void cpConstraintDestroy(cpConstraint *constraint){}++void+cpConstraintFree(cpConstraint *constraint)+{+ if(constraint) cpConstraintDestroy(constraint);+ free(constraint);+}++void+cpConstraintCheckCast(cpConstraint *constraint, const cpConstraintClass *klass)+{+ assert(constraint->klass == klass); // Bad cpConstraint type in cast+}+++// *** defined in util.h++void+cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b)+{+ constraint->klass = klass;+ constraint->a = a;+ constraint->b = b;+ + constraint->maxForce = INFINITY;+ constraint->biasCoef = cp_constraint_bias_coef;+ constraint->maxBias = INFINITY;+}
+ chipmunk-5.0/constraints/cpConstraint.h view
@@ -0,0 +1,90 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++// TODO: Comment me!+ +extern cpFloat cp_constraint_bias_coef;++struct cpConstraintClass;+struct cpConstraint;++typedef void (*cpConstraintPreStepFunction)(struct cpConstraint *constraint, cpFloat dt, cpFloat dt_inv);+typedef void (*cpConstraintApplyImpulseFunction)(struct cpConstraint *constraint);+typedef cpFloat (*cpConstraintGetImpulseFunction)(struct cpConstraint *constraint);++typedef struct cpConstraintClass {+ cpConstraintPreStepFunction preStep;+ cpConstraintApplyImpulseFunction applyImpulse;+ cpConstraintGetImpulseFunction getImpulse;+} cpConstraintClass;++++typedef struct cpConstraint {+ const cpConstraintClass *klass;+ + cpBody *a, *b;+ cpFloat maxForce;+ cpFloat biasCoef;+ cpFloat maxBias;+ + void *data;+} cpConstraint;++void cpConstraintDestroy(cpConstraint *constraint);+void cpConstraintFree(cpConstraint *constraint);+++void cpConstraintCheckCast(cpConstraint *constraint, const cpConstraintClass *klass);++#define CP_DefineConstraintProperty(struct, type, member, name) \+static inline type \+struct##Get##name(cpConstraint *constraint){ \+ cpConstraintCheckCast(constraint, struct##GetClass()); \+ return ((struct *)constraint)->member; \+} \+static inline void \+struct##Set##name(cpConstraint *constraint, type value){ \+ cpConstraintCheckCast(constraint, struct##GetClass()); \+ ((struct *)constraint)->member = value; \+} \+/* These are for compatibility with the interim trunk version, for some reason I thought I needed the underscores to make the macro work */ \+static inline type \+struct##_get_##member(cpConstraint *constraint){ \+ cpConstraintCheckCast(constraint, struct##GetClass()); \+ return ((struct *)constraint)->member; \+} \+static inline void \+struct##_set_##member(cpConstraint *constraint, type value){ \+ cpConstraintCheckCast(constraint, struct##GetClass()); \+ ((struct *)constraint)->member = value; \+}++// Built in Joint types+#include "cpPinJoint.h"+#include "cpSlideJoint.h"+#include "cpPivotJoint.h"+#include "cpGrooveJoint.h"+#include "cpDampedSpring.h"+#include "cpDampedRotarySpring.h"+#include "cpRotaryLimitJoint.h"+#include "cpGearJoint.h"+#include "cpSimpleMotor.h"
+ chipmunk-5.0/constraints/cpDampedRotarySpring.c view
@@ -0,0 +1,106 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>+#include <math.h>++#include "../chipmunk.h"+#include "util.h"++static cpFloat+defaultSpringTorque(cpDampedRotarySpring *spring, cpFloat relativeAngle){+ return (relativeAngle - spring->restAngle)*spring->stiffness;+}++static void+preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = spring->constraint.a;+ cpBody *b = spring->constraint.b;+ + spring->iSum = 1.0f/(a->i_inv + b->i_inv);++ spring->dt = dt;+ spring->target_wrn = 0.0f;++ // apply spring torque+ cpFloat j_spring = spring->springTorqueFunc((cpConstraint *)spring, a->a - b->a)*dt;+ a->w -= j_spring*a->i_inv;+ b->w += j_spring*b->i_inv;+}++static void+applyImpulse(cpDampedRotarySpring *spring)+{+ cpBody *a = spring->constraint.a;+ cpBody *b = spring->constraint.b;+ + // compute relative velocity+ cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;+ + // compute velocity loss from drag+ // not 100% certain this is derived correctly, though it makes sense+ cpFloat w_damp = wrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->iSum));+ spring->target_wrn = wrn - w_damp;+ + //apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));+ cpFloat j_damp = w_damp*spring->iSum;+ a->w -= j_damp*a->i_inv;+ b->w += j_damp*b->i_inv;+}++static cpFloat+getImpulse(cpConstraint *constraint)+{+ return 0.0f;+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpDampedRotarySpring)++cpDampedRotarySpring *+cpDampedRotarySpringAlloc(void)+{+ return (cpDampedRotarySpring *)malloc(sizeof(cpDampedRotarySpring));+}++cpDampedRotarySpring *+cpDampedRotarySpringInit(cpDampedRotarySpring *spring, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)+{+ cpConstraintInit((cpConstraint *)spring, &klass, a, b);+ + spring->restAngle = restAngle;+ spring->stiffness = stiffness;+ spring->damping = damping;+ spring->springTorqueFunc = (cpDampedRotarySpringTorqueFunc)defaultSpringTorque;+ + return spring;+}++cpConstraint *+cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)+{+ return (cpConstraint *)cpDampedRotarySpringInit(cpDampedRotarySpringAlloc(), a, b, restAngle, stiffness, damping);+}
+ chipmunk-5.0/constraints/cpDampedRotarySpring.h view
@@ -0,0 +1,45 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++typedef cpFloat (*cpDampedRotarySpringTorqueFunc)(struct cpConstraint *spring, cpFloat relativeAngle);++const cpConstraintClass *cpDampedRotarySpringGetClass();++typedef struct cpDampedRotarySpring {+ cpConstraint constraint;+ cpFloat restAngle;+ cpFloat stiffness;+ cpFloat damping;+ cpDampedRotarySpringTorqueFunc springTorqueFunc;+ + cpFloat dt;+ cpFloat target_wrn;+ + cpFloat iSum;+} cpDampedRotarySpring;++cpDampedRotarySpring *cpDampedRotarySpringAlloc(void);+cpDampedRotarySpring *cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);+cpConstraint *cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);++CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle);+CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness);+CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping);
+ chipmunk-5.0/constraints/cpDampedSpring.c view
@@ -0,0 +1,117 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>+#include <math.h>++#include "../chipmunk.h"+#include "util.h"++static cpFloat+defaultSpringForce(cpDampedSpring *spring, cpFloat dist){+ return (spring->restLength - dist)*spring->stiffness;+}++static void+preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = spring->constraint.a;+ cpBody *b = spring->constraint.b;+ + spring->r1 = cpvrotate(spring->anchr1, a->rot);+ spring->r2 = cpvrotate(spring->anchr2, b->rot);+ + cpVect delta = cpvsub(cpvadd(b->p, spring->r2), cpvadd(a->p, spring->r1));+ cpFloat dist = cpvlength(delta);+ spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));+ + // calculate mass normal+ spring->nMass = 1.0f/k_scalar(a, b, spring->r1, spring->r2, spring->n);++ spring->dt = dt;+ spring->target_vrn = 0.0f;++ // apply spring force+ cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist);+ apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, f_spring*dt));+}++static void+applyImpulse(cpDampedSpring *spring)+{+ cpBody *a = spring->constraint.a;+ cpBody *b = spring->constraint.b;+ + cpVect n = spring->n;+ cpVect r1 = spring->r1;+ cpVect r2 = spring->r2;++ // compute relative velocity+ cpFloat vrn = normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;+ + // compute velocity loss from drag+ // not 100% certain this is derived correctly, though it makes sense+ cpFloat v_damp = -vrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->nMass));+ spring->target_vrn = vrn + v_damp;+ + apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));+}++static cpFloat+getImpulse(cpConstraint *constraint)+{+ return 0.0f;+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpDampedSpring)++cpDampedSpring *+cpDampedSpringAlloc(void)+{+ return (cpDampedSpring *)malloc(sizeof(cpDampedSpring));+}++cpDampedSpring *+cpDampedSpringInit(cpDampedSpring *spring, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping)+{+ cpConstraintInit((cpConstraint *)spring, cpDampedSpringGetClass(), a, b);+ + spring->anchr1 = anchr1;+ spring->anchr2 = anchr2;+ + spring->restLength = restLength;+ spring->stiffness = stiffness;+ spring->damping = damping;+ spring->springForceFunc = (cpDampedSpringForceFunc)defaultSpringForce;+ + return spring;+}++cpConstraint *+cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping)+{+ return (cpConstraint *)cpDampedSpringInit(cpDampedSpringAlloc(), a, b, anchr1, anchr2, restLength, stiffness, damping);+}
+ chipmunk-5.0/constraints/cpDampedSpring.h view
@@ -0,0 +1,53 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++struct cpDampedSpring;++typedef cpFloat (*cpDampedSpringForceFunc)(struct cpConstraint *spring, cpFloat dist);++const cpConstraintClass *cpDampedSpringGetClass();++typedef struct cpDampedSpring {+ cpConstraint constraint;+ cpVect anchr1, anchr2;+ cpFloat restLength;+ cpFloat stiffness;+ cpFloat damping;+ cpDampedSpringForceFunc springForceFunc;+ + cpFloat dt;+ cpFloat target_vrn;+ + cpVect r1, r2;+ cpFloat nMass;+ cpVect n;+} cpDampedSpring;++cpDampedSpring *cpDampedSpringAlloc(void);+cpDampedSpring *cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);+cpConstraint *cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);++CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1);+CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr2, Anchr2);+CP_DefineConstraintProperty(cpDampedSpring, cpFloat, restLength, RestLength);+CP_DefineConstraintProperty(cpDampedSpring, cpFloat, stiffness, Stiffness);+CP_DefineConstraintProperty(cpDampedSpring, cpFloat, damping, Damping);+CP_DefineConstraintProperty(cpDampedSpring, cpDampedSpringForceFunc, springForceFunc, SpringForceFunc);
+ chipmunk-5.0/constraints/cpGearJoint.c view
@@ -0,0 +1,104 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpGearJoint *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + // calculate moment of inertia coefficient.+ joint->iSum = 1.0f/(a->i_inv*cpfabs(joint->ratio) + b->i_inv);+ + // calculate bias velocity+ cpFloat maxBias = joint->constraint.maxBias;+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(b->a*joint->ratio - a->a - joint->phase), -maxBias, maxBias);+ + // compute max impulse+ joint->jMax = J_MAX(joint, dt);++ // apply joint torque+ a->w -= joint->jAcc*a->i_inv;+ b->w += joint->jAcc*b->i_inv*joint->ratio;+}++static void+applyImpulse(cpGearJoint *joint)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + // compute relative rotational velocity+ cpFloat wr = b->w*joint->ratio - a->w;+ + // compute normal impulse + cpFloat j = (joint->bias - wr)*joint->iSum;+ cpFloat jOld = joint->jAcc;+ joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);+ j = joint->jAcc - jOld;+ + // apply impulse+ a->w -= j*a->i_inv;+ b->w += j*b->i_inv*joint->ratio;+}++static cpFloat+getImpulse(cpGearJoint *joint)+{+ return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpGearJoint)++cpGearJoint *+cpGearJointAlloc(void)+{+ return (cpGearJoint *)malloc(sizeof(cpGearJoint));+}++cpGearJoint *+cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ + joint->phase = phase;+ joint->ratio = ratio;+ + joint->jAcc = 0.0f;+ + return joint;+}++cpConstraint *+cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)+{+ return (cpConstraint *)cpGearJointInit(cpGearJointAlloc(), a, b, phase, ratio);+}
+ chipmunk-5.0/constraints/cpGearJoint.h view
@@ -0,0 +1,39 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++const cpConstraintClass *cpGearJointGetClass();++typedef struct cpGearJoint {+ cpConstraint constraint;+ cpFloat phase, ratio;+ + cpFloat iSum;+ + cpFloat bias;+ cpFloat jAcc, jMax;+} cpGearJoint;++cpGearJoint *cpGearJointAlloc(void);+cpGearJoint *cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);+cpConstraint *cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);++CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase);+CP_DefineConstraintProperty(cpGearJoint, cpFloat, ratio, Ratio);
+ chipmunk-5.0/constraints/cpGrooveJoint.c view
@@ -0,0 +1,138 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpGrooveJoint *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + // calculate endpoints in worldspace+ cpVect ta = cpBodyLocal2World(a, joint->grv_a);+ cpVect tb = cpBodyLocal2World(a, joint->grv_b);++ // calculate axis+ cpVect n = cpvrotate(joint->grv_n, a->rot);+ cpFloat d = cpvdot(ta, n);+ + joint->grv_tn = n;+ joint->r2 = cpvrotate(joint->anchr2, b->rot);+ + // calculate tangential distance along the axis of r2+ cpFloat td = cpvcross(cpvadd(b->p, joint->r2), n);+ // calculate clamping factor and r2+ if(td <= cpvcross(ta, n)){+ joint->clamp = 1.0f;+ joint->r1 = cpvsub(ta, a->p);+ } else if(td >= cpvcross(tb, n)){+ joint->clamp = -1.0f;+ joint->r1 = cpvsub(tb, a->p);+ } else {+ joint->clamp = 0.0f;+ joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);+ }+ + // Calculate mass tensor+ k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2); + + // compute max impulse+ joint->jMaxLen = J_MAX(joint, dt);+ + // calculate bias velocity+ cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));+ joint->bias = cpvclamp(cpvmult(delta, -joint->constraint.biasCoef*dt_inv), joint->constraint.maxBias);+ + // apply accumulated impulse+ apply_impulses(a, b, joint->r1, joint->r2, joint->jAcc);+}++static inline cpVect+grooveConstrain(cpGrooveJoint *joint, cpVect j){+ cpVect n = joint->grv_tn;+ cpVect jClamp = (joint->clamp*cpvcross(j, n) > 0.0f) ? j : cpvproject(j, n);+ return cpvclamp(jClamp, joint->jMaxLen);+}++static void+applyImpulse(cpGrooveJoint *joint)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + cpVect r1 = joint->r1;+ cpVect r2 = joint->r2;+ + // compute impulse+ cpVect vr = relative_velocity(a, b, r1, r2);++ cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);+ cpVect jOld = joint->jAcc;+ joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j));+ j = cpvsub(joint->jAcc, jOld);+ + // apply impulse+ apply_impulses(a, b, joint->r1, joint->r2, j);+}++static cpFloat+getImpulse(cpGrooveJoint *joint)+{+ return cpvlength(joint->jAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpGrooveJoint)++cpGrooveJoint *+cpGrooveJointAlloc(void)+{+ return (cpGrooveJoint *)malloc(sizeof(cpGrooveJoint));+}++cpGrooveJoint *+cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ + joint->grv_a = groove_a;+ joint->grv_b = groove_b;+ joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));+ joint->anchr2 = anchr2;+ + joint->jAcc = cpvzero;+ + return joint;+}++cpConstraint *+cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)+{+ return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);+}
+ chipmunk-5.0/constraints/cpGrooveJoint.h view
@@ -0,0 +1,44 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++const cpConstraintClass *cpGrooveJointGetClass();++typedef struct cpGrooveJoint {+ cpConstraint constraint;+ cpVect grv_n, grv_a, grv_b;+ cpVect anchr2;+ + cpVect grv_tn;+ cpFloat clamp;+ cpVect r1, r2;+ cpVect k1, k2;+ + cpVect jAcc;+ cpFloat jMaxLen;+ cpVect bias;+} cpGrooveJoint;++cpGrooveJoint *cpGrooveJointAlloc(void);+cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);+cpConstraint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);++// TODO setters for the groove.+CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2);
+ chipmunk-5.0/constraints/cpPinJoint.c view
@@ -0,0 +1,117 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>+//#include <math.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpPinJoint *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + joint->r1 = cpvrotate(joint->anchr1, a->rot);+ joint->r2 = cpvrotate(joint->anchr2, b->rot);+ + cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));+ cpFloat dist = cpvlength(delta);+ joint->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));+ + // calculate mass normal+ joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);+ + // calculate bias velocity+ cpFloat maxBias = joint->constraint.maxBias;+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(dist - joint->dist), -maxBias, maxBias);+ + // compute max impulse+ joint->jnMax = J_MAX(joint, dt);+ + // apply accumulated impulse+ cpVect j = cpvmult(joint->n, joint->jnAcc);+ apply_impulses(a, b, joint->r1, joint->r2, j);+}++static void+applyImpulse(cpPinJoint *joint)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ cpVect n = joint->n;++ // compute relative velocity+ cpFloat vrn = normal_relative_velocity(a, b, joint->r1, joint->r2, n);+ + // compute normal impulse+ cpFloat jn = (joint->bias - vrn)*joint->nMass;+ cpFloat jnOld = joint->jnAcc;+ joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, joint->jnMax);+ jn = joint->jnAcc - jnOld;+ + // apply impulse+ apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));+}++static cpFloat+getImpulse(cpPinJoint *joint)+{+ return cpfabs(joint->jnAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpPinJoint);+++cpPinJoint *+cpPinJointAlloc(void)+{+ return (cpPinJoint *)malloc(sizeof(cpPinJoint));+}++cpPinJoint *+cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ + joint->anchr1 = anchr1;+ joint->anchr2 = anchr2;+ + cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot));+ cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot));+ joint->dist = cpvlength(cpvsub(p2, p1));++ joint->jnAcc = 0.0;+ + return joint;+}++cpConstraint *+cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)+{+ return (cpConstraint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2);+}
+ chipmunk-5.0/constraints/cpPinJoint.h view
@@ -0,0 +1,43 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +const cpConstraintClass *cpPinJointGetClass();++typedef struct cpPinJoint {+ cpConstraint constraint;+ cpVect anchr1, anchr2;+ cpFloat dist;+ + cpVect r1, r2;+ cpVect n;+ cpFloat nMass;+ + cpFloat jnAcc, jnMax;+ cpFloat bias;+} cpPinJoint;++cpPinJoint *cpPinJointAlloc(void);+cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);+cpConstraint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);++CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1);+CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr2, Anchr2);+CP_DefineConstraintProperty(cpPinJoint, cpFloat, dist, Dist);
+ chipmunk-5.0/constraints/cpPivotJoint.c view
@@ -0,0 +1,116 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + joint->r1 = cpvrotate(joint->anchr1, a->rot);+ joint->r2 = cpvrotate(joint->anchr2, b->rot);+ + // Calculate mass tensor+ k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);+ + // compute max impulse+ joint->jMaxLen = J_MAX(joint, dt);+ + // calculate bias velocity+ cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));+ joint->bias = cpvclamp(cpvmult(delta, -joint->constraint.biasCoef*dt_inv), joint->constraint.maxBias);+ + // apply accumulated impulse+ apply_impulses(a, b, joint->r1, joint->r2, joint->jAcc);+}++static void+applyImpulse(cpPivotJoint *joint)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + cpVect r1 = joint->r1;+ cpVect r2 = joint->r2;+ + // compute relative velocity+ cpVect vr = relative_velocity(a, b, r1, r2);+ + // compute normal impulse+ cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);+ cpVect jOld = joint->jAcc;+ joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->jMaxLen);+ j = cpvsub(joint->jAcc, jOld);+ + // apply impulse+ apply_impulses(a, b, joint->r1, joint->r2, j);+}++static cpFloat+getImpulse(cpConstraint *joint)+{+ return cpvlength(((cpPivotJoint *)joint)->jAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpPivotJoint)++cpPivotJoint *+cpPivotJointAlloc(void)+{+ return (cpPivotJoint *)malloc(sizeof(cpPivotJoint));+}++cpPivotJoint *+cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ +// joint->anchr1 = cpvunrotate(cpvsub(pivot, a->p), a->rot);+// joint->anchr2 = cpvunrotate(cpvsub(pivot, b->p), b->rot);+ joint->anchr1 = anchr1;+ joint->anchr2 = anchr2;+ + joint->jAcc = cpvzero;+ + return joint;+}++cpConstraint *+cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)+{+ return (cpConstraint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, anchr1, anchr2);+}++cpConstraint *+cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)+{+ return cpPivotJointNew2(a, b, cpBodyWorld2Local(a, pivot), cpBodyWorld2Local(b, pivot));+}
+ chipmunk-5.0/constraints/cpPivotJoint.h view
@@ -0,0 +1,42 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++const cpConstraintClass *cpPivotJointGetClass();++typedef struct cpPivotJoint {+ cpConstraint constraint;+ cpVect anchr1, anchr2;+ + cpVect r1, r2;+ cpVect k1, k2;+ + cpVect jAcc;+ cpFloat jMaxLen;+ cpVect bias;+} cpPivotJoint;++cpPivotJoint *cpPivotJointAlloc(void);+cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);+cpConstraint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);+cpConstraint *cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);++CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1);+CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2);
+ chipmunk-5.0/constraints/cpRotaryLimitJoint.c view
@@ -0,0 +1,122 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + cpFloat dist = b->a - a->a;+ cpFloat pdist = 0.0;+ if(dist > joint->max) {+ pdist = joint->max - dist;+ } else if(dist < joint->min) {+ pdist = joint->min - dist;+ }+ + // calculate moment of inertia coefficient.+ joint->iSum = 1.0f/(a->i_inv + b->i_inv);+ + // calculate bias velocity+ cpFloat maxBias = joint->constraint.maxBias;+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);+ + // compute max impulse+ joint->jMax = J_MAX(joint, dt);++ // If the bias is 0, the joint is not at a limit. Reset the impulse.+ if(!joint->bias)+ joint->jAcc = 0.0f;++ // apply joint torque+ a->w -= joint->jAcc*a->i_inv;+ b->w += joint->jAcc*b->i_inv;+}++static void+applyImpulse(cpRotaryLimitJoint *joint)+{+ if(!joint->bias) return; // early exit++ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + // compute relative rotational velocity+ cpFloat wr = b->w - a->w;+ + // compute normal impulse + cpFloat j = -(joint->bias + wr)*joint->iSum;+ cpFloat jOld = joint->jAcc;+ if(joint->bias < 0.0f){+ joint->jAcc = cpfclamp(jOld + j, 0.0f, joint->jMax);+ } else {+ joint->jAcc = cpfclamp(jOld + j, -joint->jMax, 0.0f);+ }+ j = joint->jAcc - jOld;+ + // apply impulse+ a->w -= j*a->i_inv;+ b->w += j*b->i_inv;+}++static cpFloat+getImpulse(cpRotaryLimitJoint *joint)+{+ return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpRotaryLimitJoint)++cpRotaryLimitJoint *+cpRotaryLimitJointAlloc(void)+{+ return (cpRotaryLimitJoint *)malloc(sizeof(cpRotaryLimitJoint));+}++cpRotaryLimitJoint *+cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ + joint->min = min;+ joint->max = max;+ + joint->jAcc = 0.0f;+ + return joint;+}++cpConstraint *+cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max)+{+ return (cpConstraint *)cpRotaryLimitJointInit(cpRotaryLimitJointAlloc(), a, b, min, max);+}
+ chipmunk-5.0/constraints/cpRotaryLimitJoint.h view
@@ -0,0 +1,39 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++const cpConstraintClass *cpRotaryLimitJointGetClass();++typedef struct cpRotaryLimitJoint {+ cpConstraint constraint;+ cpFloat min, max;+ + cpFloat iSum;+ + cpFloat bias;+ cpFloat jAcc, jMax;+} cpRotaryLimitJoint;++cpRotaryLimitJoint *cpRotaryLimitJointAlloc(void);+cpRotaryLimitJoint *cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max);+cpConstraint *cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max);++CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min);+CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max);
+ chipmunk-5.0/constraints/cpSimpleMotor.c view
@@ -0,0 +1,99 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpSimpleMotor *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + // calculate moment of inertia coefficient.+ joint->iSum = 1.0f/(a->i_inv + b->i_inv);+ + // compute max impulse+ joint->jMax = J_MAX(joint, dt);++ // apply joint torque+ a->w -= joint->jAcc*a->i_inv;+ b->w += joint->jAcc*b->i_inv;+}++static void+applyImpulse(cpSimpleMotor *joint)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + // compute relative rotational velocity+ cpFloat wr = b->w - a->w + joint->rate;+ + // compute normal impulse + cpFloat j = -wr*joint->iSum;+ cpFloat jOld = joint->jAcc;+ joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);+ j = joint->jAcc - jOld;+ + // apply impulse+ a->w -= j*a->i_inv;+ b->w += j*b->i_inv;+}++static cpFloat+getImpulse(cpSimpleMotor *joint)+{+ return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpSimpleMotor)++cpSimpleMotor *+cpSimpleMotorAlloc(void)+{+ return (cpSimpleMotor *)malloc(sizeof(cpSimpleMotor));+}++cpSimpleMotor *+cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ + joint->rate = rate;+ + joint->jAcc = 0.0f;+ + return joint;+}++cpConstraint *+cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate)+{+ return (cpConstraint *)cpSimpleMotorInit(cpSimpleMotorAlloc(), a, b, rate);+}
+ chipmunk-5.0/constraints/cpSimpleMotor.h view
@@ -0,0 +1,37 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++const cpConstraintClass *cpSimpleMotorGetClass();++typedef struct cpSimpleMotor {+ cpConstraint constraint;+ cpFloat rate;+ + cpFloat iSum;+ + cpFloat jAcc, jMax;+} cpSimpleMotor;++cpSimpleMotor *cpSimpleMotorAlloc(void);+cpSimpleMotor *cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);+cpConstraint *cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);++CP_DefineConstraintProperty(cpSimpleMotor, cpFloat, rate, Rate);
+ chipmunk-5.0/constraints/cpSlideJoint.c view
@@ -0,0 +1,131 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <stdlib.h>++#include "../chipmunk.h"+#include "util.h"++static void+preStep(cpSlideJoint *joint, cpFloat dt, cpFloat dt_inv)+{+ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + joint->r1 = cpvrotate(joint->anchr1, a->rot);+ joint->r2 = cpvrotate(joint->anchr2, b->rot);+ + cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));+ cpFloat dist = cpvlength(delta);+ cpFloat pdist = 0.0;+ if(dist > joint->max) {+ pdist = dist - joint->max;+ } else if(dist < joint->min) {+ pdist = joint->min - dist;+ dist = -dist;+ }+ joint->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));+ + // calculate mass normal+ joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);+ + // calculate bias velocity+ cpFloat maxBias = joint->constraint.maxBias;+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);+ + // compute max impulse+ joint->jnMax = J_MAX(joint, dt);++ // apply accumulated impulse+ if(!joint->bias) //{+ // if bias is 0, then the joint is not at a limit.+ joint->jnAcc = 0.0f;+// } else {+ cpVect j = cpvmult(joint->n, joint->jnAcc);+ apply_impulses(a, b, joint->r1, joint->r2, j);+// }+}++static void+applyImpulse(cpSlideJoint *joint)+{+ if(!joint->bias) return; // early exit++ cpBody *a = joint->constraint.a;+ cpBody *b = joint->constraint.b;+ + cpVect n = joint->n;+ cpVect r1 = joint->r1;+ cpVect r2 = joint->r2;+ + // compute relative velocity+ cpVect vr = relative_velocity(a, b, r1, r2);+ cpFloat vrn = cpvdot(vr, n);+ + // compute normal impulse+ cpFloat jn = (joint->bias - vrn)*joint->nMass;+ cpFloat jnOld = joint->jnAcc;+ joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, 0.0f);+ jn = joint->jnAcc - jnOld;+ + // apply impulse+ apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));+}++static cpFloat+getImpulse(cpConstraint *joint)+{+ return cpfabs(((cpSlideJoint *)joint)->jnAcc);+}++static const cpConstraintClass klass = {+ (cpConstraintPreStepFunction)preStep,+ (cpConstraintApplyImpulseFunction)applyImpulse,+ (cpConstraintGetImpulseFunction)getImpulse,+};+CP_DefineClassGetter(cpSlideJoint)++cpSlideJoint *+cpSlideJointAlloc(void)+{+ return (cpSlideJoint *)malloc(sizeof(cpSlideJoint));+}++cpSlideJoint *+cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)+{+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);+ + joint->anchr1 = anchr1;+ joint->anchr2 = anchr2;+ joint->min = min;+ joint->max = max;+ + joint->jnAcc = 0.0;+ + return joint;+}++cpConstraint *+cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)+{+ return (cpConstraint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max);+}
+ chipmunk-5.0/constraints/cpSlideJoint.h view
@@ -0,0 +1,44 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++const cpConstraintClass *cpSlideJointGetClass();++typedef struct cpSlideJoint {+ cpConstraint constraint;+ cpVect anchr1, anchr2;+ cpFloat min, max;+ + cpVect r1, r2;+ cpVect n;+ cpFloat nMass;+ + cpFloat jnAcc, jnMax;+ cpFloat bias;+} cpSlideJoint;++cpSlideJoint *cpSlideJointAlloc(void);+cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);+cpConstraint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);++CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1);+CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2);+CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min);+CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max);
+ chipmunk-5.0/constraints/util.h view
@@ -0,0 +1,110 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#define CP_DefineClassGetter(t) const cpConstraintClass * t##GetClass(){return (cpConstraintClass *)&klass;}++void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b);++#define J_MAX(constraint, dt) (((cpConstraint *)constraint)->maxForce*(dt))++static inline cpVect+relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){+ cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));+ cpVect v2_sum = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));+ + return cpvsub(v2_sum, v1_sum);+}++static inline cpFloat+normal_relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n){+ return cpvdot(relative_velocity(a, b, r1, r2), n);+}++static inline void+apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)+{+ cpBodyApplyImpulse(a, cpvneg(j), r1);+ cpBodyApplyImpulse(b, j, r2);+}++static inline void+apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)+{+ cpBodyApplyBiasImpulse(a, cpvneg(j), r1);+ cpBodyApplyBiasImpulse(b, j, r2);+}++static inline cpVect+clamp_vect(cpVect v, cpFloat len)+{+ return cpvclamp(v, len);+// return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;+}++static inline cpFloat+k_scalar(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)+{+ cpFloat mass_sum = a->m_inv + b->m_inv;+ cpFloat r1cn = cpvcross(r1, n);+ cpFloat r2cn = cpvcross(r2, n);++ return mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;+}++static inline void+k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect *k1, cpVect *k2)+{+ // calculate mass matrix+ // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...+ cpFloat k11, k12, k21, k22;+ cpFloat m_sum = a->m_inv + b->m_inv;+ + // start with I*m_sum+ k11 = m_sum; k12 = 0.0f;+ k21 = 0.0f; k22 = m_sum;+ + // add the influence from r1+ cpFloat a_i_inv = a->i_inv;+ cpFloat r1xsq = r1.x * r1.x * a_i_inv;+ cpFloat r1ysq = r1.y * r1.y * a_i_inv;+ cpFloat r1nxy = -r1.x * r1.y * a_i_inv;+ k11 += r1ysq; k12 += r1nxy;+ k21 += r1nxy; k22 += r1xsq;+ + // add the influnce from r2+ cpFloat b_i_inv = b->i_inv;+ cpFloat r2xsq = r2.x * r2.x * b_i_inv;+ cpFloat r2ysq = r2.y * r2.y * b_i_inv;+ cpFloat r2nxy = -r2.x * r2.y * b_i_inv;+ k11 += r2ysq; k12 += r2nxy;+ k21 += r2nxy; k22 += r2xsq;+ + // invert+ cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);+ *k1 = cpv( k22*det_inv, -k12*det_inv);+ *k2 = cpv(-k21*det_inv, k11*det_inv);+}++static inline cpVect+mult_k(cpVect vr, cpVect k1, cpVect k2)+{+ return cpv(cpvdot(vr, k1), cpvdot(vr, k2));+}
+ chipmunk-5.0/cpArbiter.c view
@@ -0,0 +1,254 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>++#include "chipmunk.h"+#include "constraints/util.h"++cpFloat cp_bias_coef = 0.1f;+cpFloat cp_collision_slop = 0.1f;++cpContact*+cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash)+{+ con->p = p;+ con->n = n;+ con->dist = dist;+ + con->jnAcc = 0.0f;+ con->jtAcc = 0.0f;+ con->jBias = 0.0f;+ + con->hash = hash;+ + return con;+}++cpVect+cpContactsSumImpulses(cpContact *contacts, int numContacts)+{+ cpVect sum = cpvzero;+ + for(int i=0; i<numContacts; i++){+ cpContact *con = &contacts[i];+ sum = cpvadd(sum, cpvmult(con->n, con->jnAcc));+ }+ + return sum;+}++cpVect+cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts)+{+ cpVect sum = cpvzero;+ + for(int i=0; i<numContacts; i++){+ cpContact *con = &contacts[i];+ sum = cpvadd(sum, cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc)));+ }+ + return sum;+}++cpFloat+cpContactsEstimateCrushingImpulse(cpContact *contacts, int numContacts)+{+ cpFloat fsum = 0.0f;+ cpVect vsum = cpvzero;+ + for(int i=0; i<numContacts; i++){+ cpContact *con = &contacts[i];+ cpVect j = cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc));+ + fsum += cpvlength(j);+ vsum = cpvadd(vsum, j);+ }+ + cpFloat vmag = cpvlength(vsum);+ return (1.0f - vmag/fsum);+}++cpArbiter*+cpArbiterAlloc(void)+{+ return (cpArbiter *)calloc(1, sizeof(cpArbiter));+}++cpArbiter*+cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b, int stamp)+{+ arb->numContacts = 0;+ arb->contacts = NULL;+ + arb->a = a;+ arb->b = b;+ + arb->stamp = stamp;+ + return arb;+}++cpArbiter*+cpArbiterNew(cpShape *a, cpShape *b, int stamp)+{+ return cpArbiterInit(cpArbiterAlloc(), a, b, stamp);+}++void+cpArbiterDestroy(cpArbiter *arb)+{+ free(arb->contacts);+}++void+cpArbiterFree(cpArbiter *arb)+{+ if(arb) cpArbiterDestroy(arb);+ free(arb);+}++void+cpArbiterInject(cpArbiter *arb, cpContact *contacts, int numContacts)+{+ // Iterate over the possible pairs to look for hash value matches.+ for(int i=0; i<arb->numContacts; i++){+ cpContact *old = &arb->contacts[i];+ + for(int j=0; j<numContacts; j++){+ cpContact *new_contact = &contacts[j];+ + // This could trigger false positives, but is fairly unlikely nor serious if it does.+ if(new_contact->hash == old->hash){+ // Copy the persistant contact information.+ new_contact->jnAcc = old->jnAcc;+ new_contact->jtAcc = old->jtAcc;+ }+ }+ }++ free(arb->contacts);+ + arb->contacts = contacts;+ arb->numContacts = numContacts;+}++void+cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv)+{+ cpShape *shapea = arb->a;+ cpShape *shapeb = arb->b;+ + cpFloat e = shapea->e * shapeb->e;+ arb->u = shapea->u * shapeb->u;+ arb->target_v = cpvsub(shapeb->surface_v, shapea->surface_v);++ cpBody *a = shapea->body;+ cpBody *b = shapeb->body;+ + for(int i=0; i<arb->numContacts; i++){+ cpContact *con = &arb->contacts[i];+ + // Calculate the offsets.+ con->r1 = cpvsub(con->p, a->p);+ con->r2 = cpvsub(con->p, b->p);+ + // Calculate the mass normal and mass tangent.+ con->nMass = 1.0f/k_scalar(a, b, con->r1, con->r2, con->n);+ con->tMass = 1.0f/k_scalar(a, b, con->r1, con->r2, cpvperp(con->n));+ + // Calculate the target bias velocity.+ con->bias = -cp_bias_coef*dt_inv*cpfmin(0.0f, con->dist + cp_collision_slop);+ con->jBias = 0.0f;+ + // Calculate the target bounce velocity.+ con->bounce = normal_relative_velocity(a, b, con->r1, con->r2, con->n)*e;//cpvdot(con->n, cpvsub(v2, v1))*e;+ }+}++void+cpArbiterApplyCachedImpulse(cpArbiter *arb)+{+ cpShape *shapea = arb->a;+ cpShape *shapeb = arb->b;+ + arb->u = shapea->u * shapeb->u;+ arb->target_v = cpvsub(shapeb->surface_v, shapea->surface_v);++ cpBody *a = shapea->body;+ cpBody *b = shapeb->body;+ + for(int i=0; i<arb->numContacts; i++){+ cpContact *con = &arb->contacts[i];+ apply_impulses(a, b, con->r1, con->r2, cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc)));+ }+}++void+cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef)+{+ cpBody *a = arb->a->body;+ cpBody *b = arb->b->body;++ for(int i=0; i<arb->numContacts; i++){+ cpContact *con = &arb->contacts[i];+ cpVect n = con->n;+ cpVect r1 = con->r1;+ cpVect r2 = con->r2;+ + // Calculate the relative bias velocities.+ cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias));+ cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias));+ cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);+ + // Calculate and clamp the bias impulse.+ cpFloat jbn = (con->bias - vbn)*con->nMass;+ cpFloat jbnOld = con->jBias;+ con->jBias = cpfmax(jbnOld + jbn, 0.0f);+ jbn = con->jBias - jbnOld;+ + // Apply the bias impulse.+ apply_bias_impulses(a, b, r1, r2, cpvmult(n, jbn));++ // Calculate the relative velocity.+ cpVect vr = relative_velocity(a, b, r1, r2);+ cpFloat vrn = cpvdot(vr, n);+ + // Calculate and clamp the normal impulse.+ cpFloat jn = -(con->bounce*eCoef + vrn)*con->nMass;+ cpFloat jnOld = con->jnAcc;+ con->jnAcc = cpfmax(jnOld + jn, 0.0f);+ jn = con->jnAcc - jnOld;+ + // Calculate the relative tangent velocity.+ cpFloat vrt = cpvdot(cpvadd(vr, arb->target_v), cpvperp(n));+ + // Calculate and clamp the friction impulse.+ cpFloat jtMax = arb->u*con->jnAcc;+ cpFloat jt = -vrt*con->tMass;+ cpFloat jtOld = con->jtAcc;+ con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax);+ jt = con->jtAcc - jtOld;+ + // Apply the final impulse.+ apply_impulses(a, b, r1, r2, cpvrotate(n, cpv(jn, jt)));+ }+}
+ chipmunk-5.0/cpArbiter.h view
@@ -0,0 +1,85 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++// Determines how fast penetrations resolve themselves.+extern cpFloat cp_bias_coef;+// Amount of allowed penetration. Used to reduce vibrating contacts.+extern cpFloat cp_collision_slop;++// Data structure for contact points.+typedef struct cpContact{+ // Contact point and normal.+ cpVect p, n;+ // Penetration distance.+ cpFloat dist;+ + // Calculated by cpArbiterPreStep().+ cpVect r1, r2;+ cpFloat nMass, tMass, bounce;++ // Persistant contact information.+ cpFloat jnAcc, jtAcc, jBias;+ cpFloat bias;+ + // Hash value used to (mostly) uniquely identify a contact.+ cpHashValue hash;+} cpContact;++// Contacts are always allocated in groups.+cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash);++// Sum the contact impulses. (Can be used after cpSpaceStep() returns)+cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts);+cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts);++// Data structure for tracking collisions between shapes.+typedef struct cpArbiter{+ // Information on the contact points between the objects.+ int numContacts;+ cpContact *contacts;+ + // The two shapes involved in the collision.+ cpShape *a, *b;+ + // Calculated by cpArbiterPreStep().+ cpFloat u;+ cpVect target_v;+ + // Time stamp of the arbiter. (from cpSpace)+ int stamp;+} cpArbiter;++// Basic allocation/destruction functions.+cpArbiter* cpArbiterAlloc(void);+cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b, int stamp);+cpArbiter* cpArbiterNew(cpShape *a, cpShape *b, int stamp);++void cpArbiterDestroy(cpArbiter *arb);+void cpArbiterFree(cpArbiter *arb);++// These functions are all intended to be used internally.+// Inject new contact points into the arbiter while preserving contact history.+void cpArbiterInject(cpArbiter *arb, cpContact *contacts, int numContacts);+// Precalculate values used by the solver.+void cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv);+void cpArbiterApplyCachedImpulse(cpArbiter *arb);+// Run an iteration of the solver on the arbiter.+void cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef);
+ chipmunk-5.0/cpArray.c view
@@ -0,0 +1,114 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <string.h>++#include "chipmunk.h"+++//#define CP_ARRAY_INCREMENT 10++// NOTE: cpArray is rarely used and will probably go away.++cpArray*+cpArrayAlloc(void)+{+ return (cpArray *)calloc(1, sizeof(cpArray));+}++cpArray*+cpArrayInit(cpArray *arr, int size)+{+ arr->num = 0;+ + size = (size ? size : 4);+ arr->max = size;+ arr->arr = (void **)malloc(size*sizeof(void**));+ + return arr;+}++cpArray*+cpArrayNew(int size)+{+ return cpArrayInit(cpArrayAlloc(), size);+}++void+cpArrayDestroy(cpArray *arr)+{+ free(arr->arr);+}++void+cpArrayFree(cpArray *arr)+{+ if(!arr) return;+ cpArrayDestroy(arr);+ free(arr);+}++void+cpArrayPush(cpArray *arr, void *object)+{+ if(arr->num == arr->max){+ arr->max *= 2;+ arr->arr = (void **)realloc(arr->arr, arr->max*sizeof(void**));+ }+ + arr->arr[arr->num] = object;+ arr->num++;+}++void+cpArrayDeleteIndex(cpArray *arr, int index)+{+ int last = --arr->num;+ arr->arr[index] = arr->arr[last];+}++void+cpArrayDeleteObj(cpArray *arr, void *obj)+{+ for(int i=0; i<arr->num; i++){+ if(arr->arr[i] == obj){+ cpArrayDeleteIndex(arr, i);+ return;+ }+ }+}++void+cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data)+{+ for(int i=0; i<arr->num; i++)+ iterFunc(arr->arr[i], data);+}++int+cpArrayContains(cpArray *arr, void *ptr)+{+ for(int i=0; i<arr->num; i++)+ if(arr->arr[i] == ptr) return 1;+ + return 0;+}
+ chipmunk-5.0/cpArray.h view
@@ -0,0 +1,45 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +// NOTE: cpArray is rarely used and will probably go away.++typedef struct cpArray{+ int num, max;+ void **arr;+} cpArray;++typedef void (*cpArrayIter)(void *ptr, void *data);++cpArray *cpArrayAlloc(void);+cpArray *cpArrayInit(cpArray *arr, int size);+cpArray *cpArrayNew(int size);++void cpArrayDestroy(cpArray *arr);+void cpArrayFree(cpArray *arr);++void cpArrayClear(cpArray *arr);++void cpArrayPush(cpArray *arr, void *object);+void cpArrayDeleteIndex(cpArray *arr, int index);+void cpArrayDeleteObj(cpArray *arr, void *obj);++void cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data);+int cpArrayContains(cpArray *arr, void *ptr);
+ chipmunk-5.0/cpBB.c view
@@ -0,0 +1,47 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <math.h>+#include <stdlib.h>++#include "chipmunk.h"++cpVect+cpBBClampVect(const cpBB bb, const cpVect v)+{+ cpFloat x = cpfmin(cpfmax(bb.l, v.x), bb.r);+ cpFloat y = cpfmin(cpfmax(bb.b, v.y), bb.t);+ return cpv(x, y);+}++cpVect+cpBBWrapVect(const cpBB bb, const cpVect v)+{+ cpFloat ix = fabsf(bb.r - bb.l);+ cpFloat modx = cpfmod(v.x - bb.l, ix);+ cpFloat x = (modx > 0.0f) ? modx : modx + ix;+ + cpFloat iy = fabsf(bb.t - bb.b);+ cpFloat mody = cpfmod(v.y - bb.b, iy);+ cpFloat y = (mody > 0.0f) ? mody : mody + iy;+ + return cpv(x + bb.l, y + bb.b);+}
+ chipmunk-5.0/cpBB.h view
@@ -0,0 +1,53 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +typedef struct cpBB{+ cpFloat l, b, r ,t;+} cpBB;++static inline cpBB+cpBBNew(const cpFloat l, const cpFloat b,+ const cpFloat r, const cpFloat t)+{+ cpBB bb = {l, b, r, t};+ return bb;+}++static inline int+cpBBintersects(const cpBB a, const cpBB b)+{+ return (a.l<=b.r && b.l<=a.r && a.b<=b.t && b.b<=a.t);+}++static inline int+cpBBcontainsBB(const cpBB bb, const cpBB other)+{+ return (bb.l < other.l && bb.r > other.r && bb.b < other.b && bb.t > other.t);+}++static inline int+cpBBcontainsVect(const cpBB bb, const cpVect v)+{+ return (bb.l < v.x && bb.r > v.x && bb.b < v.y && bb.t > v.y);+}++cpVect cpBBClampVect(const cpBB bb, const cpVect v); // clamps the vector to lie within the bbox+cpVect cpBBWrapVect(const cpBB bb, const cpVect v); // wrap a vector to a bbox
+ chipmunk-5.0/cpBody.c view
@@ -0,0 +1,179 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <float.h>++#include "chipmunk.h"++cpBody*+cpBodyAlloc(void)+{+ return (cpBody *)malloc(sizeof(cpBody));+}++cpBody*+cpBodyInit(cpBody *body, cpFloat m, cpFloat i)+{+ body->velocity_func = cpBodyUpdateVelocity;+ body->position_func = cpBodyUpdatePosition;+ + cpBodySetMass(body, m);+ cpBodySetMoment(body, i);++ body->p = cpvzero;+ body->v = cpvzero;+ body->f = cpvzero;+ + cpBodySetAngle(body, 0.0f);+ body->w = 0.0f;+ body->t = 0.0f;+ + body->v_bias = cpvzero;+ body->w_bias = 0.0f;+ + body->data = NULL;+// body->active = 1;++ return body;+}++cpBody*+cpBodyNew(cpFloat m, cpFloat i)+{+ return cpBodyInit(cpBodyAlloc(), m, i);+}++void cpBodyDestroy(cpBody *body){}++void+cpBodyFree(cpBody *body)+{+ if(body) cpBodyDestroy(body);+ free(body);+}++void+cpBodySetMass(cpBody *body, cpFloat mass)+{+ body->m = mass;+ body->m_inv = 1.0f/mass;+}++void+cpBodySetMoment(cpBody *body, cpFloat moment)+{+ body->i = moment;+ body->i_inv = 1.0f/moment;+}++void+cpBodySetAngle(cpBody *body, cpFloat angle)+{+ body->a = angle;//fmod(a, (cpFloat)M_PI*2.0f);+ body->rot = cpvforangle(angle);+}++void+cpBodySlew(cpBody *body, cpVect pos, cpFloat dt)+{+ cpVect delta = cpvsub(pos, body->p);+ body->v = cpvmult(delta, 1.0/dt);+}++void+cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)+{+ body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));+ body->w = body->w*damping + body->t*body->i_inv*dt;+}++void+cpBodyUpdatePosition(cpBody *body, cpFloat dt)+{+ body->p = cpvadd(body->p, cpvmult(cpvadd(body->v, body->v_bias), dt));+ cpBodySetAngle(body, body->a + (body->w + body->w_bias)*dt);+ + body->v_bias = cpvzero;+ body->w_bias = 0.0f;+}++void+cpBodyResetForces(cpBody *body)+{+ body->f = cpvzero;+ body->t = 0.0f;+}++void+cpBodyApplyForce(cpBody *body, cpVect force, cpVect r)+{+ body->f = cpvadd(body->f, force);+ body->t += cpvcross(r, force);+}++void+cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt)+{+ // Calculate the world space anchor coordinates.+ cpVect r1 = cpvrotate(anchr1, a->rot);+ cpVect r2 = cpvrotate(anchr2, b->rot);+ + cpVect delta = cpvsub(cpvadd(b->p, r2), cpvadd(a->p, r1));+ cpFloat dist = cpvlength(delta);+ cpVect n = dist ? cpvmult(delta, 1.0f/dist) : cpvzero;+ + cpFloat f_spring = (dist - rlen)*k;++ // Calculate the world relative velocities of the anchor points.+ cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));+ cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));+ + // Calculate the damping force.+ // This really should be in the impulse solver and can produce problems when using large damping values.+ cpFloat vrn = cpvdot(cpvsub(v2, v1), n);+ cpFloat f_damp = vrn*cpfmin(dmp, 1.0f/(dt*(a->m_inv + b->m_inv)));+ + // Apply!+ cpVect f = cpvmult(n, f_spring + f_damp);+ cpBodyApplyForce(a, f, r1);+ cpBodyApplyForce(b, cpvneg(f), r2);+}++//int+//cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max)+//{+// cpFloat ke = body->m*cpvdot(body->v, body->v);+// cpFloat re = body->i*body->w*body->w;+// +// if(ke + re > body->m*dvsq)+// body->active = 1;+// else if(body->active)+// body->active = (body->active + 1)%(max + 1);+// else {+// body->v = cpvzero;+// body->v_bias = cpvzero;+// body->w = 0.0f;+// body->w_bias = 0.0f;+// }+// +// return body->active;+//}
+ chipmunk-5.0/cpBody.h view
@@ -0,0 +1,153 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++struct cpBody;+typedef void (*cpBodyVelocityFunc)(struct cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);+typedef void (*cpBodyPositionFunc)(struct cpBody *body, cpFloat dt);++ +typedef struct cpBody{+ // *** Integration Functions.ntoehu++ // Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)+ cpBodyVelocityFunc velocity_func;+ + // Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)+ cpBodyPositionFunc position_func;+ + // *** Mass Properties+ + // Mass and it's inverse.+ // Always use cpBodySetMass() whenever changing the mass as these values must agree.+ cpFloat m, m_inv;+ + // Moment of inertia and it's inverse.+ // Always use cpBodySetMass() whenever changing the mass as these values must agree.+ cpFloat i, i_inv;+ + // *** Positional Properties+ + // Linear components of motion (position, velocity, and force)+ cpVect p, v, f;+ + // Angular components of motion (angle, angular velocity, and torque)+ // Always use cpBodySetAngle() to set the angle of the body as a and rot must agree.+ cpFloat a, w, t;+ + // Cached unit length vector representing the angle of the body.+ // Used for fast vector rotation using cpvrotate().+ cpVect rot;+ + // *** User Definable Fields+ + // User defined data pointer.+ void *data;+ + // *** Internally Used Fields+ + // Velocity bias values used when solving penetrations and correcting constraints.+ cpVect v_bias;+ cpFloat w_bias;+ +// int active;+} cpBody;++// Basic allocation/destruction functions+cpBody *cpBodyAlloc(void);+cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);+cpBody *cpBodyNew(cpFloat m, cpFloat i);++void cpBodyDestroy(cpBody *body);+void cpBodyFree(cpBody *body);++#define CP_DefineBodyGetter(type, member, name) static inline type cpBodyGet##name(cpBody *body){return body->member;}+#define CP_DefineBodySetter(type, member, name) static inline void cpBodySet##name(cpBody *body, type value){body->member = value;}++#define CP_DefineBodyProperty(type, member, name) \+CP_DefineBodyGetter(type, member, name) \+CP_DefineBodySetter(type, member, name)+++// Accessors for cpBody struct members+CP_DefineBodyGetter(cpFloat, m, Mass);+void cpBodySetMass(cpBody *body, cpFloat m);++CP_DefineBodyGetter(cpFloat, i, Moment);+void cpBodySetMoment(cpBody *body, cpFloat i);+++CP_DefineBodyProperty(cpVect, p, Pos);+CP_DefineBodyProperty(cpVect, v, Vel);+CP_DefineBodyProperty(cpVect, f, Force);+CP_DefineBodyGetter(cpFloat, a, Angle);+void cpBodySetAngle(cpBody *body, cpFloat a);+CP_DefineBodyProperty(cpFloat, w, AngVel);+CP_DefineBodyProperty(cpFloat, t, Torque);+CP_DefineBodyGetter(cpVect, rot, Rot);++// Modify the velocity of the body so that it will move to the specified absolute coordinates in the next timestep.+// Intended for objects that are moved manually with a custom velocity integration function.+void cpBodySlew(cpBody *body, cpVect pos, cpFloat dt);++// Default Integration functions.+void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);+void cpBodyUpdatePosition(cpBody *body, cpFloat dt);++// Convert body local to world coordinates+static inline cpVect+cpBodyLocal2World(cpBody *body, cpVect v)+{+ return cpvadd(body->p, cpvrotate(v, body->rot));+}++// Convert world to body local coordinates+static inline cpVect+cpBodyWorld2Local(cpBody *body, cpVect v)+{+ return cpvunrotate(cpvsub(v, body->p), body->rot);+}++// Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).+static inline void+cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r)+{+ body->v = cpvadd(body->v, cpvmult(j, body->m_inv));+ body->w += body->i_inv*cpvcross(r, j);+}++// Not intended for external use. Used by cpArbiter.c and cpConstraint.c.+static inline void+cpBodyApplyBiasImpulse(cpBody *body, cpVect j, cpVect r)+{+ body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));+ body->w_bias += body->i_inv*cpvcross(r, j);+}++// Zero the forces on a body.+void cpBodyResetForces(cpBody *body);+// Apply a force (in world coordinates) to a body at a point relative to the center of gravity (also in world coordinates).+void cpBodyApplyForce(cpBody *body, cpVect f, cpVect r);++// Apply a damped spring force between two bodies.+// Warning: Large damping values can be unstable. Use a cpDampedSpring constraint for this instead.+void cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);++//int cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max);
+ chipmunk-5.0/cpCollision.c view
@@ -0,0 +1,403 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <math.h>+#include <stdio.h>+#include <assert.h>++#include "chipmunk.h"++typedef int (*collisionFunc)(cpShape*, cpShape*, cpContact**);++// Add contact points for circle to circle collisions.+// Used by several collision tests.+static int+circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact **con)+{+ cpFloat mindist = r1 + r2;+ cpVect delta = cpvsub(p2, p1);+ cpFloat distsq = cpvlengthsq(delta);+ if(distsq >= mindist*mindist) return 0;+ + cpFloat dist = cpfsqrt(distsq);+ // To avoid singularities, do nothing in the case of dist = 0.+ cpFloat non_zero_dist = (dist ? dist : INFINITY);++ // Allocate and initialize the contact.+ (*con) = (cpContact *)malloc(sizeof(cpContact));+ cpContactInit(+ (*con),+ cpvadd(p1, cpvmult(delta, 0.5 + (r1 - 0.5*mindist)/non_zero_dist)),+ cpvmult(delta, 1.0/non_zero_dist),+ dist - mindist,+ 0+ );+ + return 1;+}++// Collide circle shapes.+static int+circle2circle(cpShape *shape1, cpShape *shape2, cpContact **arr)+{+ cpCircleShape *circ1 = (cpCircleShape *)shape1;+ cpCircleShape *circ2 = (cpCircleShape *)shape2;+ + return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr);+}++// Collide circles to segment shapes.+static int+circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact **con)+{+ cpCircleShape *circ = (cpCircleShape *)circleShape;+ cpSegmentShape *seg = (cpSegmentShape *)segmentShape;+ + // Radius sum+ cpFloat rsum = circ->r + seg->r;+ + // Calculate normal distance from segment.+ cpFloat dn = cpvdot(seg->tn, circ->tc) - cpvdot(seg->ta, seg->tn);+ cpFloat dist = cpfabs(dn) - rsum;+ if(dist > 0.0f) return 0;+ + // Calculate tangential distance along segment.+ cpFloat dt = -cpvcross(seg->tn, circ->tc);+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);+ + // Decision tree to decide which feature of the segment to collide with.+ if(dt < dtMin){+ if(dt < (dtMin - rsum)){+ return 0;+ } else {+ return circle2circleQuery(circ->tc, seg->ta, circ->r, seg->r, con);+ }+ } else {+ if(dt < dtMax){+ cpVect n = (dn < 0.0f) ? seg->tn : cpvneg(seg->tn);+ (*con) = (cpContact *)malloc(sizeof(cpContact));+ cpContactInit(+ (*con),+ cpvadd(circ->tc, cpvmult(n, circ->r + dist*0.5f)),+ n,+ dist,+ 0 + );+ return 1;+ } else {+ if(dt < (dtMax + rsum)) {+ return circle2circleQuery(circ->tc, seg->tb, circ->r, seg->r, con);+ } else {+ return 0;+ }+ }+ }+ + return 1;+}++// Helper function for allocating contact point lists.+static cpContact *+addContactPoint(cpContact **arr, int *max, int *num)+{+ if(*arr == NULL){+ // Allocate the array if it hasn't been done.+ (*max) = 2;+ (*num) = 0;+ (*arr) = (cpContact *)malloc((*max)*sizeof(cpContact));+ } else if(*num == *max){+ // Extend it if necessary.+ (*max) *= 2;+ (*arr) = (cpContact *)realloc(*arr, (*max)*sizeof(cpContact));+ }+ + cpContact *con = &(*arr)[*num];+ (*num)++;+ + return con;+}++// Find the minimum separating axis for the give poly and axis list.+static inline int+findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out)+{+ int min_index = 0;+ cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);+ if(min > 0.0) return -1;+ + for(int i=1; i<num; i++){+ cpFloat dist = cpPolyShapeValueOnAxis(poly, axes[i].n, axes[i].d);+ if(dist > 0.0) {+ return -1;+ } else if(dist > min){+ min = dist;+ min_index = i;+ }+ }+ + (*min_out) = min;+ return min_index;+}++// Add contacts for penetrating vertexes.+static inline int+findVerts(cpContact **arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist)+{+ int max = 0;+ int num = 0;+ + for(int i=0; i<poly1->numVerts; i++){+ cpVect v = poly1->tVerts[i];+ if(cpPolyShapeContainsVertPartial(poly2, v, cpvneg(n)))+ cpContactInit(addContactPoint(arr, &max, &num), v, n, dist, CP_HASH_PAIR(poly1, i));+ }+ + for(int i=0; i<poly2->numVerts; i++){+ cpVect v = poly2->tVerts[i];+ if(cpPolyShapeContainsVertPartial(poly1, v, n))+ cpContactInit(addContactPoint(arr, &max, &num), v, n, dist, CP_HASH_PAIR(poly2, i));+ }+ + // if(!num)+ // addContactPoint(arr, &size, &num, cpContactNew(shape1->body->p, n, dist, 0));++ return num;+}++// Collide poly shapes together.+static int+poly2poly(cpShape *shape1, cpShape *shape2, cpContact **arr)+{+ cpPolyShape *poly1 = (cpPolyShape *)shape1;+ cpPolyShape *poly2 = (cpPolyShape *)shape2;+ + cpFloat min1;+ int mini1 = findMSA(poly2, poly1->tAxes, poly1->numVerts, &min1);+ if(mini1 == -1) return 0;+ + cpFloat min2;+ int mini2 = findMSA(poly1, poly2->tAxes, poly2->numVerts, &min2);+ if(mini2 == -1) return 0;+ + // There is overlap, find the penetrating verts+ if(min1 > min2)+ return findVerts(arr, poly1, poly2, poly1->tAxes[mini1].n, min1);+ else+ return findVerts(arr, poly1, poly2, cpvneg(poly2->tAxes[mini2].n), min2);+}++// Like cpPolyValueOnAxis(), but for segments.+static inline float+segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)+{+ cpFloat a = cpvdot(n, seg->ta) - seg->r;+ cpFloat b = cpvdot(n, seg->tb) - seg->r;+ return cpfmin(a, b) - d;+}++// Identify vertexes that have penetrated the segment.+static inline void+findPointsBehindSeg(cpContact **arr, int *max, int *num, cpSegmentShape *seg, cpPolyShape *poly, cpFloat pDist, cpFloat coef) +{+ cpFloat dta = cpvcross(seg->tn, seg->ta);+ cpFloat dtb = cpvcross(seg->tn, seg->tb);+ cpVect n = cpvmult(seg->tn, coef);+ + for(int i=0; i<poly->numVerts; i++){+ cpVect v = poly->tVerts[i];+ if(cpvdot(v, n) < cpvdot(seg->tn, seg->ta)*coef + seg->r){+ cpFloat dt = cpvcross(seg->tn, v);+ if(dta >= dt && dt >= dtb){+ cpContactInit(addContactPoint(arr, max, num), v, n, pDist, CP_HASH_PAIR(poly, i));+ }+ }+ }+}++// This one is complicated and gross. Just don't go there...+// TODO: Comment me!+static int+seg2poly(cpShape *shape1, cpShape *shape2, cpContact **arr)+{+ cpSegmentShape *seg = (cpSegmentShape *)shape1;+ cpPolyShape *poly = (cpPolyShape *)shape2;+ cpPolyShapeAxis *axes = poly->tAxes;+ + cpFloat segD = cpvdot(seg->tn, seg->ta);+ cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r;+ cpFloat minNeg = cpPolyShapeValueOnAxis(poly, cpvneg(seg->tn), -segD) - seg->r;+ if(minNeg > 0.0f || minNorm > 0.0f) return 0;+ + int mini = 0;+ cpFloat poly_min = segValueOnAxis(seg, axes->n, axes->d);+ if(poly_min > 0.0f) return 0;+ for(int i=0; i<poly->numVerts; i++){+ cpFloat dist = segValueOnAxis(seg, axes[i].n, axes[i].d);+ if(dist > 0.0f){+ return 0;+ } else if(dist > poly_min){+ poly_min = dist;+ mini = i;+ }+ }+ + int max = 0;+ int num = 0;+ + cpVect poly_n = cpvneg(axes[mini].n);+ + cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r));+ cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r));+ if(cpPolyShapeContainsVert(poly, va))+ cpContactInit(addContactPoint(arr, &max, &num), va, poly_n, poly_min, CP_HASH_PAIR(seg, 0));+ if(cpPolyShapeContainsVert(poly, vb))+ cpContactInit(addContactPoint(arr, &max, &num), vb, poly_n, poly_min, CP_HASH_PAIR(seg, 1));++ // Floating point precision problems here.+ // This will have to do for now.+ poly_min -= cp_collision_slop;+ if(minNorm >= poly_min || minNeg >= poly_min) {+ if(minNorm > minNeg)+ findPointsBehindSeg(arr, &max, &num, seg, poly, minNorm, 1.0f);+ else+ findPointsBehindSeg(arr, &max, &num, seg, poly, minNeg, -1.0f);+ }+ + // If no other collision points are found, try colliding endpoints.+ if(num == 0){+ cpVect poly_a = poly->tVerts[mini];+ cpVect poly_b = poly->tVerts[(mini + 1)%poly->numVerts];+ + if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr))+ return 1;+ + if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr))+ return 1;+ + if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr))+ return 1;+ + if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr))+ return 1;+ }++ return num;+}++// This one is less gross, but still gross.+// TODO: Comment me!+static int+circle2poly(cpShape *shape1, cpShape *shape2, cpContact **con)+{+ cpCircleShape *circ = (cpCircleShape *)shape1;+ cpPolyShape *poly = (cpPolyShape *)shape2;+ cpPolyShapeAxis *axes = poly->tAxes;+ + int mini = 0;+ cpFloat min = cpvdot(axes->n, circ->tc) - axes->d - circ->r;+ for(int i=0; i<poly->numVerts; i++){+ cpFloat dist = cpvdot(axes[i].n, circ->tc) - axes[i].d - circ->r;+ if(dist > 0.0){+ return 0;+ } else if(dist > min) {+ min = dist;+ mini = i;+ }+ }+ + cpVect n = axes[mini].n;+ cpVect a = poly->tVerts[mini];+ cpVect b = poly->tVerts[(mini + 1)%poly->numVerts];+ cpFloat dta = cpvcross(n, a);+ cpFloat dtb = cpvcross(n, b);+ cpFloat dt = cpvcross(n, circ->tc);+ + if(dt < dtb){+ return circle2circleQuery(circ->tc, b, circ->r, 0.0f, con);+ } else if(dt < dta) {+ (*con) = (cpContact *)malloc(sizeof(cpContact));+ cpContactInit(+ (*con),+ cpvsub(circ->tc, cpvmult(n, circ->r + min/2.0f)),+ cpvneg(n),+ min,+ 0 + );+ + return 1;+ } else {+ return circle2circleQuery(circ->tc, a, circ->r, 0.0f, con);+ }+}++//static const collisionFunc builtinCollisionFuncs[9] = {+// circle2circle,+// NULL,+// NULL,+// circle2segment,+// NULL,+// NULL,+// circle2poly,+// seg2poly,+// poly2poly,+//};+//static const collisionFunc *colfuncs = builtinCollisionFuncs;++static collisionFunc *colfuncs = NULL;++static void+addColFunc(cpShapeType a, cpShapeType b, collisionFunc func)+{+ colfuncs[a + b*CP_NUM_SHAPES] = func;+}++#ifdef __cplusplus+extern "C" {+#endif+ // Initializes the array of collision functions.+ // Called by cpInitChipmunk().+ void+ cpInitCollisionFuncs(void)+ {+ if(!colfuncs)+ colfuncs = (collisionFunc *)calloc(CP_NUM_SHAPES*CP_NUM_SHAPES, sizeof(collisionFunc));+ + addColFunc(CP_CIRCLE_SHAPE, CP_CIRCLE_SHAPE, circle2circle);+ addColFunc(CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, circle2segment);+ addColFunc(CP_SEGMENT_SHAPE, CP_POLY_SHAPE, seg2poly);+ addColFunc(CP_CIRCLE_SHAPE, CP_POLY_SHAPE, circle2poly);+ addColFunc(CP_POLY_SHAPE, CP_POLY_SHAPE, poly2poly);+ } +#ifdef __cplusplus+}+#endif++int+cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr)+{+ // Their shape types must be in order.+ assert(a->klass->type <= b->klass->type);+ + collisionFunc cfunc = colfuncs[a->klass->type + b->klass->type*CP_NUM_SHAPES];+ return (cfunc) ? cfunc(a, b, arr) : 0;+}
+ chipmunk-5.0/cpCollision.h view
@@ -0,0 +1,23 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++// Collides two cpShape structures. (this function is lonely :( )+int cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr);
+ chipmunk-5.0/cpHashSet.c view
@@ -0,0 +1,225 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <assert.h>++#include "chipmunk.h"+#include "prime.h"++void+cpHashSetDestroy(cpHashSet *set)+{+ // Free the chains.+ for(int i=0; i<set->size; i++){+ // Free the bins in the chain.+ cpHashSetBin *bin = set->table[i];+ while(bin){+ cpHashSetBin *next = bin->next;+ free(bin);+ bin = next;+ }+ }+ + // Free the table.+ free(set->table);+}++void+cpHashSetFree(cpHashSet *set)+{+ if(set) cpHashSetDestroy(set);+ free(set);+}++cpHashSet *+cpHashSetAlloc(void)+{+ return (cpHashSet *)calloc(1, sizeof(cpHashSet));+}++cpHashSet *+cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)+{+ set->size = next_prime(size);+ set->entries = 0;+ + set->eql = eqlFunc;+ set->trans = trans;+ + set->default_value = NULL;+ + set->table = (cpHashSetBin **)calloc(set->size, sizeof(cpHashSetBin *));+ + return set;+}++cpHashSet *+cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)+{+ return cpHashSetInit(cpHashSetAlloc(), size, eqlFunc, trans);+}++static int+setIsFull(cpHashSet *set)+{+ return (set->entries >= set->size);+}++static void+cpHashSetResize(cpHashSet *set)+{+ // Get the next approximate doubled prime.+ int newSize = next_prime(set->size + 1);+ // Allocate a new table.+ cpHashSetBin **newTable = (cpHashSetBin **)calloc(newSize, sizeof(cpHashSetBin *));+ + // Iterate over the chains.+ for(int i=0; i<set->size; i++){+ // Rehash the bins into the new table.+ cpHashSetBin *bin = set->table[i];+ while(bin){+ cpHashSetBin *next = bin->next;+ + int index = bin->hash%newSize;+ bin->next = newTable[index];+ newTable[index] = bin;+ + bin = next;+ }+ }+ + free(set->table);+ + set->table = newTable;+ set->size = newSize;+}++void *+cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data)+{+ int index = hash%set->size;+ + // Find the bin with the matching element.+ cpHashSetBin *bin = set->table[index];+ while(bin && !set->eql(ptr, bin->elt))+ bin = bin->next;+ + // Create it necessary.+ if(!bin){+ bin = (cpHashSetBin *)malloc(sizeof(cpHashSetBin));+ bin->hash = hash;+ bin->elt = set->trans(ptr, data); // Transform the pointer.+ + bin->next = set->table[index];+ set->table[index] = bin;+ + set->entries++;+ + // Resize the set if it's full.+ if(setIsFull(set))+ cpHashSetResize(set);+ }+ + return bin->elt;+}++void *+cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr)+{+ int index = hash%set->size;+ + // Pointer to the previous bin pointer.+ cpHashSetBin **prev_ptr = &set->table[index];+ // Pointer the the current bin.+ cpHashSetBin *bin = set->table[index];+ + // Find the bin+ while(bin && !set->eql(ptr, bin->elt)){+ prev_ptr = &bin->next;+ bin = bin->next;+ }+ + // Remove it if it exists.+ if(bin){+ // Update the previous bin pointer to point to the next bin.+ (*prev_ptr) = bin->next;+ set->entries--;+ + void *return_value = bin->elt;+ +// *bin = (cpHashSetBin){};+ free(bin);+ + return return_value;+ }+ + return NULL;+}++void *+cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr)+{ + int index = hash%set->size;+ cpHashSetBin *bin = set->table[index];+ while(bin && !set->eql(ptr, bin->elt))+ bin = bin->next;+ + return (bin ? bin->elt : set->default_value);+}++void+cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data)+{+ for(int i=0; i<set->size; i++){+ cpHashSetBin *bin = set->table[i];+ while(bin){+ cpHashSetBin *next = bin->next;+ func(bin->elt, data);+ bin = next;+ }+ }+}++void+cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data)+{+ // Iterate over all the chains.+ for(int i=0; i<set->size; i++){+ // The rest works similarly to cpHashSetRemove() above.+ cpHashSetBin **prev_ptr = &set->table[i];+ cpHashSetBin *bin = set->table[i];+ while(bin){+ cpHashSetBin *next = bin->next;+ + if(func(bin->elt, data)){+ prev_ptr = &bin->next;+ } else {+ (*prev_ptr) = next;++ set->entries--;+ free(bin);+ }+ + bin = next;+ }+ }+}
+ chipmunk-5.0/cpHashSet.h view
@@ -0,0 +1,79 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +// cpHashSet uses a chained hashtable implementation.+// Other than the transformation functions, there is nothing fancy going on.++// cpHashSetBin's form the linked lists in the chained hash table.+typedef struct cpHashSetBin {+ // Pointer to the element.+ void *elt;+ // Hash value of the element.+ cpHashValue hash;+ // Next element in the chain.+ struct cpHashSetBin *next;+} cpHashSetBin;++// Equality function. Returns true if ptr is equal to elt.+typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt);+// Used by cpHashSetInsert(). Called to transform the ptr into an element.+typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);+// Iterator function for a hashset.+typedef void (*cpHashSetIterFunc)(void *elt, void *data);+// Reject function. Returns true if elt should be dropped.+typedef int (*cpHashSetRejectFunc)(void *elt, void *data);++typedef struct cpHashSet {+ // Number of elements stored in the table.+ int entries;+ // Number of cells in the table.+ int size;+ + cpHashSetEqlFunc eql;+ cpHashSetTransFunc trans;+ + // Default value returned by cpHashSetFind() when no element is found.+ // Defaults to NULL.+ void *default_value;+ + cpHashSetBin **table;+} cpHashSet;++// Basic allocation/destruction functions.+void cpHashSetDestroy(cpHashSet *set);+void cpHashSetFree(cpHashSet *set);++cpHashSet *cpHashSetAlloc(void);+cpHashSet *cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);+cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);++// Insert an element into the set, returns the element.+// If it doesn't already exist, the transformation function is applied.+void *cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data);+// Remove and return an element from the set.+void *cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr);+// Find an element in the set. Returns the default value if the element isn't found.+void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr);++// Iterate over a hashset.+void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data);+// Iterate over a hashset while rejecting certain elements.+void cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data);
+ chipmunk-5.0/cpPolyShape.c view
@@ -0,0 +1,219 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <stdio.h>+#include <assert.h>++#include "chipmunk.h"++cpPolyShape *+cpPolyShapeAlloc(void)+{+ return (cpPolyShape *)calloc(1, sizeof(cpPolyShape));+}++static void+cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot)+{+ cpVect *src = poly->verts;+ cpVect *dst = poly->tVerts;+ + for(int i=0; i<poly->numVerts; i++)+ dst[i] = cpvadd(p, cpvrotate(src[i], rot));+}++static void+cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot)+{+ cpPolyShapeAxis *src = poly->axes;+ cpPolyShapeAxis *dst = poly->tAxes;+ + for(int i=0; i<poly->numVerts; i++){+ cpVect n = cpvrotate(src[i].n, rot);+ dst[i].n = n;+ dst[i].d = cpvdot(p, n) + src[i].d;+ }+}++static cpBB+cpPolyShapeCacheData(cpShape *shape, cpVect p, cpVect rot)+{+ cpPolyShape *poly = (cpPolyShape *)shape;+ + cpFloat l, b, r, t;+ + cpPolyShapeTransformAxes(poly, p, rot);+ cpPolyShapeTransformVerts(poly, p, rot);+ + cpVect *verts = poly->tVerts;+ l = r = verts[0].x;+ b = t = verts[0].y;+ + // TODO do as part of cpPolyShapeTransformVerts?+ for(int i=1; i<poly->numVerts; i++){+ cpVect v = verts[i];+ + l = cpfmin(l, v.x);+ r = cpfmax(r, v.x);+ + b = cpfmin(b, v.y);+ t = cpfmax(t, v.y);+ }+ + return cpBBNew(l, b, r, t);+}++static void+cpPolyShapeDestroy(cpShape *shape)+{+ cpPolyShape *poly = (cpPolyShape *)shape;+ + free(poly->verts);+ free(poly->tVerts);+ + free(poly->axes);+ free(poly->tAxes);+}++static int+cpPolyShapePointQuery(cpShape *shape, cpVect p){+ return cpBBcontainsVect(shape->bb, p) && cpPolyShapeContainsVert((cpPolyShape *)shape, p);+}++static void+cpPolyShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)+{+ cpPolyShape *poly = (cpPolyShape *)shape;+ cpPolyShapeAxis *axes = poly->tAxes;+ cpVect *verts = poly->tVerts;+ int numVerts = poly->numVerts;+ + for(int i=0; i<numVerts; i++){+ cpVect n = axes[i].n;+ cpFloat an = cpvdot(a, n);+ if(axes[i].d > an) continue;+ + cpFloat bn = cpvdot(b, n);+ cpFloat t = (axes[i].d - an)/(bn - an);+ if(t < 0.0f || 1.0f < t) continue;+ + cpVect point = cpvlerp(a, b, t);+ cpFloat dt = -cpvcross(n, point);+ cpFloat dtMin = -cpvcross(n, verts[i]);+ cpFloat dtMax = -cpvcross(n, verts[(i+1)%numVerts]);+ + if(dtMin <= dt && dt <= dtMax){+ info->shape = shape;+ info->t = t;+ info->n = n;+ }+ }+}++static const cpShapeClass polyClass = {+ CP_POLY_SHAPE,+ cpPolyShapeCacheData,+ cpPolyShapeDestroy,+ cpPolyShapePointQuery,+ cpPolyShapeSegmentQuery,+};++int+cpPolyValidate(cpVect *verts, int numVerts)+{+ for(int i=0; i<numVerts; i++){+ cpVect a = verts[i];+ cpVect b = verts[(i+1)%numVerts];+ cpVect c = verts[(i+2)%numVerts];+ + if(cpvcross(cpvsub(b, a), cpvsub(c, b)) >= 0.0f)+ return 0;+ }+ + return 1;+}++int+cpPolyShapeGetNumVerts(cpShape *shape)+{+ assert(shape->klass == &polyClass);+ return ((cpPolyShape *)shape)->numVerts;+}++cpVect+cpPolyShapeGetVert(cpShape *shape, int index)+{+ assert(shape->klass == &polyClass);+ assert(index < cpPolyShapeGetNumVerts(shape));+ + return ((cpPolyShape *)shape)->verts[index];+}+++static void+setUpVerts(cpPolyShape *poly, int numVerts, cpVect *verts, cpVect offset)+{+ poly->numVerts = numVerts;++ poly->verts = (cpVect *)calloc(numVerts, sizeof(cpVect));+ poly->tVerts = (cpVect *)calloc(numVerts, sizeof(cpVect));+ poly->axes = (cpPolyShapeAxis *)calloc(numVerts, sizeof(cpPolyShapeAxis));+ poly->tAxes = (cpPolyShapeAxis *)calloc(numVerts, sizeof(cpPolyShapeAxis));+ + for(int i=0; i<numVerts; i++){+ cpVect a = cpvadd(offset, verts[i]);+ cpVect b = cpvadd(offset, verts[(i+1)%numVerts]);+ cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));++ poly->verts[i] = a;+ poly->axes[i].n = n;+ poly->axes[i].d = cpvdot(n, a);+ }+}++cpPolyShape *+cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)+{+ // Fail if the user attempts to pass a concave poly, or a bad winding.+ assert(cpPolyValidate(verts, numVerts));+ + setUpVerts(poly, numVerts, verts, offset);+ cpShapeInit((cpShape *)poly, &polyClass, body);++ return poly;+}++cpShape *+cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)+{+ return (cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), body, numVerts, verts, offset);+}++// Unsafe API (chipmunk_unsafe.h)++void+cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset)+{+ assert(shape->klass == &polyClass);+ cpPolyShapeDestroy(shape);+ setUpVerts((cpPolyShape *)shape, numVerts, verts, offset);+}
+ chipmunk-5.0/cpPolyShape.h view
@@ -0,0 +1,100 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++// Axis structure used by cpPolyShape.+typedef struct cpPolyShapeAxis{+ // normal+ cpVect n;+ // distance from origin+ cpFloat d;+} cpPolyShapeAxis;++// Convex polygon shape structure.+typedef struct cpPolyShape{+ cpShape shape;+ + // Vertex and axis lists.+ int numVerts;+ cpVect *verts;+ cpPolyShapeAxis *axes;++ // Transformed vertex and axis lists.+ cpVect *tVerts;+ cpPolyShapeAxis *tAxes;+} cpPolyShape;++// Basic allocation functions.+cpPolyShape *cpPolyShapeAlloc(void);+cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset);+cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);++// Check that a set of vertexes has a correct winding and that they are convex+int cpPolyValidate(cpVect *verts, int numVerts);++int cpPolyShapeGetNumVerts(cpShape *shape);+cpVect cpPolyShapeGetVert(cpShape *shape, int index);++// *** inlined utility functions++// Returns the minimum distance of the polygon to the axis.+static inline cpFloat+cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)+{+ cpVect *verts = poly->tVerts;+ cpFloat min = cpvdot(n, verts[0]);+ + int i;+ for(i=1; i<poly->numVerts; i++)+ min = cpfmin(min, cpvdot(n, verts[i]));+ + return min - d;+}++// Returns true if the polygon contains the vertex.+static inline int+cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v)+{+ cpPolyShapeAxis *axes = poly->tAxes;+ + int i;+ for(i=0; i<poly->numVerts; i++){+ cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;+ if(dist > 0.0) return 0;+ }+ + return 1;+}++// Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.+static inline int+cpPolyShapeContainsVertPartial(cpPolyShape *poly, cpVect v, cpVect n)+{+ cpPolyShapeAxis *axes = poly->tAxes;+ + int i;+ for(i=0; i<poly->numVerts; i++){+ if(cpvdot(axes[i].n, n) < 0.0f) continue;+ cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;+ if(dist > 0.0) return 0;+ }+ + return 1;+}
+ chipmunk-5.0/cpShape.c view
@@ -0,0 +1,401 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <assert.h>+#include <stdio.h>+#include <math.h>++#include "chipmunk.h"++#define CP_DefineShapeGetter(struct, type, member, name) \+CP_DeclareShapeGetter(struct, type, name){ \+ assert(shape->klass == &struct##Class); \+ return ((struct *)shape)->member; \+}+cpHashValue SHAPE_ID_COUNTER = 0;++void+cpResetShapeIdCounter(void)+{+ SHAPE_ID_COUNTER = 0;+}+++cpShape*+cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)+{+ shape->klass = klass;+ + shape->id = SHAPE_ID_COUNTER;+ SHAPE_ID_COUNTER++;+ + shape->body = body;+ + shape->e = 0.0f;+ shape->u = 0.0f;+ shape->surface_v = cpvzero;+ + shape->collision_type = 0;+ shape->group = 0;+ shape->layers = -1;+ + shape->data = NULL;+ + cpShapeCacheBB(shape);+ + return shape;+}++void+cpShapeDestroy(cpShape *shape)+{+ if(shape->klass->destroy) shape->klass->destroy(shape);+}++void+cpShapeFree(cpShape *shape)+{+ if(shape) cpShapeDestroy(shape);+ free(shape);+}++cpBB+cpShapeCacheBB(cpShape *shape)+{+ cpBody *body = shape->body;+ + shape->bb = shape->klass->cacheData(shape, body->p, body->rot);+ return shape->bb;+}++int+cpShapePointQuery(cpShape *shape, cpVect p, cpLayers layers, cpGroup group){+ if(!(group && shape->group && group == shape->group) && (layers&shape->layers)){+ return shape->klass->pointQuery(shape, p);+ }+ + return 0;+}++int+cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpLayers layers, cpGroup group, cpSegmentQueryInfo *info){+ if(!(group && shape->group && group == shape->group) && (layers&shape->layers)){+ shape->klass->segmentQuery(shape, a, b, info);+ }+ + return (info->shape != NULL);+}++void+cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info)+{+ printf("Segment Query:\n");+ printf("\tt: %f\n", info->t);+// printf("\tdist: %f\n", info->dist);+// printf("\tpoint: %s\n", cpvstr(info->point));+ printf("\tn: %s\n", cpvstr(info->n));+}+++++cpCircleShape *+cpCircleShapeAlloc(void)+{+ return (cpCircleShape *)calloc(1, sizeof(cpCircleShape));+}++static inline cpBB+bbFromCircle(const cpVect c, const cpFloat r)+{+ return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);+}++static cpBB+cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)+{+ cpCircleShape *circle = (cpCircleShape *)shape;+ + circle->tc = cpvadd(p, cpvrotate(circle->c, rot));+ return bbFromCircle(circle->tc, circle->r);+}++static int+cpCircleShapePointQuery(cpShape *shape, cpVect p){+ cpCircleShape *circle = (cpCircleShape *)shape;+ return cpvnear(circle->tc, p, circle->r);+}++static void+circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info)+{+ // umm... gross I normally frown upon such things+ a = cpvsub(a, center);+ b = cpvsub(b, center);+ + cpFloat qa = cpvdot(a, a) - 2.0f*cpvdot(a, b) + cpvdot(b, b);+ cpFloat qb = -2.0f*cpvdot(a, a) + 2.0f*cpvdot(a, b);+ cpFloat qc = cpvdot(a, a) - r*r;+ + cpFloat det = qb*qb - 4.0f*qa*qc;+ + if(det >= 0.0f){+ cpFloat t = (-qb - cpfsqrt(det))/(2.0f*qa);+ if(0.0 <= t && t <= 1.0f){+ info->shape = shape;+ info->t = t;+ info->n = cpvnormalize(cpvlerp(a, b, t));+ }+ }+}++static void+cpCircleShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)+{+ cpCircleShape *circle = (cpCircleShape *)shape;+ circleSegmentQuery(shape, circle->tc, circle->r, a, b, info);+}++static const cpShapeClass cpCircleShapeClass = {+ CP_CIRCLE_SHAPE,+ cpCircleShapeCacheData,+ NULL,+ cpCircleShapePointQuery,+ cpCircleShapeSegmentQuery,+};++cpCircleShape *+cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)+{+ circle->c = offset;+ circle->r = radius;+ + cpShapeInit((cpShape *)circle, &cpCircleShapeClass, body);+ + return circle;+}++cpShape *+cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)+{+ return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset);+}++CP_DefineShapeGetter(cpCircleShape, cpVect, c, Center)+CP_DefineShapeGetter(cpCircleShape, cpFloat, r, Radius)++cpSegmentShape *+cpSegmentShapeAlloc(void)+{+ return (cpSegmentShape *)calloc(1, sizeof(cpSegmentShape));+}++static cpBB+cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)+{+ cpSegmentShape *seg = (cpSegmentShape *)shape;+ + seg->ta = cpvadd(p, cpvrotate(seg->a, rot));+ seg->tb = cpvadd(p, cpvrotate(seg->b, rot));+ seg->tn = cpvrotate(seg->n, rot);+ + cpFloat l,r,s,t;+ + if(seg->ta.x < seg->tb.x){+ l = seg->ta.x;+ r = seg->tb.x;+ } else {+ l = seg->tb.x;+ r = seg->ta.x;+ }+ + if(seg->ta.y < seg->tb.y){+ s = seg->ta.y;+ t = seg->tb.y;+ } else {+ s = seg->tb.y;+ t = seg->ta.y;+ }+ + cpFloat rad = seg->r;+ return cpBBNew(l - rad, s - rad, r + rad, t + rad);+}++static int+cpSegmentShapePointQuery(cpShape *shape, cpVect p){+ if(!cpBBcontainsVect(shape->bb, p)) return 0;+ + cpSegmentShape *seg = (cpSegmentShape *)shape;+ + // Calculate normal distance from segment.+ cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);+ cpFloat dist = cpfabs(dn) - seg->r;+ if(dist > 0.0f) return 0;+ + // Calculate tangential distance along segment.+ cpFloat dt = -cpvcross(seg->tn, p);+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);+ + // Decision tree to decide which feature of the segment to collide with.+ if(dt <= dtMin){+ if(dt < (dtMin - seg->r)){+ return 0;+ } else {+ return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);+ }+ } else {+ if(dt < dtMax){+ return 1;+ } else {+ if(dt < (dtMax + seg->r)) {+ return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);+ } else {+ return 0;+ }+ }+ }+ + return 1; +}++static void+cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)+{+ cpSegmentShape *seg = (cpSegmentShape *)shape;+ cpVect n = seg->tn;+ // flip n if a is behind the axis+ if(cpvdot(a, n) < cpvdot(seg->ta, n))+ n = cpvneg(n);+ + cpFloat an = cpvdot(a, n);+ cpFloat bn = cpvdot(b, n);+ cpFloat d = cpvdot(seg->ta, n) + seg->r;+ + cpFloat t = (d - an)/(bn - an);+ if(0.0f < t && t < 1.0f){+ cpVect point = cpvlerp(a, b, t);+ cpFloat dt = -cpvcross(seg->tn, point);+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);+ + if(dtMin < dt && dt < dtMax){+ info->shape = shape;+ info->t = t;+ info->n = n;+ + return; // don't continue on and check endcaps+ }+ }+ + if(seg->r) {+ cpSegmentQueryInfo info1 = {.shape = NULL};+ cpSegmentQueryInfo info2 = {.shape = NULL};+ circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1);+ circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2);+ + if(info1.shape && !info2.shape){+ (*info) = info1;+ } else if(info2.shape && !info1.shape){+ (*info) = info2;+ } else if(info1.shape && info2.shape){+ if(info1.t < info2.t){+ (*info) = info1;+ } else {+ (*info) = info2;+ }+ }+ }+}++static const cpShapeClass cpSegmentShapeClass = {+ CP_SEGMENT_SHAPE,+ cpSegmentShapeCacheData,+ NULL,+ cpSegmentShapePointQuery,+ cpSegmentShapeSegmentQuery,+};++cpSegmentShape *+cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r)+{+ seg->a = a;+ seg->b = b;+ seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));+ + seg->r = r;+ + cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body);+ + return seg;+}++cpShape*+cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r)+{+ return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r);+}++CP_DefineShapeGetter(cpSegmentShape, cpVect, a, A)+CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B)+CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal)+CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius)++// Unsafe API (chipmunk_unsafe.h)++void+cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)+{+ assert(shape->klass == &cpCircleShapeClass);+ cpCircleShape *circle = (cpCircleShape *)shape;+ + circle->r = radius;+}++void+cpCircleShapeSetOffset(cpShape *shape, cpVect offset)+{+ assert(shape->klass == &cpCircleShapeClass);+ cpCircleShape *circle = (cpCircleShape *)shape;+ + circle->c = offset;+}++void+cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)+{+ assert(shape->klass == &cpSegmentShapeClass);+ cpSegmentShape *seg = (cpSegmentShape *)shape;+ + seg->a = a;+ seg->b = b;+ seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));+}++void+cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius)+{+ assert(shape->klass == &cpSegmentShapeClass);+ cpSegmentShape *seg = (cpSegmentShape *)shape;+ + seg->r = radius;+}
+ chipmunk-5.0/cpShape.h view
@@ -0,0 +1,155 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +// Forward declarations required for defining other structs.+struct cpShape;+struct cpShapeClass;++typedef struct cpSegmentQueryInfo{+ struct cpShape *shape; // shape that was hit, NULL if no collision+ cpFloat t; // line(t) = a + (b - a)t, will always be in the range [0, 1]+ cpVect n; // normal of hit surface+} cpSegmentQueryInfo;++// For determinism, you can reset the shape id counter.+void cpResetShapeIdCounter(void);++// Enumeration of shape types.+typedef enum cpShapeType{+ CP_CIRCLE_SHAPE,+ CP_SEGMENT_SHAPE,+ CP_POLY_SHAPE,+ CP_NUM_SHAPES+} cpShapeType;++// Shape class. Holds function pointers and type data.+typedef struct cpShapeClass {+ cpShapeType type;+ + // Called by cpShapeCacheBB().+ cpBB (*cacheData)(struct cpShape *shape, cpVect p, cpVect rot);+ // Called to by cpShapeDestroy().+ void (*destroy)(struct cpShape *shape);+ + // called by cpShapePointQuery().+ int (*pointQuery)(struct cpShape *shape, cpVect p);+ + // called by cpShapeSegmentQuery()+ void (*segmentQuery)(struct cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);+} cpShapeClass;++// Basic shape struct that the others inherit from.+typedef struct cpShape{+ // The "class" of a shape as defined above + const cpShapeClass *klass;+ + // cpBody that the shape is attached to.+ cpBody *body;++ // Cached BBox for the shape.+ cpBB bb;+ + // *** Surface properties.+ + // Coefficient of restitution. (elasticity)+ cpFloat e;+ // Coefficient of friction.+ cpFloat u;+ // Surface velocity used when solving for friction.+ cpVect surface_v;++ // *** User Definable Fields++ // User defined data pointer for the shape.+ void *data;+ + // User defined collision type for the shape.+ cpCollisionType collision_type;+ // User defined collision group for the shape.+ cpGroup group;+ // User defined layer bitmask for the shape.+ cpLayers layers;+ + // *** Internally Used Fields+ + // Unique id used as the hash value.+ cpHashValue id;+} cpShape;++// Low level shape initialization func.+cpShape* cpShapeInit(cpShape *shape, const struct cpShapeClass *klass, cpBody *body);++// Basic destructor functions. (allocation functions are not shared)+void cpShapeDestroy(cpShape *shape);+void cpShapeFree(cpShape *shape);++// Cache the BBox of the shape.+cpBB cpShapeCacheBB(cpShape *shape);++// Test if a point lies within a shape.+int cpShapePointQuery(cpShape *shape, cpVect p, cpLayers layers, cpGroup group);+void cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info);++#define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(cpShape *shape)++// Circle shape structure.+typedef struct cpCircleShape{+ cpShape shape;+ + // Center in body space coordinates+ cpVect c;+ // Radius.+ cpFloat r;+ + // Transformed center. (world space coordinates)+ cpVect tc;+} cpCircleShape;++// Basic allocation functions for cpCircleShape.+cpCircleShape *cpCircleShapeAlloc(void);+cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);+cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);++CP_DeclareShapeGetter(cpCircleShape, cpVect, Offset);+CP_DeclareShapeGetter(cpCircleShape, cpFloat, Radius);++// Segment shape structure.+typedef struct cpSegmentShape{+ cpShape shape;+ + // Endpoints and normal of the segment. (body space coordinates)+ cpVect a, b, n;+ // Radius of the segment. (Thickness)+ cpFloat r;++ // Transformed endpoints and normal. (world space coordinates)+ cpVect ta, tb, tn;+} cpSegmentShape;++// Basic allocation functions for cpSegmentShape.+cpSegmentShape* cpSegmentShapeAlloc(void);+cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius);+cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius);++CP_DeclareShapeGetter(cpSegmentShape, cpVect, A);+CP_DeclareShapeGetter(cpSegmentShape, cpVect, B);+CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal);+CP_DeclareShapeGetter(cpSegmentShape, cpFloat, Radius);
+ chipmunk-5.0/cpSpace.c view
@@ -0,0 +1,571 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdlib.h>+#include <stdio.h>+#include <string.h>+#include <math.h>+#include <assert.h>++#include "chipmunk.h"++int cp_contact_persistence = 3;++#pragma mark Contact Set Helpers++// Equal function for contactSet.+static int+contactSetEql(cpShape **shapes, cpArbiter *arb)+{+ cpShape *a = shapes[0];+ cpShape *b = shapes[1];+ + return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));+}++// Transformation function for contactSet.+static void *+contactSetTrans(cpShape **shapes, cpSpace *space)+{+ cpShape *a = shapes[0];+ cpShape *b = shapes[1];+ + return cpArbiterNew(a, b, space->stamp);+}++#pragma mark Collision Pair Function Helpers++// Collision pair function wrapper struct.+typedef struct collFuncData {+ cpCollFunc func;+ void *data;+} collFuncData;++// Equals function for collFuncSet.+static int+collFuncSetEql(cpCollisionType *ids, cpCollPairFunc *pair)+{+ cpCollisionType a = ids[0];+ cpCollisionType b = ids[1];+ + return ((a == pair->a && b == pair->b) || (b == pair->a && a == pair->b));+}++// Transformation function for collFuncSet.+static void *+collFuncSetTrans(cpCollisionType *ids, collFuncData *funcData)+{+ cpCollPairFunc *pair = (cpCollPairFunc *)malloc(sizeof(cpCollPairFunc));+ pair->a = ids[0];+ pair->b = ids[1];+ pair->func = funcData->func;+ pair->data = funcData->data;++ return pair;+}++#pragma mark Misc Helper Funcs++// Default collision pair function.+static int+alwaysCollide(cpShape *a, cpShape *b, cpContact *arr, int numCon, cpFloat normal_coef, void *data)+{+ return 1;+}++// BBfunc callback for the spatial hash.+static cpBB shapeBBFunc(cpShape *shape){return shape->bb;}++// Iterator functions for destructors.+static void freeWrap(void *ptr, void *unused){ free(ptr);}+static void shapeFreeWrap(cpShape *ptr, void *unused){ cpShapeFree(ptr);}+static void arbiterFreeWrap(cpArbiter *ptr, void *unused){ cpArbiterFree(ptr);}+static void bodyFreeWrap(cpBody *ptr, void *unused){ cpBodyFree(ptr);}+static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFree(ptr);}++#pragma mark Memory Management Functions++cpSpace*+cpSpaceAlloc(void)+{+ return (cpSpace *)calloc(1, sizeof(cpSpace));+}++#define DEFAULT_DIM_SIZE 100.0f+#define DEFAULT_COUNT 1000+#define DEFAULT_ITERATIONS 10+#define DEFAULT_ELASTIC_ITERATIONS 0++cpSpace*+cpSpaceInit(cpSpace *space)+{+ space->iterations = DEFAULT_ITERATIONS;+ space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;+// space->sleepTicks = 300;+ + space->gravity = cpvzero;+ space->damping = 1.0f;+ + space->stamp = 0;++ space->staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);+ space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);+ + space->bodies = cpArrayNew(0);+ space->arbiters = cpArrayNew(0);+ space->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);+ + space->constraints = cpArrayNew(0);+ + cpCollPairFunc pairFunc = {0, 0, alwaysCollide, NULL};+ space->defaultPairFunc = pairFunc;+ space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);+ space->collFuncSet->default_value = &space->defaultPairFunc;+ + return space;+}++cpSpace*+cpSpaceNew(void)+{+ return cpSpaceInit(cpSpaceAlloc());+}++void+cpSpaceDestroy(cpSpace *space)+{+ cpSpaceHashFree(space->staticShapes);+ cpSpaceHashFree(space->activeShapes);+ + cpArrayFree(space->bodies);+ + cpArrayFree(space->constraints);+ + if(space->contactSet)+ cpHashSetEach(space->contactSet, (cpHashSetIterFunc)&arbiterFreeWrap, NULL);+ + cpHashSetFree(space->contactSet);+ cpArrayFree(space->arbiters);+ + if(space->collFuncSet)+ cpHashSetEach(space->collFuncSet, &freeWrap, NULL);+ cpHashSetFree(space->collFuncSet);+}++void+cpSpaceFree(cpSpace *space)+{+ if(space) cpSpaceDestroy(space);+ free(space);+}++void+cpSpaceFreeChildren(cpSpace *space)+{+ cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);+ cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);+ cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL);+ cpArrayEach(space->constraints, (cpArrayIter)&constraintFreeWrap, NULL);+}++#pragma mark Collision Pair Function Management++void+cpSpaceAddCollisionPairFunc(cpSpace *space, cpCollisionType a, cpCollisionType b, cpCollFunc func, void *data)+{+ cpCollisionType ids[] = {a, b};+ cpHashValue hash = CP_HASH_PAIR(a, b);+ // Remove any old function so the new one will get added.+ cpSpaceRemoveCollisionPairFunc(space, a, b);+ + collFuncData funcData = {func, data};+ cpHashSetInsert(space->collFuncSet, hash, ids, &funcData);+}++void+cpSpaceRemoveCollisionPairFunc(cpSpace *space, cpCollisionType a, cpCollisionType b)+{+ cpCollisionType ids[] = {a, b};+ cpHashValue hash = CP_HASH_PAIR(a, b);+ cpCollPairFunc *old_pair = (cpCollPairFunc *)cpHashSetRemove(space->collFuncSet, hash, ids);+ free(old_pair);+}++void+cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data)+{+ cpCollPairFunc pairFunc = {0, 0, (func ? func : alwaysCollide), (func ? data : NULL)};+ space->defaultPairFunc = pairFunc;+}++#pragma mark Body, Shape, and Joint Management++cpShape *+cpSpaceAddShape(cpSpace *space, cpShape *shape)+{+ assert(shape->body);+ cpSpaceHashInsert(space->activeShapes, shape, shape->id, shape->bb);+ + return shape;+}++cpShape *+cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)+{+ assert(shape->body);++ cpShapeCacheBB(shape);+ cpSpaceHashInsert(space->staticShapes, shape, shape->id, shape->bb);+ + return shape;+}++cpBody *+cpSpaceAddBody(cpSpace *space, cpBody *body)+{+ cpArrayPush(space->bodies, body);+ + return body;+}++cpConstraint *+cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)+{+ cpArrayPush(space->constraints, constraint);+ + return constraint;+}++static void+shapeRemovalArbiterReject(cpSpace *space, cpShape *shape)+{+ cpArray *old_ary = space->arbiters;+ int num = old_ary->num;+ + if(num == 0) return;+ + // make a new arbiters array and copy over all valid arbiters+ cpArray *new_ary = cpArrayNew(num);+ + for(int i=0; i<num; i++){+ cpArbiter *arb = (cpArbiter *)old_ary->arr[i];+ if(arb->a != shape && arb->b != shape){+ cpArrayPush(new_ary, arb);+ }+ }+ + space->arbiters = new_ary;+ cpArrayFree(old_ary);+}++void+cpSpaceRemoveShape(cpSpace *space, cpShape *shape)+{+ cpSpaceHashRemove(space->activeShapes, shape, shape->id);+ shapeRemovalArbiterReject(space, shape);+}++void+cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)+{+ cpSpaceHashRemove(space->staticShapes, shape, shape->id);+ shapeRemovalArbiterReject(space, shape);+}++void+cpSpaceRemoveBody(cpSpace *space, cpBody *body)+{+ cpArrayDeleteObj(space->bodies, body);+}++void+cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)+{+ cpArrayDeleteObj(space->constraints, constraint);+}++#pragma mark Point Query Functions++typedef struct pointQueryContext {+ cpLayers layers;+ cpGroup group;+ cpSpacePointQueryFunc func;+ void *data;+} pointQueryContext;++static void +pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)+{+ if(cpShapePointQuery(shape, *point, context->layers, context->group))+ context->func(shape, context->data);+}++void+cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)+{+ pointQueryContext context = {layers, group, func, data};+ cpSpaceHashPointQuery(space->activeShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);+ cpSpaceHashPointQuery(space->staticShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);+}++static void+rememberLastPointQuery(cpShape *shape, cpShape **outShape)+{+ (*outShape) = shape;+}++cpShape *+cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)+{+ cpShape *shape = NULL;+ cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)rememberLastPointQuery, &shape);+ + return shape;+}++void+cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)+{+ cpArray *bodies = space->bodies;+ + for(int i=0; i<bodies->num; i++)+ func((cpBody *)bodies->arr[i], data);+}++#pragma mark Spatial Hash Management++// Iterator function used for updating shape BBoxes.+static void+updateBBCache(cpShape *shape, void *unused)+{+ cpShapeCacheBB(shape);+}++void+cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)+{+ cpSpaceHashResize(space->staticShapes, dim, count);+ cpSpaceHashRehash(space->staticShapes);+}++void+cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)+{+ cpSpaceHashResize(space->activeShapes, dim, count);+}++void +cpSpaceRehashStatic(cpSpace *space)+{+ cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&updateBBCache, NULL);+ cpSpaceHashRehash(space->staticShapes);+}++#pragma mark Collision Detection Functions++static inline int+queryReject(cpShape *a, cpShape *b)+{+ return+ // BBoxes must overlap+ !cpBBintersects(a->bb, b->bb)+ // Don't collide shapes attached to the same body.+ || a->body == b->body+ // Don't collide objects in the same non-zero group+ || (a->group && b->group && a->group == b->group)+ // Don't collide objects that don't share at least on layer.+ || !(a->layers & b->layers);+}++// Callback from the spatial hash.+static void+queryFunc(cpShape *a, cpShape *b, cpSpace *space)+{+ // Reject any of the simple cases+ if(queryReject(a,b)) return;+ + // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )+ if(a->klass->type > b->klass->type){+ cpShape *temp = a;+ a = b;+ b = temp;+ }+ + // Narrow-phase collision detection.+ cpContact *contacts = NULL;+ int numContacts = cpCollideShapes(a, b, &contacts);+ if(!numContacts) return; // Shapes are not colliding.+ + // Get an arbiter from space->contactSet for the two shapes.+ // This is where the persistant contact magic comes from.+ cpShape *shape_pair[] = {a, b};+ cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->contactSet, CP_HASH_PAIR(a, b), shape_pair, space);+ + // Timestamp the arbiter.+ arb->stamp = space->stamp;+ // For collisions between two similar primitive types, the order could have been swapped.+ arb->a = a; arb->b = b;+ // Inject the new contact points into the arbiter.+ cpArbiterInject(arb, contacts, numContacts);+ + // Add the arbiter to the list of active arbiters.+ cpArrayPush(space->arbiters, arb);+}++// Iterator for active/static hash collisions.+static void+active2staticIter(cpShape *shape, cpSpace *space)+{+ cpSpaceHashQuery(space->staticShapes, shape, shape->bb, (cpSpaceHashQueryFunc)&queryFunc, space);+}++// Hashset reject func to throw away old arbiters.+static int+contactSetReject(cpArbiter *arb, cpSpace *space)+{+ if((space->stamp - arb->stamp) > cp_contact_persistence){+ cpArbiterFree(arb);+ return 0;+ }+ + return 1;+}++static void+filterArbiterByCallback(cpSpace *space)+{+ int num = space->arbiters->num;+ + // copy to the stack+ cpArbiter *ary[num];+ memcpy(ary, space->arbiters->arr, num*sizeof(void *));+ + for(int i=0; i<num; i++){+ cpArbiter *arb = ary[i];+ + // The collision pair function requires objects to be ordered by their collision types.+ cpShape *a = arb->a;+ cpShape *b = arb->b;+ cpFloat normal_coef = 1.0f;+ + // Find the collision pair function for the shapes.+ cpCollisionType ids[] = {a->collision_type, b->collision_type};+ cpHashValue hash = CP_HASH_PAIR(a->collision_type, b->collision_type);+ cpCollPairFunc *pairFunc = (cpCollPairFunc *)cpHashSetFind(space->collFuncSet, hash, ids);+ if(!pairFunc->func) continue; // A NULL pair function means don't collide at all.+ + // Swap them if necessary.+ if(a->collision_type != pairFunc->a){+ cpShape *temp = a;+ a = b;+ b = temp;+ normal_coef = -1.0f;+ }+ + if(!pairFunc->func(a, b, arb->contacts, arb->numContacts, normal_coef, pairFunc->data)){+ cpArrayDeleteObj(space->arbiters, arb);+ }+ }+}++#pragma mark All Important cpSpaceStep() Function++void+cpSpaceStep(cpSpace *space, cpFloat dt)+{+ if(!dt) return; // prevents div by zero.+ cpFloat dt_inv = 1.0f/dt;++ cpArray *bodies = space->bodies;+ cpArray *constraints = space->constraints;+ + // Empty the arbiter list.+ cpHashSetReject(space->contactSet, (cpHashSetRejectFunc)&contactSetReject, space);+ space->arbiters->num = 0;++ // Integrate positions.+ for(int i=0; i<bodies->num; i++){+ cpBody *body = (cpBody *)bodies->arr[i];+ body->position_func(body, dt);+ }+ + // Pre-cache BBoxes and shape data.+ cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&updateBBCache, NULL);+ + // Collide!+ cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&active2staticIter, space);+ cpSpaceHashQueryRehash(space->activeShapes, (cpSpaceHashQueryFunc)&queryFunc, space);+ + // Filter arbiter list based on collision callbacks+ filterArbiterByCallback(space);++ // Prestep the arbiters.+ cpArray *arbiters = space->arbiters;+ for(int i=0; i<arbiters->num; i++)+ cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt_inv);++ // Prestep the constraints.+ for(int i=0; i<constraints->num; i++){+ cpConstraint *constraint = (cpConstraint *)constraints->arr[i];+ constraint->klass->preStep(constraint, dt, dt_inv);+ }++ for(int i=0; i<space->elasticIterations; i++){+ for(int j=0; j<arbiters->num; j++)+ cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 1.0f);+ + for(int j=0; j<constraints->num; j++){+ cpConstraint *constraint = (cpConstraint *)constraints->arr[j];+ constraint->klass->applyImpulse(constraint);+ }+ }++ // Integrate velocities.+ cpFloat damping = cpfpow(1.0f/space->damping, -dt);+ for(int i=0; i<bodies->num; i++){+ cpBody *body = (cpBody *)bodies->arr[i];+ body->velocity_func(body, space->gravity, damping, dt);+ }++ for(int i=0; i<arbiters->num; i++)+ cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i]);+ + // Run the impulse solver.+ // run the old-style elastic solver if elastic iterations are disabled+ cpFloat elasticCoef = (space->elasticIterations ? 0.0f : 1.0f);+ for(int i=0; i<space->iterations; i++){+ for(int j=0; j<arbiters->num; j++)+ cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], elasticCoef);+ + for(int j=0; j<constraints->num; j++){+ cpConstraint *constraint = (cpConstraint *)constraints->arr[j];+ constraint->klass->applyImpulse(constraint);+ }+ }++// cpFloat dvsq = cpvdot(space->gravity, space->gravity);+// dvsq *= dt*dt * space->damping*space->damping;+// for(int i=0; i<bodies->num; i++)+// cpBodyMarkLowEnergy(bodies->arr[i], dvsq, space->sleepTicks);+ + // Increment the stamp.+ space->stamp++;+}
+ chipmunk-5.0/cpSpace.h view
@@ -0,0 +1,120 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +// Number of frames that contact information should persist.+extern int cp_contact_persistence;++// User collision pair function.+typedef int (*cpCollFunc)(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data);++// Structure for holding collision pair function information.+// Used internally.+typedef struct cpCollPairFunc {+ cpCollisionType a;+ cpCollisionType b;+ cpCollFunc func;+ void *data;+} cpCollPairFunc;++typedef struct cpSpace{+ // *** User definable fields+ + // Number of iterations to use in the impulse solver to solve contacts.+ int iterations;+ + // Number of iterations to use in the impulse solver to solve elastic collisions.+ int elasticIterations;+ + // Default gravity to supply when integrating rigid body motions.+ cpVect gravity;+ + // Default damping to supply when integrating rigid body motions.+ cpFloat damping;+ + // *** Internally Used Fields+ + // Time stamp. Is incremented on every call to cpSpaceStep().+ int stamp;++ // The static and active shape spatial hashes.+ cpSpaceHash *staticShapes;+ cpSpaceHash *activeShapes;+ + // List of bodies in the system.+ cpArray *bodies;+ // List of active arbiters for the impulse solver.+ cpArray *arbiters;+ // Persistant contact set.+ cpHashSet *contactSet;+ + // List of constraints in the system.+ cpArray *constraints;+ + // Set of collisionpair functions.+ cpHashSet *collFuncSet;+ // Default collision pair function.+ cpCollPairFunc defaultPairFunc;+} cpSpace;++// Basic allocation/destruction functions.+cpSpace* cpSpaceAlloc(void);+cpSpace* cpSpaceInit(cpSpace *space);+cpSpace* cpSpaceNew(void);++void cpSpaceDestroy(cpSpace *space);+void cpSpaceFree(cpSpace *space);++// Convenience function. Frees all referenced entities. (bodies, shapes and constraints)+void cpSpaceFreeChildren(cpSpace *space);++// Collision pair function management functions.+void cpSpaceAddCollisionPairFunc(cpSpace *space, cpCollisionType a, cpCollisionType b,+ cpCollFunc func, void *data);+void cpSpaceRemoveCollisionPairFunc(cpSpace *space, cpCollisionType a, cpCollisionType b);+void cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data);++// Add and remove entities from the system.+cpShape *cpSpaceAddShape(cpSpace *space, cpShape *shape);+cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);+cpBody *cpSpaceAddBody(cpSpace *space, cpBody *body);+cpConstraint *cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);++void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);+void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);+void cpSpaceRemoveBody(cpSpace *space, cpBody *body);+void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint);++// Point query callback function+typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);+void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data);+cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group);++// Iterator function for iterating the bodies in a space.+typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);+void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);++// Spatial hash management functions.+void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);+void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);+void cpSpaceRehashStatic(cpSpace *space);++// Update the space.+void cpSpaceStep(cpSpace *space, cpFloat dt);
+ chipmunk-5.0/cpSpaceHash.c view
@@ -0,0 +1,460 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include <math.h>+#include <stdlib.h>+#include <stdio.h>+#include <assert.h>++#include "chipmunk.h"+#include "prime.h"++static cpHandle*+cpHandleAlloc(void)+{+ return (cpHandle *)malloc(sizeof(cpHandle));+}++static cpHandle*+cpHandleInit(cpHandle *hand, void *obj)+{+ hand->obj = obj;+ hand->retain = 0;+ hand->stamp = 0;+ + return hand;+}++static cpHandle*+cpHandleNew(void *obj)+{+ return cpHandleInit(cpHandleAlloc(), obj);+}++static inline void+cpHandleRetain(cpHandle *hand)+{+ hand->retain++;+}++static inline void+cpHandleFree(cpHandle *hand)+{+ free(hand);+}++static inline void+cpHandleRelease(cpHandle *hand)+{+ hand->retain--;+ if(hand->retain == 0)+ cpHandleFree(hand);+}+++cpSpaceHash*+cpSpaceHashAlloc(void)+{+ return (cpSpaceHash *)calloc(1, sizeof(cpSpaceHash));+}++// Frees the old table, and allocates a new one.+static void+cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)+{+ free(hash->table);+ + hash->numcells = numcells;+ hash->table = (cpSpaceHashBin **)calloc(numcells, sizeof(cpSpaceHashBin *));+}++// Equality function for the handleset.+static int+handleSetEql(void *obj, void *elt)+{+ cpHandle *hand = (cpHandle *)elt;+ return (obj == hand->obj);+}++// Transformation function for the handleset.+static void *+handleSetTrans(void *obj, void *unused)+{+ cpHandle *hand = cpHandleNew(obj);+ cpHandleRetain(hand);+ + return hand;+}++cpSpaceHash*+cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBFunc bbfunc)+{+ cpSpaceHashAllocTable(hash, next_prime(numcells));+ hash->celldim = celldim;+ hash->bbfunc = bbfunc;+ + hash->bins = NULL;+ hash->handleSet = cpHashSetNew(0, &handleSetEql, &handleSetTrans);+ + hash->stamp = 1;+ + return hash;+}++cpSpaceHash*+cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc)+{+ return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc);+}++static inline void+clearHashCell(cpSpaceHash *hash, int index)+{+ cpSpaceHashBin *bin = hash->table[index];+ while(bin){+ cpSpaceHashBin *next = bin->next;+ + // Release the lock on the handle.+ cpHandleRelease(bin->handle);+ // Recycle the bin.+ bin->next = hash->bins;+ hash->bins = bin;+ + bin = next;+ }+ + hash->table[index] = NULL;+}++// Clear all cells in the hashtable.+static void+clearHash(cpSpaceHash *hash)+{+ for(int i=0; i<hash->numcells; i++)+ clearHashCell(hash, i);+}++// Free the recycled hash bins.+static void+freeBins(cpSpaceHash *hash)+{+ cpSpaceHashBin *bin = hash->bins;+ while(bin){+ cpSpaceHashBin *next = bin->next;+ free(bin);+ bin = next;+ }+}++// Hashset iterator function to free the handles.+static void+handleFreeWrap(void *elt, void *unused)+{+ cpHandle *hand = (cpHandle *)elt;+ cpHandleFree(hand);+}++void+cpSpaceHashDestroy(cpSpaceHash *hash)+{+ clearHash(hash);+ freeBins(hash);+ + // Free the handles.+ cpHashSetEach(hash->handleSet, &handleFreeWrap, NULL);+ cpHashSetFree(hash->handleSet);+ + free(hash->table);+}++void+cpSpaceHashFree(cpSpaceHash *hash)+{+ if(!hash) return;+ cpSpaceHashDestroy(hash);+ free(hash);+}++void+cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)+{+ // Clear the hash to release the old handle locks.+ clearHash(hash);+ + hash->celldim = celldim;+ cpSpaceHashAllocTable(hash, next_prime(numcells));+}++// Return true if the chain contains the handle.+static inline int+containsHandle(cpSpaceHashBin *bin, cpHandle *hand)+{+ while(bin){+ if(bin->handle == hand) return 1;+ bin = bin->next;+ }+ + return 0;+}++// Get a recycled or new bin.+static inline cpSpaceHashBin *+getEmptyBin(cpSpaceHash *hash)+{+ cpSpaceHashBin *bin = hash->bins;+ + // Make a new one if necessary.+ if(bin == NULL) return (cpSpaceHashBin *)malloc(sizeof(cpSpaceHashBin));++ hash->bins = bin->next;+ return bin;+}++// The hash function itself.+static inline cpHashValue+hash_func(cpHashValue x, cpHashValue y, cpHashValue n)+{+ return (x*2185031351ul ^ y*4232417593ul) % n;+}++static inline void+hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)+{+ // Find the dimensions in cell coordinates.+ cpFloat dim = hash->celldim;+ int l = bb.l/dim;+ int r = bb.r/dim;+ int b = bb.b/dim;+ int t = bb.t/dim;+ + int n = hash->numcells;+ for(int i=l; i<=r; i++){+ for(int j=b; j<=t; j++){+ int index = hash_func(i,j,n);+ cpSpaceHashBin *bin = hash->table[index];+ + // Don't add an object twice to the same cell.+ if(containsHandle(bin, hand)) continue;++ cpHandleRetain(hand);+ // Insert a new bin for the handle in this cell.+ cpSpaceHashBin *newBin = getEmptyBin(hash);+ newBin->handle = hand;+ newBin->next = bin;+ hash->table[index] = newBin;+ }+ }+}++void+cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB bb)+{+ cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, id, obj, NULL);+ hashHandle(hash, hand, bb);+}++void+cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue id)+{+ cpHandle *hand = (cpHandle *)cpHashSetFind(hash->handleSet, id, obj);+ hashHandle(hash, hand, hash->bbfunc(obj));+}++// Hashset iterator function for rehashing the spatial hash. (hash hash hash hash?)+static void+handleRehashHelper(void *elt, void *data)+{+ cpHandle *hand = (cpHandle *)elt;+ cpSpaceHash *hash = (cpSpaceHash *)data;+ + hashHandle(hash, hand, hash->bbfunc(hand->obj));+}++void+cpSpaceHashRehash(cpSpaceHash *hash)+{+ clearHash(hash);+ + // Rehash all of the handles.+ cpHashSetEach(hash->handleSet, &handleRehashHelper, hash);+}++void+cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue id)+{+ cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, id, obj);+ + if(hand){+ hand->obj = NULL;+ cpHandleRelease(hand);+ }+}++// Used by the cpSpaceHashEach() iterator.+typedef struct eachPair {+ cpSpaceHashIterator func;+ void *data;+} eachPair;++// Calls the user iterator function. (Gross I know.)+static void+eachHelper(void *elt, void *data)+{+ cpHandle *hand = (cpHandle *)elt;+ eachPair *pair = (eachPair *)data;+ + pair->func(hand->obj, pair->data);+}++// Iterate over the objects in the spatial hash.+void+cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)+{+ // Bundle the callback up to send to the hashset iterator.+ eachPair pair = {func, data};+ + cpHashSetEach(hash->handleSet, &eachHelper, &pair);+}++// Calls the callback function for the objects in a given chain.+static inline void+query(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashQueryFunc func, void *data)+{+ for(; bin; bin = bin->next){+ cpHandle *hand = bin->handle;+ void *other = hand->obj;+ + // Skip over certain conditions+ if(+ // Have we already tried this pair in this query?+ hand->stamp == hash->stamp+ // Is obj the same as other?+ || obj == other + // Has other been removed since the last rehash?+ || !other+ ) continue;+ + func(obj, other, data);++ // Stamp that the handle was checked already against this object.+ hand->stamp = hash->stamp;+ }+}++void+cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data)+{+ cpFloat dim = hash->celldim;+ int index = hash_func((int)(point.x/dim), (int)(point.y/dim), hash->numcells);+ + query(hash, hash->table[index], &point, func, data);++ // Increment the stamp.+ // Only one cell is checked, but query() requires it anyway.+ hash->stamp++;+}++void+cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data)+{+ // Get the dimensions in cell coordinates.+ cpFloat dim = hash->celldim;+ int l = bb.l/dim;+ int r = bb.r/dim;+ int b = bb.b/dim;+ int t = bb.t/dim;+ + int n = hash->numcells;+ + // Iterate over the cells and query them.+ for(int i=l; i<=r; i++){+ for(int j=b; j<=t; j++){+ int index = hash_func(i,j,n);+ query(hash, hash->table[index], obj, func, data);+ }+ }+ + // Increment the stamp.+ hash->stamp++;+}++// Similar to struct eachPair above.+typedef struct queryRehashPair {+ cpSpaceHash *hash;+ cpSpaceHashQueryFunc func;+ void *data;+} queryRehashPair;++// Hashset iterator func used with cpSpaceHashQueryRehash().+static void+handleQueryRehashHelper(void *elt, void *data)+{+ cpHandle *hand = (cpHandle *)elt;+ + // Unpack the user callback data.+ queryRehashPair *pair = (queryRehashPair *)data;+ cpSpaceHash *hash = pair->hash;+ cpSpaceHashQueryFunc func = pair->func;++ cpFloat dim = hash->celldim;+ int n = hash->numcells;++ void *obj = hand->obj;+ cpBB bb = hash->bbfunc(obj);++ int l = bb.l/dim;+ int r = bb.r/dim;+ int b = bb.b/dim;+ int t = bb.t/dim;++ for(int i=l; i<=r; i++){+ for(int j=b; j<=t; j++){+// // exit the loops if the object has been deleted in func().+// if(!hand->obj) goto break_out;+ + int index = hash_func(i,j,n);+ cpSpaceHashBin *bin = hash->table[index];+ + if(containsHandle(bin, hand)) continue;+ + cpHandleRetain(hand); // this MUST be done first in case the object is removed in func()+ query(hash, bin, obj, func, pair->data);+ + cpSpaceHashBin *newBin = getEmptyBin(hash);+ newBin->handle = hand;+ newBin->next = bin;+ hash->table[index] = newBin;+ }+ }+ +// break_out:+ // Increment the stamp for each object we hash.+ hash->stamp++;+}++void+cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)+{+ clearHash(hash);+ + queryRehashPair pair = {hash, func, data};+ cpHashSetEach(hash->handleSet, &handleQueryRehashHelper, &pair);+}
+ chipmunk-5.0/cpSpaceHash.h view
@@ -0,0 +1,100 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++// The spatial hash is Chipmunk's default (and currently only) spatial index type.+// Based on a chained hash table.++// Used internally to track objects added to the hash+typedef struct cpHandle{+ // Pointer to the object+ void *obj;+ // Retain count+ int retain;+ // Query stamp. Used to make sure two objects+ // aren't identified twice in the same query.+ int stamp;+} cpHandle;++// Linked list element for in the chains.+typedef struct cpSpaceHashBin{+ cpHandle *handle;+ struct cpSpaceHashBin *next;+} cpSpaceHashBin;++// BBox callback. Called whenever the hash needs a bounding box from an object.+typedef cpBB (*cpSpaceHashBBFunc)(void *obj);++typedef struct cpSpaceHash{+ // Number of cells in the table.+ int numcells;+ // Dimentions of the cells.+ cpFloat celldim;+ + // BBox callback.+ cpSpaceHashBBFunc bbfunc;++ // Hashset of all the handles.+ cpHashSet *handleSet;+ + cpSpaceHashBin **table;+ // List of recycled bins.+ cpSpaceHashBin *bins;++ // Incremented on each query. See cpHandle.stamp.+ int stamp;+} cpSpaceHash;++//Basic allocation/destruction functions.+cpSpaceHash *cpSpaceHashAlloc(void);+cpSpaceHash *cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);+cpSpaceHash *cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);++void cpSpaceHashDestroy(cpSpaceHash *hash);+void cpSpaceHashFree(cpSpaceHash *hash);++// Resize the hashtable. (Does not rehash! You must call cpSpaceHashRehash() if needed.)+void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);++// Add an object to the hash.+void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB bb);+// Remove an object from the hash.+void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue id);++// Iterator function+typedef void (*cpSpaceHashIterator)(void *obj, void *data);+// Iterate over the objects in the hash.+void cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data);++// Rehash the contents of the hash.+void cpSpaceHashRehash(cpSpaceHash *hash);+// Rehash only a specific object.+void cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue id);++// Query callback.+typedef void (*cpSpaceHashQueryFunc)(void *obj1, void *obj2, void *data);+// Point query the hash. A reference to the query point is passed as obj1 to the query callback.+void cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data);+// Query the hash for a given BBox.+void cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);+// Run a query for the object, then insert it. (Optimized case)+void cpSpaceHashQueryInsert(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);+// Rehashes while querying for each object. (Optimized case) +void cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data);
+ chipmunk-5.0/cpVect.c view
@@ -0,0 +1,51 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <stdio.h>+#include <math.h>++#include "chipmunk.h"++cpFloat+cpvlength(const cpVect v)+{+ return cpfsqrt( cpvdot(v, v) );+}++cpVect+cpvforangle(const cpFloat a)+{+ return cpv(cpfcos(a), cpfsin(a));+}++cpFloat+cpvtoangle(const cpVect v)+{+ return cpfatan2(v.y, v.x);+}++char*+cpvstr(const cpVect v)+{+ static char str[256];+ sprintf(str, "(% .3f, % .3f)", v.x, v.y);+ return str;+}
+ chipmunk-5.0/cpVect.h view
@@ -0,0 +1,153 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +typedef struct cpVect{+ cpFloat x,y;+} cpVect;++static const cpVect cpvzero={0.0f,0.0f};++static inline cpVect+cpv(const cpFloat x, const cpFloat y)+{+ cpVect v = {x, y};+ return v;+}++// non-inlined functions+cpFloat cpvlength(const cpVect v);+cpVect cpvforangle(const cpFloat a); // convert radians to a normalized vector+cpFloat cpvtoangle(const cpVect v); // convert a vector to radians+char *cpvstr(const cpVect v); // get a string representation of a vector++static inline cpVect+cpvadd(const cpVect v1, const cpVect v2)+{+ return cpv(v1.x + v2.x, v1.y + v2.y);+}++static inline cpVect+cpvneg(const cpVect v)+{+ return cpv(-v.x, -v.y);+}++static inline cpVect+cpvsub(const cpVect v1, const cpVect v2)+{+ return cpv(v1.x - v2.x, v1.y - v2.y);+}++static inline cpVect+cpvmult(const cpVect v, const cpFloat s)+{+ return cpv(v.x*s, v.y*s);+}++static inline cpFloat+cpvdot(const cpVect v1, const cpVect v2)+{+ return v1.x*v2.x + v1.y*v2.y;+}++static inline cpFloat+cpvcross(const cpVect v1, const cpVect v2)+{+ return v1.x*v2.y - v1.y*v2.x;+}++static inline cpVect+cpvperp(const cpVect v)+{+ return cpv(-v.y, v.x);+}++static inline cpVect+cpvrperp(const cpVect v)+{+ return cpv(v.y, -v.x);+}++static inline cpVect+cpvproject(const cpVect v1, const cpVect v2)+{+ return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));+}++static inline cpVect+cpvrotate(const cpVect v1, const cpVect v2)+{+ return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);+}++static inline cpVect+cpvunrotate(const cpVect v1, const cpVect v2)+{+ return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);+}++static inline cpFloat+cpvlengthsq(const cpVect v)+{+ return cpvdot(v, v);+}++static inline cpVect+cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)+{+ return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));+}++static inline cpVect+cpvnormalize(const cpVect v)+{+ return cpvmult(v, 1.0f/cpvlength(v));+}++static inline cpVect+cpvnormalize_safe(const cpVect v)+{+ return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v));+}++static inline cpVect+cpvclamp(const cpVect v, const cpFloat len)+{+ return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;+}++static inline cpFloat+cpvdist(const cpVect v1, const cpVect v2)+{+ return cpvlength(cpvsub(v1, v2));+}++static inline cpFloat+cpvdistsq(const cpVect v1, const cpVect v2)+{+ return cpvlengthsq(cpvsub(v1, v2));+}++static inline int+cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)+{+ return cpvdistsq(v1, v2) < dist*dist;+}
+ chipmunk-5.0/prime.h view
@@ -0,0 +1,68 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +// Used for resizing hash tables.+// Values approximately double.++static int primes[] = {+ 5, //2^2 + 1+ 11, //2^3 + 3+ 17, //2^4 + 1+ 37, //2^5 + 5+ 67, //2^6 + 3+ 131, //2^7 + 3+ 257, //2^8 + 1+ 521, //2^9 + 9+ 1031, //2^10 + 7+ 2053, //2^11 + 5+ 4099, //2^12 + 3+ 8209, //2^13 + 17+ 16411, //2^14 + 27+ 32771, //2^15 + 3+ 65537, //2^16 + 1+ 131101, //2^17 + 29+ 262147, //2^18 + 3+ 524309, //2^19 + 21+ 1048583, //2^20 + 7+ 2097169, //2^21 + 17+ 4194319, //2^22 + 15+ 8388617, //2^23 + 9+ 16777259, //2^24 + 43+ 33554467, //2^25 + 35+ 67108879, //2^26 + 15+ 134217757, //2^27 + 29+ 268435459, //2^28 + 3+ 536870923, //2^29 + 11+ 1073741827, //2^30 + 3+ 0,+};++static inline int+next_prime(int n)+{+ int i = 0;+ while(n > primes[i]){+ i++;+ assert(primes[i]); // realistically this should never happen+ }+ + return primes[i];+}
− chipmunk/chipmunk.c
@@ -1,69 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include "stdlib.h"--#include "chipmunk.h"--#ifdef __cplusplus-extern "C" {-#endif- void cpInitCollisionFuncs(void);-#ifdef __cplusplus-}-#endif---void-cpInitChipmunk(void)-{- cpInitCollisionFuncs();-}--cpFloat-cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)-{- return (1.0f/2.0f)*m*(r1*r1 + r2*r2) + m*cpvdot(offset, offset);-}--cpFloat-cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset)-{- cpVect *tVerts = (cpVect *)calloc(numVerts, sizeof(cpVect));- for(int i=0; i<numVerts; i++)- tVerts[i] = cpvadd(verts[i], offset);- - cpFloat sum1 = 0.0f;- cpFloat sum2 = 0.0f;- for(int i=0; i<numVerts; i++){- cpVect v1 = tVerts[i];- cpVect v2 = tVerts[(i+1)%numVerts];- - cpFloat a = cpvcross(v2, v1);- cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2);- - sum1 += a*b;- sum2 += a;- }- - free(tVerts);- return (m*sum1)/(6.0f*sum2);-}
− chipmunk/chipmunk.h
@@ -1,91 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--#ifndef CHIPMUNK_HEADER-#define CHIPMUNK_HEADER--#ifdef __cplusplus-extern "C" {-#endif- -typedef double cpFloat;- -static inline cpFloat-cpfmax(cpFloat a, cpFloat b)-{- return (a > b) ? a : b;-}--static inline cpFloat-cpfmin(cpFloat a, cpFloat b)-{- return (a < b) ? a : b;-}--static inline cpFloat-cpfclamp(cpFloat f, cpFloat min, cpFloat max){- return cpfmin(cpfmax(f, min), max);-}--#ifndef INFINITY- #ifdef _MSC_VER- union MSVC_EVIL_FLOAT_HACK- {- unsigned __int8 Bytes[4];- float Value;- };- static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}};- #define INFINITY (INFINITY_HACK.Value)- #else- #define INFINITY (1e1000)- #endif-#endif--#include "cpVect.h"-#include "cpBB.h"-#include "cpBody.h"-#include "cpArray.h"-#include "cpHashSet.h"-#include "cpSpaceHash.h"--#include "cpShape.h"-#include "cpPolyShape.h"--#include "cpArbiter.h"-#include "cpCollision.h"- -#include "cpJoint.h"--#include "cpSpace.h"--#define CP_HASH_COEF (3344921057ul)-#define CP_HASH_PAIR(A, B) ((unsigned int)(A)*CP_HASH_COEF ^ (unsigned int)(B)*CP_HASH_COEF)--void cpInitChipmunk(void);--cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);-cpFloat cpMomentForPoly(cpFloat m, int numVerts, cpVect *verts, cpVect offset);--#ifdef __cplusplus-}-#endif--#endif
− chipmunk/cpArbiter.c
@@ -1,263 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <math.h>--#include "chipmunk.h"--cpFloat cp_bias_coef = 0.1f;-cpFloat cp_collision_slop = 0.1f;--cpContact*-cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, unsigned int hash)-{- con->p = p;- con->n = n;- con->dist = dist;- - con->jnAcc = 0.0f;- con->jtAcc = 0.0f;- con->jBias = 0.0f;- - con->hash = hash;- - return con;-}--cpVect-cpContactsSumImpulses(cpContact *contacts, int numContacts)-{- cpVect sum = cpvzero;- - for(int i=0; i<numContacts; i++){- cpContact *con = &contacts[i];- cpVect j = cpvmult(con->n, con->jnAcc);- sum = cpvadd(sum, j);- }- - return sum;-}--cpVect-cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts)-{- cpVect sum = cpvzero;- - for(int i=0; i<numContacts; i++){- cpContact *con = &contacts[i];- cpVect t = cpvperp(con->n);- cpVect j = cpvadd(cpvmult(con->n, con->jnAcc), cpvmult(t, con->jtAcc));- sum = cpvadd(sum, j);- }- - return sum;-}--cpArbiter*-cpArbiterAlloc(void)-{- return (cpArbiter *)calloc(1, sizeof(cpArbiter));-}--cpArbiter*-cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b, int stamp)-{- arb->numContacts = 0;- arb->contacts = NULL;- - arb->a = a;- arb->b = b;- - arb->stamp = stamp;- - return arb;-}--cpArbiter*-cpArbiterNew(cpShape *a, cpShape *b, int stamp)-{- return cpArbiterInit(cpArbiterAlloc(), a, b, stamp);-}--void-cpArbiterDestroy(cpArbiter *arb)-{- free(arb->contacts);-}--void-cpArbiterFree(cpArbiter *arb)-{- if(arb) cpArbiterDestroy(arb);- free(arb);-}--void-cpArbiterInject(cpArbiter *arb, cpContact *contacts, int numContacts)-{- // Iterate over the possible pairs to look for hash value matches.- for(int i=0; i<arb->numContacts; i++){- cpContact *old = &arb->contacts[i];- - for(int j=0; j<numContacts; j++){- cpContact *new_contact = &contacts[j];- - // This could trigger false possitives.- if(new_contact->hash == old->hash){- // Copy the persistant contact information.- new_contact->jnAcc = old->jnAcc;- new_contact->jtAcc = old->jtAcc;- }- }- }-- free(arb->contacts);- - arb->contacts = contacts;- arb->numContacts = numContacts;-}--void-cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv)-{- cpShape *shapea = arb->a;- cpShape *shapeb = arb->b;- - cpFloat e = shapea->e * shapeb->e;- arb->u = shapea->u * shapeb->u;- arb->target_v = cpvsub(shapeb->surface_v, shapea->surface_v);-- cpBody *a = shapea->body;- cpBody *b = shapeb->body;- - for(int i=0; i<arb->numContacts; i++){- cpContact *con = &arb->contacts[i];- - // Calculate the offsets.- con->r1 = cpvsub(con->p, a->p);- con->r2 = cpvsub(con->p, b->p);- - // Calculate the mass normal.- cpFloat mass_sum = a->m_inv + b->m_inv;- - cpFloat r1cn = cpvcross(con->r1, con->n);- cpFloat r2cn = cpvcross(con->r2, con->n);- cpFloat kn = mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;- con->nMass = 1.0f/kn;- - // Calculate the mass tangent.- cpVect t = cpvperp(con->n);- cpFloat r1ct = cpvcross(con->r1, t);- cpFloat r2ct = cpvcross(con->r2, t);- cpFloat kt = mass_sum + a->i_inv*r1ct*r1ct + b->i_inv*r2ct*r2ct;- con->tMass = 1.0f/kt;- - // Calculate the target bias velocity.- con->bias = -cp_bias_coef*dt_inv*cpfmin(0.0f, con->dist + cp_collision_slop);- con->jBias = 0.0f;- - // Calculate the target bounce velocity.- cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(con->r1), a->w));- cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(con->r2), b->w));- con->bounce = cpvdot(con->n, cpvsub(v2, v1))*e;- }-}--void-cpArbiterApplyCachedImpulse(cpArbiter *arb)-{- cpShape *shapea = arb->a;- cpShape *shapeb = arb->b;- - arb->u = shapea->u * shapeb->u;- arb->target_v = cpvsub(shapeb->surface_v, shapea->surface_v);-- cpBody *a = shapea->body;- cpBody *b = shapeb->body;- - for(int i=0; i<arb->numContacts; i++){- cpContact *con = &arb->contacts[i];- - cpVect t = cpvperp(con->n);- cpVect j = cpvadd(cpvmult(con->n, con->jnAcc), cpvmult(t, con->jtAcc));- cpBodyApplyImpulse(a, cpvneg(j), con->r1);- cpBodyApplyImpulse(b, j, con->r2);- }-}--void-cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef)-{- cpBody *a = arb->a->body;- cpBody *b = arb->b->body;-- for(int i=0; i<arb->numContacts; i++){- cpContact *con = &arb->contacts[i];- cpVect n = con->n;- cpVect r1 = con->r1;- cpVect r2 = con->r2;- - // Calculate the relative bias velocities.- cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias));- cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias));- cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);- - // Calculate and clamp the bias impulse.- cpFloat jbn = (con->bias - vbn)*con->nMass;- cpFloat jbnOld = con->jBias;- con->jBias = cpfmax(jbnOld + jbn, 0.0f);- jbn = con->jBias - jbnOld;- - // Apply the bias impulse.- cpVect jb = cpvmult(n, jbn);- cpBodyApplyBiasImpulse(a, cpvneg(jb), r1);- cpBodyApplyBiasImpulse(b, jb, r2);-- // Calculate the relative velocity.- cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));- cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));- cpVect vr = cpvsub(v2, v1);- cpFloat vrn = cpvdot(vr, n);- - // Calculate and clamp the normal impulse.- cpFloat jn = -(con->bounce*eCoef + vrn)*con->nMass;- cpFloat jnOld = con->jnAcc;- con->jnAcc = cpfmax(jnOld + jn, 0.0f);- jn = con->jnAcc - jnOld;- - // Calculate the relative tangent velocity.- cpVect t = cpvperp(n);- cpFloat vrt = cpvdot(cpvadd(vr, arb->target_v), t);- - // Calculate and clamp the friction impulse.- cpFloat jtMax = arb->u*con->jnAcc;- cpFloat jt = -vrt*con->tMass;- cpFloat jtOld = con->jtAcc;- con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax);- jt = con->jtAcc - jtOld;- - // Apply the final impulse.- cpVect j = cpvadd(cpvmult(n, jn), cpvmult(t, jt));- cpBodyApplyImpulse(a, cpvneg(j), r1);- cpBodyApplyImpulse(b, j, r2);- }-}
− chipmunk/cpArbiter.h
@@ -1,85 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--// Determines how fast penetrations resolve themselves.-extern cpFloat cp_bias_coef;-// Amount of allowed penetration. Used to reduce vibrating contacts.-extern cpFloat cp_collision_slop;--// Data structure for contact points.-typedef struct cpContact{- // Contact point and normal.- cpVect p, n;- // Penetration distance.- cpFloat dist;- - // Calculated by cpArbiterPreStep().- cpVect r1, r2;- cpFloat nMass, tMass, bounce;-- // Persistant contact information.- cpFloat jnAcc, jtAcc, jBias;- cpFloat bias;- - // Hash value used to (mostly) uniquely identify a contact.- unsigned int hash;-} cpContact;--// Contacts are always allocated in groups.-cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, unsigned int hash);--// Sum the contact impulses. (Can be used after cpSpaceStep() returns)-cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts);-cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts);--// Data structure for tracking collisions between shapes.-typedef struct cpArbiter{- // Information on the contact points between the objects.- int numContacts;- cpContact *contacts;- - // The two shapes involved in the collision.- cpShape *a, *b;- - // Calculated by cpArbiterPreStep().- cpFloat u;- cpVect target_v;- - // Time stamp of the arbiter. (from cpSpace)- int stamp;-} cpArbiter;--// Basic allocation/destruction functions.-cpArbiter* cpArbiterAlloc(void);-cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b, int stamp);-cpArbiter* cpArbiterNew(cpShape *a, cpShape *b, int stamp);--void cpArbiterDestroy(cpArbiter *arb);-void cpArbiterFree(cpArbiter *arb);--// These functions are all intended to be used internally.-// Inject new contact points into the arbiter while preserving contact history.-void cpArbiterInject(cpArbiter *arb, cpContact *contacts, int numContacts);-// Precalculate values used by the solver.-void cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv);-void cpArbiterApplyCachedImpulse(cpArbiter *arb);-// Run an iteration of the solver on the arbiter.-void cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef);
− chipmunk/cpArray.c
@@ -1,114 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <string.h>--#include "chipmunk.h"---//#define CP_ARRAY_INCREMENT 10--// NOTE: cpArray is rarely used and will probably go away.--cpArray*-cpArrayAlloc(void)-{- return (cpArray *)calloc(1, sizeof(cpArray));-}--cpArray*-cpArrayInit(cpArray *arr, int size)-{- arr->num = 0;- - size = (size ? size : 4);- arr->max = size;- arr->arr = (void **)malloc(size*sizeof(void**));- - return arr;-}--cpArray*-cpArrayNew(int size)-{- return cpArrayInit(cpArrayAlloc(), size);-}--void-cpArrayDestroy(cpArray *arr)-{- free(arr->arr);-}--void-cpArrayFree(cpArray *arr)-{- if(!arr) return;- cpArrayDestroy(arr);- free(arr);-}--void-cpArrayPush(cpArray *arr, void *object)-{- if(arr->num == arr->max){- arr->max *= 2;- arr->arr = (void **)realloc(arr->arr, arr->max*sizeof(void**));- }- - arr->arr[arr->num] = object;- arr->num++;-}--void-cpArrayDeleteIndex(cpArray *arr, int index)-{- int last = --arr->num;- arr->arr[index] = arr->arr[last];-}--void-cpArrayDeleteObj(cpArray *arr, void *obj)-{- for(int i=0; i<arr->num; i++){- if(arr->arr[i] == obj){- cpArrayDeleteIndex(arr, i);- return;- }- }-}--void-cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data)-{- for(int i=0; i<arr->num; i++)- iterFunc(arr->arr[i], data);-}--int-cpArrayContains(cpArray *arr, void *ptr)-{- for(int i=0; i<arr->num; i++)- if(arr->arr[i] == ptr) return 1;- - return 0;-}
− chipmunk/cpArray.h
@@ -1,45 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -// NOTE: cpArray is rarely used and will probably go away.--typedef struct cpArray{- int num, max;- void **arr;-} cpArray;--typedef void (*cpArrayIter)(void *ptr, void *data);--cpArray *cpArrayAlloc(void);-cpArray *cpArrayInit(cpArray *arr, int size);-cpArray *cpArrayNew(int size);--void cpArrayDestroy(cpArray *arr);-void cpArrayFree(cpArray *arr);--void cpArrayClear(cpArray *arr);--void cpArrayPush(cpArray *arr, void *object);-void cpArrayDeleteIndex(cpArray *arr, int index);-void cpArrayDeleteObj(cpArray *arr, void *obj);--void cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data);-int cpArrayContains(cpArray *arr, void *ptr);
− chipmunk/cpBB.c
@@ -1,46 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <math.h>--#include "chipmunk.h"--cpVect-cpBBClampVect(const cpBB bb, const cpVect v)-{- cpFloat x = cpfmin(cpfmax(bb.l, v.x), bb.r);- cpFloat y = cpfmin(cpfmax(bb.b, v.y), bb.t);- return cpv(x, y);-}--cpVect-cpBBWrapVect(const cpBB bb, const cpVect v)-{- cpFloat ix = fabsf(bb.r - bb.l);- cpFloat modx = fmodf(v.x - bb.l, ix);- cpFloat x = (modx > 0.0f) ? modx : modx + ix;- - cpFloat iy = fabsf(bb.t - bb.b);- cpFloat mody = fmodf(v.y - bb.b, iy);- cpFloat y = (mody > 0.0f) ? mody : mody + iy;- - return cpv(x + bb.l, y + bb.b);-}
− chipmunk/cpBB.h
@@ -1,53 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -typedef struct cpBB{- cpFloat l, b, r ,t;-} cpBB;--static inline cpBB-cpBBNew(const cpFloat l, const cpFloat b,- const cpFloat r, const cpFloat t)-{- cpBB bb = {l, b, r, t};- return bb;-}--static inline int-cpBBintersects(const cpBB a, const cpBB b)-{- return (a.l<=b.r && b.l<=a.r && a.b<=b.t && b.b<=a.t);-}--static inline int-cpBBcontainsBB(const cpBB bb, const cpBB other)-{- return (bb.l < other.l && bb.r > other.r && bb.b < other.b && bb.t > other.t);-}--static inline int-cpBBcontainsVect(const cpBB bb, const cpVect v)-{- return (bb.l < v.x && bb.r > v.x && bb.b < v.y && bb.t > v.y);-}--cpVect cpBBClampVect(const cpBB bb, const cpVect v); // clamps the vector to lie within the bbox-cpVect cpBBWrapVect(const cpBB bb, const cpVect v); // wrap a vector to a bbox
− chipmunk/cpBody.c
@@ -1,180 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <math.h>-#include <float.h>--#include "chipmunk.h"--cpBody*-cpBodyAlloc(void)-{- return (cpBody *)malloc(sizeof(cpBody));-}--cpBody*-cpBodyInit(cpBody *body, cpFloat m, cpFloat i)-{- body->velocity_func = cpBodyUpdateVelocity;- body->position_func = cpBodyUpdatePosition;- - cpBodySetMass(body, m);- cpBodySetMoment(body, i);-- body->p = cpvzero;- body->v = cpvzero;- body->f = cpvzero;- - cpBodySetAngle(body, 0.0f);- body->w = 0.0f;- body->t = 0.0f;- - body->v_bias = cpvzero;- body->w_bias = 0.0f;- - body->data = NULL;-// body->active = 1;-- return body;-}--cpBody*-cpBodyNew(cpFloat m, cpFloat i)-{- return cpBodyInit(cpBodyAlloc(), m, i);-}--void cpBodyDestroy(cpBody *body){}--void-cpBodyFree(cpBody *body)-{- if(body) cpBodyDestroy(body);- free(body);-}--void-cpBodySetMass(cpBody *body, cpFloat m)-{- body->m = m;- body->m_inv = 1.0f/m;-}--void-cpBodySetMoment(cpBody *body, cpFloat i)-{- body->i = i;- body->i_inv = 1.0f/i;-}--void-cpBodySetAngle(cpBody *body, cpFloat a)-{- body->a = fmod(a, (cpFloat)M_PI*2.0f);- body->rot = cpvforangle(a);-}--void-cpBodySlew(cpBody *body, cpVect pos, cpFloat dt)-{- cpVect delta = cpvsub(pos, body->p);- body->v = cpvmult(delta, 1.0/dt);-}--void-cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)-{- body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));- body->w = body->w*damping + body->t*body->i_inv*dt;-}--void-cpBodyUpdatePosition(cpBody *body, cpFloat dt)-{- body->p = cpvadd(body->p, cpvmult(cpvadd(body->v, body->v_bias), dt));- cpBodySetAngle(body, body->a + (body->w + body->w_bias)*dt);- - body->v_bias = cpvzero;- body->w_bias = 0.0f;-}--void-cpBodyResetForces(cpBody *body)-{- body->f = cpvzero;- body->t = 0.0f;-}--void-cpBodyApplyForce(cpBody *body, cpVect f, cpVect r)-{- body->f = cpvadd(body->f, f);- body->t += cpvcross(r, f);-}--void-cpDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt)-{- // Calculate the world space anchor coordinates.- cpVect r1 = cpvrotate(anchr1, a->rot);- cpVect r2 = cpvrotate(anchr2, b->rot);- - cpVect delta = cpvsub(cpvadd(b->p, r2), cpvadd(a->p, r1));- cpFloat dist = cpvlength(delta);- cpVect n = dist ? cpvmult(delta, 1.0f/dist) : cpvzero;- - cpFloat f_spring = (dist - rlen)*k;-- // Calculate the world relative velocities of the anchor points.- cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));- cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));- - // Calculate the damping force.- // This really should be in the impulse solver and can produce problems when using large damping values.- cpFloat vrn = cpvdot(cpvsub(v2, v1), n);- cpFloat f_damp = vrn*cpfmin(dmp, 1.0f/(dt*(a->m_inv + b->m_inv)));- - // Apply!- cpVect f = cpvmult(n, f_spring + f_damp);- cpBodyApplyForce(a, f, r1);- cpBodyApplyForce(b, cpvneg(f), r2);-}--//int-//cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max)-//{-// cpFloat ke = body->m*cpvdot(body->v, body->v);-// cpFloat re = body->i*body->w*body->w;-// -// if(ke + re > body->m*dvsq)-// body->active = 1;-// else if(body->active)-// body->active = (body->active + 1)%(max + 1);-// else {-// body->v = cpvzero;-// body->v_bias = cpvzero;-// body->w = 0.0f;-// body->w_bias = 0.0f;-// }-// -// return body->active;-//}
− chipmunk/cpBody.h
@@ -1,132 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--struct cpBody;-typedef void (*cpBodyVelocityFunc)(struct cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);-typedef void (*cpBodyPositionFunc)(struct cpBody *body, cpFloat dt);-- -typedef struct cpBody{- // *** Integration Functions.-- // Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)- cpBodyVelocityFunc velocity_func;- - // Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)- cpBodyPositionFunc position_func;- - // *** Mass Properties- - // Mass and it's inverse.- // Always use cpBodySetMass() whenever changing the mass as these values must agree.- cpFloat m, m_inv;- - // Moment of inertia and it's inverse.- // Always use cpBodySetMass() whenever changing the mass as these values must agree.- cpFloat i, i_inv;- - // *** Positional Properties- - // Linear components of motion (position, velocity, and force)- cpVect p, v, f;- - // Angular components of motion (angle, angular velocity, and torque)- // Always use cpBodySetAngle() to set the angle of the body as a and rot must agree.- cpFloat a, w, t;- - // Cached unit length vector representing the angle of the body.- // Used for fast vector rotation using cpvrotate().- cpVect rot;- - // *** User Definable Fields- - // User defined data pointer.- void *data;- - // *** Internally Used Fields- - // Velocity bias values used when solving penetrations and correcting joints.- cpVect v_bias;- cpFloat w_bias;- -// int active;-} cpBody;--// Basic allocation/destruction functions-cpBody *cpBodyAlloc(void);-cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);-cpBody *cpBodyNew(cpFloat m, cpFloat i);--void cpBodyDestroy(cpBody *body);-void cpBodyFree(cpBody *body);--// Setters for some of the special properties (mandatory!)-void cpBodySetMass(cpBody *body, cpFloat m);-void cpBodySetMoment(cpBody *body, cpFloat i);-void cpBodySetAngle(cpBody *body, cpFloat a);--// Modify the velocity of the body so that it will move to the specified absolute coordinates in the next timestep.-// Intended for objects that are moved manually with a custom velocity integration function.-void cpBodySlew(cpBody *body, cpVect pos, cpFloat dt);--// Default Integration functions.-void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);-void cpBodyUpdatePosition(cpBody *body, cpFloat dt);--// Convert body local to world coordinates-static inline cpVect-cpBodyLocal2World(cpBody *body, cpVect v)-{- return cpvadd(body->p, cpvrotate(v, body->rot));-}--// Convert world to body local coordinates-static inline cpVect-cpBodyWorld2Local(cpBody *body, cpVect v)-{- return cpvunrotate(cpvsub(v, body->p), body->rot);-}--// Apply an impulse (in world coordinates) to the body.-static inline void-cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r)-{- body->v = cpvadd(body->v, cpvmult(j, body->m_inv));- body->w += body->i_inv*cpvcross(r, j);-}--// Not intended for external use. Used by cpArbiter.c and cpJoint.c.-static inline void-cpBodyApplyBiasImpulse(cpBody *body, cpVect j, cpVect r)-{- body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));- body->w_bias += body->i_inv*cpvcross(r, j);-}--// Zero the forces on a body.-void cpBodyResetForces(cpBody *body);-// Apply a force (in world coordinates) to a body.-void cpBodyApplyForce(cpBody *body, cpVect f, cpVect r);--// Apply a damped spring force between two bodies.-void cpDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);--//int cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max);
− chipmunk/cpCollision.c
@@ -1,390 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <math.h>-#include <stdio.h>-#include <assert.h>--#include "chipmunk.h"--typedef int (*collisionFunc)(cpShape*, cpShape*, cpContact**);--static collisionFunc *colfuncs = NULL;--// Add contact points for circle to circle collisions.-// Used by several collision tests.-static int-circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact **con)-{- cpFloat mindist = r1 + r2;- cpVect delta = cpvsub(p2, p1);- cpFloat distsq = cpvlengthsq(delta);- if(distsq >= mindist*mindist) return 0;- - cpFloat dist = sqrtf(distsq);- // To avoid singularities, do nothing in the case of dist = 0.- cpFloat non_zero_dist = (dist ? dist : INFINITY);-- // Allocate and initialize the contact.- (*con) = (cpContact *)malloc(sizeof(cpContact));- cpContactInit(- (*con),- cpvadd(p1, cpvmult(delta, 0.5 + (r1 - 0.5*mindist)/non_zero_dist)),- cpvmult(delta, 1.0/non_zero_dist),- dist - mindist,- 0- );- - return 1;-}--// Collide circle shapes.-static int-circle2circle(cpShape *shape1, cpShape *shape2, cpContact **arr)-{- cpCircleShape *circ1 = (cpCircleShape *)shape1;- cpCircleShape *circ2 = (cpCircleShape *)shape2;- - return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr);-}--// Collide circles to segment shapes.-static int-circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact **con)-{- cpCircleShape *circ = (cpCircleShape *)circleShape;- cpSegmentShape *seg = (cpSegmentShape *)segmentShape;- - // Radius sum- cpFloat rsum = circ->r + seg->r;- - // Calculate normal distance from segment.- cpFloat dn = cpvdot(seg->tn, circ->tc) - cpvdot(seg->ta, seg->tn);- cpFloat dist = fabs(dn) - rsum;- if(dist > 0.0f) return 0;- - // Calculate tangential distance along segment.- cpFloat dt = -cpvcross(seg->tn, circ->tc);- cpFloat dtMin = -cpvcross(seg->tn, seg->ta);- cpFloat dtMax = -cpvcross(seg->tn, seg->tb);- - // Decision tree to decide which feature of the segment to collide with.- if(dt < dtMin){- if(dt < (dtMin - rsum)){- return 0;- } else {- return circle2circleQuery(circ->tc, seg->ta, circ->r, seg->r, con);- }- } else {- if(dt < dtMax){- cpVect n = (dn < 0.0f) ? seg->tn : cpvneg(seg->tn);- (*con) = (cpContact *)malloc(sizeof(cpContact));- cpContactInit(- (*con),- cpvadd(circ->tc, cpvmult(n, circ->r + dist*0.5f)),- n,- dist,- 0 - );- return 1;- } else {- if(dt < (dtMax + rsum)) {- return circle2circleQuery(circ->tc, seg->tb, circ->r, seg->r, con);- } else {- return 0;- }- }- }- - return 1;-}--// Helper function for allocating contact point lists.-static cpContact *-addContactPoint(cpContact **arr, int *max, int *num)-{- if(*arr == NULL){- // Allocate the array if it hasn't been done.- (*max) = 2;- (*num) = 0;- (*arr) = (cpContact *)malloc((*max)*sizeof(cpContact));- } else if(*num == *max){- // Extend it if necessary.- (*max) *= 2;- (*arr) = (cpContact *)realloc(*arr, (*max)*sizeof(cpContact));- }- - cpContact *con = &(*arr)[*num];- (*num)++;- - return con;-}--// Find the minimum separating axis for the give poly and axis list.-static inline int-findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out)-{- int min_index = 0;- cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);- if(min > 0.0) return -1;- - for(int i=1; i<num; i++){- cpFloat dist = cpPolyShapeValueOnAxis(poly, axes[i].n, axes[i].d);- if(dist > 0.0) {- return -1;- } else if(dist > min){- min = dist;- min_index = i;- }- }- - (*min_out) = min;- return min_index;-}--// Add contacts for penetrating vertexes.-static inline int-findVerts(cpContact **arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist)-{- int max = 0;- int num = 0;- - for(int i=0; i<poly1->numVerts; i++){- cpVect v = poly1->tVerts[i];- if(cpPolyShapeContainsVertPartial(poly2, v, cpvneg(n)))- cpContactInit(addContactPoint(arr, &max, &num), v, n, dist, CP_HASH_PAIR(poly1, i));- }- - for(int i=0; i<poly2->numVerts; i++){- cpVect v = poly2->tVerts[i];- if(cpPolyShapeContainsVertPartial(poly1, v, n))- cpContactInit(addContactPoint(arr, &max, &num), v, n, dist, CP_HASH_PAIR(poly2, i));- }- - // if(!num)- // addContactPoint(arr, &size, &num, cpContactNew(shape1->body->p, n, dist, 0));-- return num;-}--// Collide poly shapes together.-static int-poly2poly(cpShape *shape1, cpShape *shape2, cpContact **arr)-{- cpPolyShape *poly1 = (cpPolyShape *)shape1;- cpPolyShape *poly2 = (cpPolyShape *)shape2;- - cpFloat min1;- int mini1 = findMSA(poly2, poly1->tAxes, poly1->numVerts, &min1);- if(mini1 == -1) return 0;- - cpFloat min2;- int mini2 = findMSA(poly1, poly2->tAxes, poly2->numVerts, &min2);- if(mini2 == -1) return 0;- - // There is overlap, find the penetrating verts- if(min1 > min2)- return findVerts(arr, poly1, poly2, poly1->tAxes[mini1].n, min1);- else- return findVerts(arr, poly1, poly2, cpvneg(poly2->tAxes[mini2].n), min2);-}--// Like cpPolyValueOnAxis(), but for segments.-static inline float-segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)-{- cpFloat a = cpvdot(n, seg->ta) - seg->r;- cpFloat b = cpvdot(n, seg->tb) - seg->r;- return cpfmin(a, b) - d;-}--// Identify vertexes that have penetrated the segment.-static inline void-findPointsBehindSeg(cpContact **arr, int *max, int *num, cpSegmentShape *seg, cpPolyShape *poly, cpFloat pDist, cpFloat coef) -{- cpFloat dta = cpvcross(seg->tn, seg->ta);- cpFloat dtb = cpvcross(seg->tn, seg->tb);- cpVect n = cpvmult(seg->tn, coef);- - for(int i=0; i<poly->numVerts; i++){- cpVect v = poly->tVerts[i];- if(cpvdot(v, n) < cpvdot(seg->tn, seg->ta)*coef + seg->r){- cpFloat dt = cpvcross(seg->tn, v);- if(dta >= dt && dt >= dtb){- cpContactInit(addContactPoint(arr, max, num), v, n, pDist, CP_HASH_PAIR(poly, i));- }- }- }-}--// This one is complicated and gross. Just don't go there...-// TODO: Comment me!-static int-seg2poly(cpShape *shape1, cpShape *shape2, cpContact **arr)-{- cpSegmentShape *seg = (cpSegmentShape *)shape1;- cpPolyShape *poly = (cpPolyShape *)shape2;- cpPolyShapeAxis *axes = poly->tAxes;- - cpFloat segD = cpvdot(seg->tn, seg->ta);- cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r;- cpFloat minNeg = cpPolyShapeValueOnAxis(poly, cpvneg(seg->tn), -segD) - seg->r;- if(minNeg > 0.0f || minNorm > 0.0f) return 0;- - int mini = 0;- cpFloat poly_min = segValueOnAxis(seg, axes->n, axes->d);- if(poly_min > 0.0f) return 0;- for(int i=0; i<poly->numVerts; i++){- cpFloat dist = segValueOnAxis(seg, axes[i].n, axes[i].d);- if(dist > 0.0f){- return 0;- } else if(dist > poly_min){- poly_min = dist;- mini = i;- }- }- - int max = 0;- int num = 0;- - cpVect poly_n = cpvneg(axes[mini].n);- - cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r));- cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r));- if(cpPolyShapeContainsVert(poly, va))- cpContactInit(addContactPoint(arr, &max, &num), va, poly_n, poly_min, CP_HASH_PAIR(seg, 0));- if(cpPolyShapeContainsVert(poly, vb))- cpContactInit(addContactPoint(arr, &max, &num), vb, poly_n, poly_min, CP_HASH_PAIR(seg, 1));-- // Floating point precision problems here.- // This will have to do for now.- poly_min -= cp_collision_slop;- if(minNorm >= poly_min || minNeg >= poly_min) {- if(minNorm > minNeg)- findPointsBehindSeg(arr, &max, &num, seg, poly, minNorm, 1.0f);- else- findPointsBehindSeg(arr, &max, &num, seg, poly, minNeg, -1.0f);- }- - // If no other collision points are found, try colliding endpoints.- if(num == 0){- cpVect poly_a = poly->tVerts[mini];- cpVect poly_b = poly->tVerts[(mini + 1)%poly->numVerts];- - if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr))- return 1;- - if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr))- return 1;- - if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr))- return 1;- - if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr))- return 1;- }-- return num;-}--// This one is less gross, but still gross.-// TODO: Comment me!-static int-circle2poly(cpShape *shape1, cpShape *shape2, cpContact **con)-{- cpCircleShape *circ = (cpCircleShape *)shape1;- cpPolyShape *poly = (cpPolyShape *)shape2;- cpPolyShapeAxis *axes = poly->tAxes;- - int mini = 0;- cpFloat min = cpvdot(axes->n, circ->tc) - axes->d - circ->r;- for(int i=0; i<poly->numVerts; i++){- cpFloat dist = cpvdot(axes[i].n, circ->tc) - axes[i].d - circ->r;- if(dist > 0.0){- return 0;- } else if(dist > min) {- min = dist;- mini = i;- }- }- - cpVect n = axes[mini].n;- cpVect a = poly->tVerts[mini];- cpVect b = poly->tVerts[(mini + 1)%poly->numVerts];- cpFloat dta = cpvcross(n, a);- cpFloat dtb = cpvcross(n, b);- cpFloat dt = cpvcross(n, circ->tc);- - if(dt < dtb){- return circle2circleQuery(circ->tc, b, circ->r, 0.0f, con);- } else if(dt < dta) {- (*con) = (cpContact *)malloc(sizeof(cpContact));- cpContactInit(- (*con),- cpvsub(circ->tc, cpvmult(n, circ->r + min/2.0f)),- cpvneg(n),- min,- 0 - );- - return 1;- } else {- return circle2circleQuery(circ->tc, a, circ->r, 0.0f, con);- }-}--static void-addColFunc(cpShapeType a, cpShapeType b, collisionFunc func)-{- colfuncs[a + b*CP_NUM_SHAPES] = func;-}--#ifdef __cplusplus-extern "C" {-#endif- // Initializes the array of collision functions.- // Called by cpInitChipmunk().- void- cpInitCollisionFuncs(void)- {- if(!colfuncs)- colfuncs = (collisionFunc *)calloc(CP_NUM_SHAPES*CP_NUM_SHAPES, sizeof(collisionFunc));- - addColFunc(CP_CIRCLE_SHAPE, CP_CIRCLE_SHAPE, circle2circle);- addColFunc(CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, circle2segment);- addColFunc(CP_SEGMENT_SHAPE, CP_POLY_SHAPE, seg2poly);- addColFunc(CP_CIRCLE_SHAPE, CP_POLY_SHAPE, circle2poly);- addColFunc(CP_POLY_SHAPE, CP_POLY_SHAPE, poly2poly);- } -#ifdef __cplusplus-}-#endif--int-cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr)-{- // Their shape types must be in order.- assert(a->klass->type <= b->klass->type);- - collisionFunc cfunc = colfuncs[a->klass->type + b->klass->type*CP_NUM_SHAPES];- return (cfunc) ? cfunc(a, b, arr) : 0;-}
− chipmunk/cpCollision.h
@@ -1,23 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--// Collides two cpShape structures. (this function is lonely :( )-int cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr);
− chipmunk/cpHashSet.c
@@ -1,219 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <assert.h>--#include "chipmunk.h"-#include "prime.h"--void-cpHashSetDestroy(cpHashSet *set)-{- // Free the chains.- for(int i=0; i<set->size; i++){- // Free the bins in the chain.- cpHashSetBin *bin = set->table[i];- while(bin){- cpHashSetBin *next = bin->next;- free(bin);- bin = next;- }- }- - // Free the table.- free(set->table);-}--void-cpHashSetFree(cpHashSet *set)-{- if(set) cpHashSetDestroy(set);- free(set);-}--cpHashSet *-cpHashSetAlloc(void)-{- return (cpHashSet *)calloc(1, sizeof(cpHashSet));-}--cpHashSet *-cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)-{- set->size = next_prime(size);- set->entries = 0;- - set->eql = eqlFunc;- set->trans = trans;- - set->default_value = NULL;- - set->table = (cpHashSetBin **)calloc(set->size, sizeof(cpHashSetBin *));- - return set;-}--cpHashSet *-cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)-{- return cpHashSetInit(cpHashSetAlloc(), size, eqlFunc, trans);-}--static int-setIsFull(cpHashSet *set)-{- return (set->entries >= set->size);-}--static void-cpHashSetResize(cpHashSet *set)-{- // Get the next approximate doubled prime.- int newSize = next_prime(set->size + 1);- // Allocate a new table.- cpHashSetBin **newTable = (cpHashSetBin **)calloc(newSize, sizeof(cpHashSetBin *));- - // Iterate over the chains.- for(int i=0; i<set->size; i++){- // Rehash the bins into the new table.- cpHashSetBin *bin = set->table[i];- while(bin){- cpHashSetBin *next = bin->next;- - int index = bin->hash%newSize;- bin->next = newTable[index];- newTable[index] = bin;- - bin = next;- }- }- - free(set->table);- - set->table = newTable;- set->size = newSize;-}--void *-cpHashSetInsert(cpHashSet *set, unsigned int hash, void *ptr, void *data)-{- int index = hash%set->size;- - // Find the bin with the matching element.- cpHashSetBin *bin = set->table[index];- while(bin && !set->eql(ptr, bin->elt))- bin = bin->next;- - // Create it necessary.- if(!bin){- bin = (cpHashSetBin *)malloc(sizeof(cpHashSetBin));- bin->hash = hash;- bin->elt = set->trans(ptr, data); // Transform the pointer.- - bin->next = set->table[index];- set->table[index] = bin;- - set->entries++;- - // Resize the set if it's full.- if(setIsFull(set))- cpHashSetResize(set);- }- - return bin->elt;-}--void *-cpHashSetRemove(cpHashSet *set, unsigned int hash, void *ptr)-{- int index = hash%set->size;- - // Pointer to the previous bin pointer.- cpHashSetBin **prev_ptr = &set->table[index];- // Pointer the the current bin.- cpHashSetBin *bin = set->table[index];- - // Find the bin- while(bin && !set->eql(ptr, bin->elt)){- prev_ptr = &bin->next;- bin = bin->next;- }- - // Remove it if it exists.- if(bin){- // Update the previos bin pointer to point to the next bin.- (*prev_ptr) = bin->next;- set->entries--;- - void *return_value = bin->elt;- free(bin);- return return_value;- }- - return NULL;-}--void *-cpHashSetFind(cpHashSet *set, unsigned int hash, void *ptr)-{ - int index = hash%set->size;- cpHashSetBin *bin = set->table[index];- while(bin && !set->eql(ptr, bin->elt))- bin = bin->next;- - return (bin ? bin->elt : set->default_value);-}--void-cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data)-{- for(int i=0; i<set->size; i++){- cpHashSetBin *bin;- for(bin = set->table[i]; bin; bin = bin->next)- func(bin->elt, data);- }-}--void-cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data)-{- // Iterate over all the chains.- for(int i=0; i<set->size; i++){- // The rest works similarly to cpHashSetRemove() above.- cpHashSetBin **prev_ptr = &set->table[i];- cpHashSetBin *bin = set->table[i];- while(bin){- cpHashSetBin *next = bin->next;- - if(func(bin->elt, data)){- prev_ptr = &bin->next;- } else {- (*prev_ptr) = next;-- set->entries--;- free(bin);- }- - bin = next;- }- }-}
− chipmunk/cpHashSet.h
@@ -1,79 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -// cpHashSet uses a chained hashtable implementation.-// Other than the transformation functions, there is nothing fancy going on.--// cpHashSetBin's form the linked lists in the chained hash table.-typedef struct cpHashSetBin {- // Pointer to the element.- void *elt;- // Hash value of the element.- unsigned int hash;- // Next element in the chain.- struct cpHashSetBin *next;-} cpHashSetBin;--// Equality function. Returns true if ptr is equal to elt.-typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt);-// Used by cpHashSetInsert(). Called to transform the ptr into an element.-typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);-// Iterator function for a hashset.-typedef void (*cpHashSetIterFunc)(void *elt, void *data);-// Reject function. Returns true if elt should be dropped.-typedef int (*cpHashSetRejectFunc)(void *elt, void *data);--typedef struct cpHashSet {- // Number of elements stored in the table.- int entries;- // Number of cells in the table.- int size;- - cpHashSetEqlFunc eql;- cpHashSetTransFunc trans;- - // Default value returned by cpHashSetFind() when no element is found.- // Defaults to NULL.- void *default_value;- - cpHashSetBin **table;-} cpHashSet;--// Basic allocation/destruction functions.-void cpHashSetDestroy(cpHashSet *set);-void cpHashSetFree(cpHashSet *set);--cpHashSet *cpHashSetAlloc(void);-cpHashSet *cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);-cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);--// Insert an element into the set, returns the element.-// If it doesn't already exist, the transformation function is applied.-void *cpHashSetInsert(cpHashSet *set, unsigned int hash, void *ptr, void *data);-// Remove and return an element from the set.-void *cpHashSetRemove(cpHashSet *set, unsigned int hash, void *ptr);-// Find an element in the set. Returns the default value if the element isn't found.-void *cpHashSetFind(cpHashSet *set, unsigned int hash, void *ptr);--// Iterate over a hashset.-void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data);-// Iterate over a hashset while rejecting certain elements.-void cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data);
− chipmunk/cpJoint.c
@@ -1,553 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke-* -* Permission is hereby granted, free of charge, to any person obtaining a copy-* of this software and associated documentation files (the "Software"), to deal-* in the Software without restriction, including without limitation the rights-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell-* copies of the Software, and to permit persons to whom the Software is-* furnished to do so, subject to the following conditions:-* -* The above copyright notice and this permission notice shall be included in-* all copies or substantial portions of the Software.-* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-* SOFTWARE.-*/--#include <stdlib.h>-#include <math.h>--#include "chipmunk.h"--// TODO: Comment me!--cpFloat cp_joint_bias_coef = 0.1f;--void cpJointDestroy(cpJoint *joint){}--void-cpJointFree(cpJoint *joint)-{- if(joint) cpJointDestroy(joint);- free(joint);-}--static void-cpJointInit(cpJoint *joint, const cpJointClass *klass, cpBody *a, cpBody *b)-{- joint->klass = klass;- joint->a = a;- joint->b = b;-}---static inline cpVect-relative_velocity(cpVect r1, cpVect v1, cpFloat w1, cpVect r2, cpVect v2, cpFloat w2){- cpVect v1_sum = cpvadd(v1, cpvmult(cpvperp(r1), w1));- cpVect v2_sum = cpvadd(v2, cpvmult(cpvperp(r2), w2));- - return cpvsub(v2_sum, v1_sum);-}--static inline cpFloat-scalar_k(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)-{- cpFloat mass_sum = a->m_inv + b->m_inv;- cpFloat r1cn = cpvcross(r1, n);- cpFloat r2cn = cpvcross(r2, n);-- return mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;-}--static inline void-apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)-{- cpBodyApplyImpulse(a, cpvneg(j), r1);- cpBodyApplyImpulse(b, j, r2);-}--static inline void-apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)-{- cpBodyApplyBiasImpulse(a, cpvneg(j), r1);- cpBodyApplyBiasImpulse(b, j, r2);-}---static void-pinJointPreStep(cpJoint *joint, cpFloat dt_inv)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- cpPinJoint *jnt = (cpPinJoint *)joint;- - jnt->r1 = cpvrotate(jnt->anchr1, a->rot);- jnt->r2 = cpvrotate(jnt->anchr2, b->rot);- - cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));- cpFloat dist = cpvlength(delta);- jnt->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));- - // calculate mass normal- jnt->nMass = 1.0f/scalar_k(a, b, jnt->r1, jnt->r2, jnt->n);- - // calculate bias velocity- jnt->bias = -cp_joint_bias_coef*dt_inv*(dist - jnt->dist);- jnt->jBias = 0.0f;- - // apply accumulated impulse- cpVect j = cpvmult(jnt->n, jnt->jnAcc);- apply_impulses(a, b, jnt->r1, jnt->r2, j);-}--static void-pinJointApplyImpulse(cpJoint *joint)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- - cpPinJoint *jnt = (cpPinJoint *)joint;- cpVect n = jnt->n;- cpVect r1 = jnt->r1;- cpVect r2 = jnt->r2;-- //calculate bias impulse- cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);- cpFloat vbn = cpvdot(vbr, n);- - cpFloat jbn = (jnt->bias - vbn)*jnt->nMass;- jnt->jBias += jbn;- - cpVect jb = cpvmult(n, jbn);- apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);- - // compute relative velocity- cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);- cpFloat vrn = cpvdot(vr, n);- - // compute normal impulse- cpFloat jn = -vrn*jnt->nMass;- jnt->jnAcc =+ jn;- - // apply impulse- cpVect j = cpvmult(n, jn);- apply_impulses(a, b, jnt->r1, jnt->r2, j);-}--static const cpJointClass pinJointClass = {- CP_PIN_JOINT,- pinJointPreStep,- pinJointApplyImpulse,-};--cpPinJoint *-cpPinJointAlloc(void)-{- return (cpPinJoint *)malloc(sizeof(cpPinJoint));-}--cpPinJoint *-cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)-{- cpJointInit((cpJoint *)joint, &pinJointClass, a, b);- - joint->anchr1 = anchr1;- joint->anchr2 = anchr2;- - cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot));- cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot));- joint->dist = cpvlength(cpvsub(p2, p1));-- joint->jnAcc = 0.0;- - return joint;-}--cpJoint *-cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)-{- return (cpJoint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2);-}-----static void-slideJointPreStep(cpJoint *joint, cpFloat dt_inv)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- cpSlideJoint *jnt = (cpSlideJoint *)joint;- - jnt->r1 = cpvrotate(jnt->anchr1, a->rot);- jnt->r2 = cpvrotate(jnt->anchr2, b->rot);- - cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));- cpFloat dist = cpvlength(delta);- cpFloat pdist = 0.0;- if(dist > jnt->max) {- pdist = dist - jnt->max;- } else if(dist < jnt->min) {- pdist = jnt->min - dist;- dist = -dist;- }- jnt->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));- - // calculate mass normal- jnt->nMass = 1.0f/scalar_k(a, b, jnt->r1, jnt->r2, jnt->n);- - // calculate bias velocity- jnt->bias = -cp_joint_bias_coef*dt_inv*(pdist);- jnt->jBias = 0.0f;- - // apply accumulated impulse- if(!jnt->bias) //{- // if bias is 0, then the joint is not at a limit.- jnt->jnAcc = 0.0f;-// } else {- cpVect j = cpvmult(jnt->n, jnt->jnAcc);- apply_impulses(a, b, jnt->r1, jnt->r2, j);-// }-}--static void-slideJointApplyImpulse(cpJoint *joint)-{- cpSlideJoint *jnt = (cpSlideJoint *)joint;- if(!jnt->bias) return; // early exit-- cpBody *a = joint->a;- cpBody *b = joint->b;- - cpVect n = jnt->n;- cpVect r1 = jnt->r1;- cpVect r2 = jnt->r2;- - //calculate bias impulse- cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);- cpFloat vbn = cpvdot(vbr, n);- - cpFloat jbn = (jnt->bias - vbn)*jnt->nMass;- cpFloat jbnOld = jnt->jBias;- jnt->jBias = cpfmin(jbnOld + jbn, 0.0f);- jbn = jnt->jBias - jbnOld;- - cpVect jb = cpvmult(n, jbn);- apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);- - // compute relative velocity- cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);- cpFloat vrn = cpvdot(vr, n);- - // compute normal impulse- cpFloat jn = -vrn*jnt->nMass;- cpFloat jnOld = jnt->jnAcc;- jnt->jnAcc = cpfmin(jnOld + jn, 0.0f);- jn = jnt->jnAcc - jnOld;- - // apply impulse- cpVect j = cpvmult(n, jn);- apply_impulses(a, b, jnt->r1, jnt->r2, j);-}--static const cpJointClass slideJointClass = {- CP_SLIDE_JOINT,- slideJointPreStep,- slideJointApplyImpulse,-};--cpSlideJoint *-cpSlideJointAlloc(void)-{- return (cpSlideJoint *)malloc(sizeof(cpSlideJoint));-}--cpSlideJoint *-cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)-{- cpJointInit((cpJoint *)joint, &slideJointClass, a, b);- - joint->anchr1 = anchr1;- joint->anchr2 = anchr2;- joint->min = min;- joint->max = max;- - joint->jnAcc = 0.0;- - return joint;-}--cpJoint *-cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)-{- return (cpJoint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max);-}-----static void-pivotJointPreStep(cpJoint *joint, cpFloat dt_inv)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- cpPivotJoint *jnt = (cpPivotJoint *)joint;- - jnt->r1 = cpvrotate(jnt->anchr1, a->rot);- jnt->r2 = cpvrotate(jnt->anchr2, b->rot);- - // calculate mass matrix- // If I wasn't lazy, this wouldn't be so gross...- cpFloat k11, k12, k21, k22;- - cpFloat m_sum = a->m_inv + b->m_inv;- k11 = m_sum; k12 = 0.0f;- k21 = 0.0f; k22 = m_sum;- - cpFloat r1xsq = jnt->r1.x * jnt->r1.x * a->i_inv;- cpFloat r1ysq = jnt->r1.y * jnt->r1.y * a->i_inv;- cpFloat r1nxy = -jnt->r1.x * jnt->r1.y * a->i_inv;- k11 += r1ysq; k12 += r1nxy;- k21 += r1nxy; k22 += r1xsq;- - cpFloat r2xsq = jnt->r2.x * jnt->r2.x * b->i_inv;- cpFloat r2ysq = jnt->r2.y * jnt->r2.y * b->i_inv;- cpFloat r2nxy = -jnt->r2.x * jnt->r2.y * b->i_inv;- k11 += r2ysq; k12 += r2nxy;- k21 += r2nxy; k22 += r2xsq;- - cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);- jnt->k1 = cpv( k22*det_inv, -k12*det_inv);- jnt->k2 = cpv(-k21*det_inv, k11*det_inv);- - - // calculate bias velocity- cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));- jnt->bias = cpvmult(delta, -cp_joint_bias_coef*dt_inv);- jnt->jBias = cpvzero;- - // apply accumulated impulse- apply_impulses(a, b, jnt->r1, jnt->r2, jnt->jAcc);-}--static void-pivotJointApplyImpulse(cpJoint *joint)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- - cpPivotJoint *jnt = (cpPivotJoint *)joint;- cpVect r1 = jnt->r1;- cpVect r2 = jnt->r2;- cpVect k1 = jnt->k1;- cpVect k2 = jnt->k2;- - //calculate bias impulse- cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);- vbr = cpvsub(jnt->bias, vbr);- - cpVect jb = cpv(cpvdot(vbr, k1), cpvdot(vbr, k2));- jnt->jBias = cpvadd(jnt->jBias, jb);- - apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);- - // compute relative velocity- cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);- - // compute normal impulse- cpVect j = cpv(-cpvdot(vr, k1), -cpvdot(vr, k2));- jnt->jAcc = cpvadd(jnt->jAcc, j);- - // apply impulse- apply_impulses(a, b, jnt->r1, jnt->r2, j);-}--static const cpJointClass pivotJointClass = {- CP_PIVOT_JOINT,- pivotJointPreStep,- pivotJointApplyImpulse,-};--cpPivotJoint *-cpPivotJointAlloc(void)-{- return (cpPivotJoint *)malloc(sizeof(cpPivotJoint));-}--cpPivotJoint *-cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot)-{- cpJointInit((cpJoint *)joint, &pivotJointClass, a, b);- - joint->anchr1 = cpvunrotate(cpvsub(pivot, a->p), a->rot);- joint->anchr2 = cpvunrotate(cpvsub(pivot, b->p), b->rot);- - joint->jAcc = cpvzero;- - return joint;-}--cpJoint *-cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)-{- return (cpJoint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, pivot);-}-----static void-grooveJointPreStep(cpJoint *joint, cpFloat dt_inv)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- cpGrooveJoint *jnt = (cpGrooveJoint *)joint;- - // calculate endpoints in worldspace- cpVect ta = cpBodyLocal2World(a, jnt->grv_a);- cpVect tb = cpBodyLocal2World(a, jnt->grv_b);-- // calculate axis- cpVect n = cpvrotate(jnt->grv_n, a->rot);- cpFloat d = cpvdot(ta, n);- - jnt->grv_tn = n;- jnt->r2 = cpvrotate(jnt->anchr2, b->rot);- - // calculate tangential distance along the axis of r2- cpFloat td = cpvcross(cpvadd(b->p, jnt->r2), n);- // calculate clamping factor and r2- if(td <= cpvcross(ta, n)){- jnt->clamp = 1.0f;- jnt->r1 = cpvsub(ta, a->p);- } else if(td >= cpvcross(tb, n)){- jnt->clamp = -1.0f;- jnt->r1 = cpvsub(tb, a->p);- } else {- jnt->clamp = 0.0f;- jnt->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);- }- - // calculate mass matrix- // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...- cpFloat k11, k12, k21, k22;- cpFloat m_sum = a->m_inv + b->m_inv;- - // start with I*m_sum- k11 = m_sum; k12 = 0.0f;- k21 = 0.0f; k22 = m_sum;- - // add the influence from r1- cpFloat r1xsq = jnt->r1.x * jnt->r1.x * a->i_inv;- cpFloat r1ysq = jnt->r1.y * jnt->r1.y * a->i_inv;- cpFloat r1nxy = -jnt->r1.x * jnt->r1.y * a->i_inv;- k11 += r1ysq; k12 += r1nxy;- k21 += r1nxy; k22 += r1xsq;- - // add the influnce from r2- cpFloat r2xsq = jnt->r2.x * jnt->r2.x * b->i_inv;- cpFloat r2ysq = jnt->r2.y * jnt->r2.y * b->i_inv;- cpFloat r2nxy = -jnt->r2.x * jnt->r2.y * b->i_inv;- k11 += r2ysq; k12 += r2nxy;- k21 += r2nxy; k22 += r2xsq;- - // invert- cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);- jnt->k1 = cpv( k22*det_inv, -k12*det_inv);- jnt->k2 = cpv(-k21*det_inv, k11*det_inv);- - - // calculate bias velocity- cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));- jnt->bias = cpvmult(delta, -cp_joint_bias_coef*dt_inv);- jnt->jBias = cpvzero;- - // apply accumulated impulse- apply_impulses(a, b, jnt->r1, jnt->r2, jnt->jAcc);-}--static inline cpVect-grooveConstrain(cpGrooveJoint *jnt, cpVect j){- cpVect n = jnt->grv_tn;- cpVect jn = cpvmult(n, cpvdot(j, n));-- cpVect t = cpvperp(n);- cpFloat coef = (jnt->clamp*cpvcross(j, n) > 0.0f) ? 1.0f : 0.0f;- cpVect jt = cpvmult(t, cpvdot(j, t)*coef); - - return cpvadd(jn, jt);-}--static void-grooveJointApplyImpulse(cpJoint *joint)-{- cpBody *a = joint->a;- cpBody *b = joint->b;- - cpGrooveJoint *jnt = (cpGrooveJoint *)joint;- cpVect r1 = jnt->r1;- cpVect r2 = jnt->r2;- cpVect k1 = jnt->k1;- cpVect k2 = jnt->k2;- - //calculate bias impulse- cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);- vbr = cpvsub(jnt->bias, vbr);- - cpVect jb = cpv(cpvdot(vbr, k1), cpvdot(vbr, k2));- cpVect jbOld = jnt->jBias;- jnt->jBias = grooveConstrain(jnt, cpvadd(jbOld, jb));- jb = cpvsub(jnt->jBias, jbOld);- - apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);- - // compute impulse- cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);-- cpVect j = cpv(-cpvdot(vr, k1), -cpvdot(vr, k2));- cpVect jOld = jnt->jAcc;- jnt->jAcc = grooveConstrain(jnt, cpvadd(jOld, j));- j = cpvsub(jnt->jAcc, jOld);- - // apply impulse- apply_impulses(a, b, jnt->r1, jnt->r2, j);-}--static const cpJointClass grooveJointClass = {- CP_GROOVE_JOINT,- grooveJointPreStep,- grooveJointApplyImpulse,-};--cpGrooveJoint *-cpGrooveJointAlloc(void)-{- return (cpGrooveJoint *)malloc(sizeof(cpGrooveJoint));-}--cpGrooveJoint *-cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)-{- cpJointInit((cpJoint *)joint, &grooveJointClass, a, b);- - joint->grv_a = groove_a;- joint->grv_b = groove_b;- joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));- joint->anchr2 = anchr2;- - joint->jAcc = cpvzero;- - return joint;-}--cpJoint *-cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)-{- return (cpJoint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);-}-
− chipmunk/cpJoint.h
@@ -1,122 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke-* -* Permission is hereby granted, free of charge, to any person obtaining a copy-* of this software and associated documentation files (the "Software"), to deal-* in the Software without restriction, including without limitation the rights-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell-* copies of the Software, and to permit persons to whom the Software is-* furnished to do so, subject to the following conditions:-* -* The above copyright notice and this permission notice shall be included in-* all copies or substantial portions of the Software.-* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-* SOFTWARE.-*/--// TODO: Comment me!- -extern cpFloat cp_joint_bias_coef;--typedef enum cpJointType {- CP_PIN_JOINT,- CP_PIVOT_JOINT,- CP_SLIDE_JOINT,- CP_GROOVE_JOINT,- CP_CUSTOM_JOINT, // For user definable joint types.-} cpJointType;--struct cpJoint;-struct cpJointClass;--typedef struct cpJointClass {- cpJointType type;- - void (*preStep)(struct cpJoint *joint, cpFloat dt_inv);- void (*applyImpulse)(struct cpJoint *joint);-} cpJointClass;--typedef struct cpJoint {- const cpJointClass *klass;- - cpBody *a, *b;-} cpJoint;--void cpJointDestroy(cpJoint *joint);-void cpJointFree(cpJoint *joint);---typedef struct cpPinJoint {- cpJoint joint;- cpVect anchr1, anchr2;- cpFloat dist;- - cpVect r1, r2;- cpVect n;- cpFloat nMass;- - cpFloat jnAcc, jBias;- cpFloat bias;-} cpPinJoint;--cpPinJoint *cpPinJointAlloc(void);-cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);-cpJoint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);---typedef struct cpSlideJoint {- cpJoint joint;- cpVect anchr1, anchr2;- cpFloat min, max;- - cpVect r1, r2;- cpVect n;- cpFloat nMass;- - cpFloat jnAcc, jBias;- cpFloat bias;-} cpSlideJoint;--cpSlideJoint *cpSlideJointAlloc(void);-cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);-cpJoint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);---typedef struct cpPivotJoint {- cpJoint joint;- cpVect anchr1, anchr2;- - cpVect r1, r2;- cpVect k1, k2;- - cpVect jAcc, jBias;- cpVect bias;-} cpPivotJoint;--cpPivotJoint *cpPivotJointAlloc(void);-cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot);-cpJoint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);---typedef struct cpGrooveJoint {- cpJoint joint;- cpVect grv_n, grv_a, grv_b;- cpVect anchr2;- - cpVect grv_tn;- cpFloat clamp;- cpVect r1, r2;- cpVect k1, k2;- - cpVect jAcc, jBias;- cpVect bias;-} cpGrooveJoint;--cpGrooveJoint *cpGrooveJointAlloc(void);-cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);-cpJoint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
− chipmunk/cpPolyShape.c
@@ -1,139 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <stdio.h>-#include <math.h>--#include "chipmunk.h"--cpPolyShape *-cpPolyShapeAlloc(void)-{- return (cpPolyShape *)calloc(1, sizeof(cpPolyShape));-}--static void-cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot)-{- cpVect *src = poly->verts;- cpVect *dst = poly->tVerts;- - for(int i=0; i<poly->numVerts; i++)- dst[i] = cpvadd(p, cpvrotate(src[i], rot));-}--static void-cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot)-{- cpPolyShapeAxis *src = poly->axes;- cpPolyShapeAxis *dst = poly->tAxes;- - for(int i=0; i<poly->numVerts; i++){- cpVect n = cpvrotate(src[i].n, rot);- dst[i].n = n;- dst[i].d = cpvdot(p, n) + src[i].d;- }-}--static cpBB-cpPolyShapeCacheData(cpShape *shape, cpVect p, cpVect rot)-{- cpPolyShape *poly = (cpPolyShape *)shape;- - cpFloat l, b, r, t;- - cpPolyShapeTransformAxes(poly, p, rot);- cpPolyShapeTransformVerts(poly, p, rot);- - cpVect *verts = poly->tVerts;- l = r = verts[0].x;- b = t = verts[0].y;- - // TODO do as part of cpPolyShapeTransformVerts?- for(int i=1; i<poly->numVerts; i++){- cpVect v = verts[i];- - l = cpfmin(l, v.x);- r = cpfmax(r, v.x);- - b = cpfmin(b, v.y);- t = cpfmax(t, v.y);- }- - return cpBBNew(l, b, r, t);-}--static void-cpPolyShapeDestroy(cpShape *shape)-{- cpPolyShape *poly = (cpPolyShape *)shape;- - free(poly->verts);- free(poly->tVerts);- - free(poly->axes);- free(poly->tAxes);-}--static int-cpPolyShapePointQuery(cpShape *shape, cpVect p){- // TODO Check against BB first?- return cpPolyShapeContainsVert((cpPolyShape *)shape, p);-}--static const cpShapeClass polyClass = {- CP_POLY_SHAPE,- cpPolyShapeCacheData,- cpPolyShapeDestroy,- cpPolyShapePointQuery,-};--cpPolyShape *-cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)-{ - poly->numVerts = numVerts;-- poly->verts = (cpVect *)calloc(numVerts, sizeof(cpVect));- poly->tVerts = (cpVect *)calloc(numVerts, sizeof(cpVect));- poly->axes = (cpPolyShapeAxis *)calloc(numVerts, sizeof(cpPolyShapeAxis));- poly->tAxes = (cpPolyShapeAxis *)calloc(numVerts, sizeof(cpPolyShapeAxis));- - for(int i=0; i<numVerts; i++){- cpVect a = cpvadd(offset, verts[i]);- cpVect b = cpvadd(offset, verts[(i+1)%numVerts]);- cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));-- poly->verts[i] = a;- poly->axes[i].n = n;- poly->axes[i].d = cpvdot(n, a);- }- - cpShapeInit((cpShape *)poly, &polyClass, body);-- return poly;-}--cpShape *-cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)-{- return (cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), body, numVerts, verts, offset);-}
− chipmunk/cpPolyShape.h
@@ -1,92 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--// Axis structure used by cpPolyShape.-typedef struct cpPolyShapeAxis{- // normal- cpVect n;- // distance from origin- cpFloat d;-} cpPolyShapeAxis;--// Convex polygon shape structure.-typedef struct cpPolyShape{- cpShape shape;- - // Vertex and axis lists.- int numVerts;- cpVect *verts;- cpPolyShapeAxis *axes;-- // Transformed vertex and axis lists.- cpVect *tVerts;- cpPolyShapeAxis *tAxes;-} cpPolyShape;--// Basic allocation functions.-cpPolyShape *cpPolyShapeAlloc(void);-cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset);-cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);--// Returns the minimum distance of the polygon to the axis.-static inline cpFloat-cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)-{- cpVect *verts = poly->tVerts;- cpFloat min = cpvdot(n, verts[0]);- - int i;- for(i=1; i<poly->numVerts; i++)- min = cpfmin(min, cpvdot(n, verts[i]));- - return min - d;-}--// Returns true if the polygon contains the vertex.-static inline int-cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v)-{- cpPolyShapeAxis *axes = poly->tAxes;- - int i;- for(i=0; i<poly->numVerts; i++){- cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;- if(dist > 0.0) return 0;- }- - return 1;-}--// Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.-static inline int-cpPolyShapeContainsVertPartial(cpPolyShape *poly, cpVect v, cpVect n)-{- cpPolyShapeAxis *axes = poly->tAxes;- - int i;- for(i=0; i<poly->numVerts; i++){- if(cpvdot(axes[i].n, n) < 0.0f) continue;- cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;- if(dist > 0.0) return 0;- }- - return 1;-}
− chipmunk/cpShape.c
@@ -1,244 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <assert.h>-#include <stdio.h>--#include "chipmunk.h"-#include "math.h"--unsigned int SHAPE_ID_COUNTER = 0;--void-cpResetShapeIdCounter(void)-{- SHAPE_ID_COUNTER = 0;-}---cpShape*-cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)-{- shape->klass = klass;- - shape->id = SHAPE_ID_COUNTER;- SHAPE_ID_COUNTER++;- - assert(body != NULL);- shape->body = body;- - shape->e = 0.0f;- shape->u = 0.0f;- shape->surface_v = cpvzero;- - shape->collision_type = 0;- shape->group = 0;- shape->layers = 0xFFFF;- - shape->data = NULL;- - cpShapeCacheBB(shape);- - return shape;-}--void-cpShapeDestroy(cpShape *shape)-{- if(shape->klass->destroy) shape->klass->destroy(shape);-}--void-cpShapeFree(cpShape *shape)-{- if(shape) cpShapeDestroy(shape);- free(shape);-}--cpBB-cpShapeCacheBB(cpShape *shape)-{- cpBody *body = shape->body;- - shape->bb = shape->klass->cacheData(shape, body->p, body->rot);- return shape->bb;-}--int-cpShapePointQuery(cpShape *shape, cpVect p){- return shape->klass->pointQuery(shape, p);-}----cpCircleShape *-cpCircleShapeAlloc(void)-{- return (cpCircleShape *)calloc(1, sizeof(cpCircleShape));-}--static inline cpBB-bbFromCircle(const cpVect c, const cpFloat r)-{- return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);-}--static cpBB-cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)-{- cpCircleShape *circle = (cpCircleShape *)shape;- - circle->tc = cpvadd(p, cpvrotate(circle->c, rot));- return bbFromCircle(circle->tc, circle->r);-}--static int-cpCircleShapePointQuery(cpShape *shape, cpVect p){- cpCircleShape *circle = (cpCircleShape *)shape;- - cpFloat distSQ = cpvlengthsq(cpvsub(circle->tc, p));- return distSQ <= (circle->r*circle->r);-}--static const cpShapeClass circleClass = {- CP_CIRCLE_SHAPE,- cpCircleShapeCacheData,- NULL,- cpCircleShapePointQuery,-};--cpCircleShape *-cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)-{- circle->c = offset;- circle->r = radius;- - cpShapeInit((cpShape *)circle, &circleClass, body);- - return circle;-}--cpShape *-cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)-{- return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset);-}--cpSegmentShape *-cpSegmentShapeAlloc(void)-{- return (cpSegmentShape *)calloc(1, sizeof(cpSegmentShape));-}--static cpBB-cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)-{- cpSegmentShape *seg = (cpSegmentShape *)shape;- - seg->ta = cpvadd(p, cpvrotate(seg->a, rot));- seg->tb = cpvadd(p, cpvrotate(seg->b, rot));- seg->tn = cpvrotate(seg->n, rot);- - cpFloat l,r,s,t;- - if(seg->ta.x < seg->tb.x){- l = seg->ta.x;- r = seg->tb.x;- } else {- l = seg->tb.x;- r = seg->ta.x;- }- - if(seg->ta.y < seg->tb.y){- s = seg->ta.y;- t = seg->tb.y;- } else {- s = seg->tb.y;- t = seg->ta.y;- }- - cpFloat rad = seg->r;- return cpBBNew(l - rad, s - rad, r + rad, t + rad);-}--static int-cpSegmentShapePointQuery(cpShape *shape, cpVect p){- cpSegmentShape *seg = (cpSegmentShape *)shape;- - // Calculate normal distance from segment.- cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);- cpFloat dist = fabs(dn) - seg->r;- if(dist > 0.0f) return 0;- - // Calculate tangential distance along segment.- cpFloat dt = -cpvcross(seg->tn, p);- cpFloat dtMin = -cpvcross(seg->tn, seg->ta);- cpFloat dtMax = -cpvcross(seg->tn, seg->tb);- - // Decision tree to decide which feature of the segment to collide with.- if(dt <= dtMin){- if(dt < (dtMin - seg->r)){- return 0;- } else {- return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);- }- } else {- if(dt < dtMax){- return 1;- } else {- if(dt < (dtMax + seg->r)) {- return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);- } else {- return 0;- }- }- }- - return 1; -}--static const cpShapeClass segmentClass = {- CP_SEGMENT_SHAPE,- cpSegmentShapeCacheData,- NULL,- cpSegmentShapePointQuery,-};--cpSegmentShape *-cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r)-{- seg->a = a;- seg->b = b;- seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));- - seg->r = r;- - cpShapeInit((cpShape *)seg, &segmentClass, body);- - return seg;-}--cpShape*-cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r)-{- return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r);-}
− chipmunk/cpShape.h
@@ -1,141 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--// For determinism, you can reset the shape id counter.-void cpResetShapeIdCounter(void);--// Enumeration of shape types.-typedef enum cpShapeType{- CP_CIRCLE_SHAPE,- CP_SEGMENT_SHAPE,- CP_POLY_SHAPE,- CP_NUM_SHAPES-} cpShapeType;--// Forward declarations required for defining the cpShape and cpShapeClass structs.-struct cpShape;-struct cpShapeClass;--// Shape class. Holds function pointers and type data.-typedef struct cpShapeClass {- cpShapeType type;- - // Called by cpShapeCacheBB().- cpBB (*cacheData)(struct cpShape *shape, cpVect p, cpVect rot);- // Called to by cpShapeDestroy().- void (*destroy)(struct cpShape *shape);- - // called by cpShapeQueryPointQuery().- int (*pointQuery)(struct cpShape *shape, cpVect p);-} cpShapeClass;--// Basic shape struct that the others inherit from.-typedef struct cpShape{- // The "class" of a shape as defined above - const cpShapeClass *klass;- - // cpBody that the shape is attached to.- cpBody *body;-- // Cached BBox for the shape.- cpBB bb;- - // *** Surface properties.- - // Coefficient of restitution. (elasticity)- cpFloat e;- // Coefficient of friction.- cpFloat u;- // Surface velocity used when solving for friction.- cpVect surface_v;-- // *** User Definable Fields-- // User defined data pointer for the shape.- void *data;- - // User defined collision type for the shape.- unsigned int collision_type;- // User defined collision group for the shape.- unsigned int group;- // User defined layer bitmask for the shape.- unsigned int layers;- - // *** Internally Used Fields- - // Unique id used as the hash value.- unsigned int id;-} cpShape;--// Low level shape initialization func.-cpShape* cpShapeInit(cpShape *shape, const struct cpShapeClass *klass, cpBody *body);--// Basic destructor functions. (allocation functions are not shared)-void cpShapeDestroy(cpShape *shape);-void cpShapeFree(cpShape *shape);--// Cache the BBox of the shape.-cpBB cpShapeCacheBB(cpShape *shape);--// Test if a point lies within a shape.-int cpShapePointQuery(cpShape *shape, cpVect p);--// Test if a segment collides with a shape.-// Returns [0-1] if the segment collides and -1 otherwise.-// 0 would be a collision at point a, 1 would be a collision at point b.-//cpFloat cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b);---// Circle shape structure.-typedef struct cpCircleShape{- cpShape shape;- - // Center. (body space coordinates)- cpVect c;- // Radius.- cpFloat r;- - // Transformed center. (world space coordinates)- cpVect tc;-} cpCircleShape;--// Basic allocation functions for cpCircleShape.-cpCircleShape *cpCircleShapeAlloc(void);-cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);-cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);--// Segment shape structure.-typedef struct cpSegmentShape{- cpShape shape;- - // Endpoints and normal of the segment. (body space coordinates)- cpVect a, b, n;- // Radius of the segment. (Thickness)- cpFloat r;-- // Transformed endpoints and normal. (world space coordinates)- cpVect ta, tb, tn;-} cpSegmentShape;--// Basic allocation functions for cpSegmentShape.-cpSegmentShape* cpSegmentShapeAlloc(void);-cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius);-cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius);
− chipmunk/cpSpace.c
@@ -1,530 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <stdio.h>-#include <math.h>-#include <assert.h>--#include "chipmunk.h"--int cp_contact_persistence = 3;--// Equal function for contactSet.-static int-contactSetEql(void *ptr, void *elt)-{- cpShape **shapes = (cpShape **)ptr;- cpShape *a = shapes[0];- cpShape *b = shapes[1];- - cpArbiter *arb = (cpArbiter *)elt;- - return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));-}--// Transformation function for contactSet.-static void *-contactSetTrans(void *ptr, void *data)-{- cpShape **shapes = (cpShape **)ptr;- cpShape *a = shapes[0];- cpShape *b = shapes[1];- - cpSpace *space = (cpSpace *)data;- - return cpArbiterNew(a, b, space->stamp);-}--// Collision pair function wrapper struct.-typedef struct collFuncData {- cpCollFunc func;- void *data;-} collFuncData;--// Equals function for collFuncSet.-static int-collFuncSetEql(void *ptr, void *elt)-{- unsigned int *ids = (unsigned int *)ptr;- unsigned int a = ids[0];- unsigned int b = ids[1];- - cpCollPairFunc *pair = (cpCollPairFunc *)elt;- - return ((a == pair->a && b == pair->b) || (b == pair->a && a == pair->b));-}--// Transformation function for collFuncSet.-static void *-collFuncSetTrans(void *ptr, void *data)-{- unsigned int *ids = (unsigned int *)ptr;- collFuncData *funcData = (collFuncData *)data;-- cpCollPairFunc *pair = (cpCollPairFunc *)malloc(sizeof(cpCollPairFunc));- pair->a = ids[0];- pair->b = ids[1];- pair->func = funcData->func;- pair->data = funcData->data;-- return pair;-}--// Default collision pair function.-static int-alwaysCollide(cpShape *a, cpShape *b, cpContact *arr, int numCon, cpFloat normal_coef, void *data)-{- return 1;-}--// BBfunc callback for the spatial hash.-static cpBB-bbfunc(void *ptr)-{- cpShape *shape = (cpShape *)ptr;- return shape->bb;-}--// Iterator functions for destructors.-static void freeWrap(void *ptr, void *unused){ free( ptr);}-static void shapeFreeWrap(void *ptr, void *unused){ cpShapeFree((cpShape *) ptr);}-static void arbiterFreeWrap(void *ptr, void *unused){ cpArbiterFree((cpArbiter *)ptr);}-static void bodyFreeWrap(void *ptr, void *unused){ cpBodyFree((cpBody *) ptr);}-static void jointFreeWrap(void *ptr, void *unused){ cpJointFree((cpJoint *) ptr);}--cpSpace*-cpSpaceAlloc(void)-{- return (cpSpace *)calloc(1, sizeof(cpSpace));-}--#define DEFAULT_DIM_SIZE 100.0f-#define DEFAULT_COUNT 1000-#define DEFAULT_ITERATIONS 10-#define DEFAULT_ELASTIC_ITERATIONS 0--cpSpace*-cpSpaceInit(cpSpace *space)-{- space->iterations = DEFAULT_ITERATIONS;- space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;-// space->sleepTicks = 300;- - space->gravity = cpvzero;- space->damping = 1.0f;- - space->stamp = 0;-- space->staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, &bbfunc);- space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, &bbfunc);- - space->bodies = cpArrayNew(0);- space->arbiters = cpArrayNew(0);- space->contactSet = cpHashSetNew(0, contactSetEql, contactSetTrans);- - space->joints = cpArrayNew(0);- - cpCollPairFunc pairFunc = {0, 0, alwaysCollide, NULL};- space->defaultPairFunc = pairFunc;- space->collFuncSet = cpHashSetNew(0, collFuncSetEql, collFuncSetTrans);- space->collFuncSet->default_value = &space->defaultPairFunc;- - return space;-}--cpSpace*-cpSpaceNew(void)-{- return cpSpaceInit(cpSpaceAlloc());-}--void-cpSpaceDestroy(cpSpace *space)-{- cpSpaceHashFree(space->staticShapes);- cpSpaceHashFree(space->activeShapes);- - cpArrayFree(space->bodies);- - cpArrayFree(space->joints);- - if(space->contactSet)- cpHashSetEach(space->contactSet, &arbiterFreeWrap, NULL);- cpHashSetFree(space->contactSet);- cpArrayFree(space->arbiters);- - if(space->collFuncSet)- cpHashSetEach(space->collFuncSet, &freeWrap, NULL);- cpHashSetFree(space->collFuncSet);-}--void-cpSpaceFree(cpSpace *space)-{- if(space) cpSpaceDestroy(space);- free(space);-}--void-cpSpaceFreeChildren(cpSpace *space)-{- cpSpaceHashEach(space->staticShapes, &shapeFreeWrap, NULL);- cpSpaceHashEach(space->activeShapes, &shapeFreeWrap, NULL);- cpArrayEach(space->bodies, &bodyFreeWrap, NULL);- cpArrayEach(space->joints, &jointFreeWrap, NULL);-}--void-cpSpaceAddCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b,- cpCollFunc func, void *data)-{- unsigned int ids[] = {a, b};- unsigned int hash = CP_HASH_PAIR(a, b);- // Remove any old function so the new one will get added.- cpSpaceRemoveCollisionPairFunc(space, a, b);- - collFuncData funcData = {func, data};- cpHashSetInsert(space->collFuncSet, hash, ids, &funcData);-}--void-cpSpaceRemoveCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b)-{- unsigned int ids[] = {a, b};- unsigned int hash = CP_HASH_PAIR(a, b);- cpCollPairFunc *old_pair = (cpCollPairFunc *)cpHashSetRemove(space->collFuncSet, hash, ids);- free(old_pair);-}--void-cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data)-{- cpCollPairFunc pairFunc = {0, 0, (func ? func : alwaysCollide), (func ? data : NULL)};- space->defaultPairFunc = pairFunc;-}--void-cpSpaceAddShape(cpSpace *space, cpShape *shape)-{- cpSpaceHashInsert(space->activeShapes, shape, shape->id, shape->bb);-}--void-cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)-{- cpShapeCacheBB(shape);- cpSpaceHashInsert(space->staticShapes, shape, shape->id, shape->bb);-}--void-cpSpaceAddBody(cpSpace *space, cpBody *body)-{- cpArrayPush(space->bodies, body);-}--void-cpSpaceAddJoint(cpSpace *space, cpJoint *joint)-{- cpArrayPush(space->joints, joint);-}--void-cpSpaceRemoveShape(cpSpace *space, cpShape *shape)-{- cpSpaceHashRemove(space->activeShapes, shape, shape->id);-}--void-cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)-{- cpSpaceHashRemove(space->staticShapes, shape, shape->id);-}--void-cpSpaceRemoveBody(cpSpace *space, cpBody *body)-{- cpArrayDeleteObj(space->bodies, body);-}--void-cpSpaceRemoveJoint(cpSpace *space, cpJoint *joint)-{- cpArrayDeleteObj(space->joints, joint);-}--void-cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)-{- cpArray *bodies = space->bodies;- - for(int i=0; i<bodies->num; i++)- func((cpBody *)bodies->arr[i], data);-}--// Iterator function used for updating shape BBoxes.-static void-updateBBCache(void *ptr, void *unused)-{- cpShape *shape = (cpShape *)ptr;- cpShapeCacheBB(shape);-}--void-cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)-{- cpSpaceHashResize(space->staticShapes, dim, count);- cpSpaceHashRehash(space->staticShapes);-}--void-cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)-{- cpSpaceHashResize(space->activeShapes, dim, count);-}--void -cpSpaceRehashStatic(cpSpace *space)-{- cpSpaceHashEach(space->staticShapes, &updateBBCache, NULL);- cpSpaceHashRehash(space->staticShapes);-}--typedef struct pointQueryFuncPair {- cpSpacePointQueryFunc func;- void *data;-} pointQueryFuncPair;--static int -pointQueryHelper(void *point, void *obj, void *data)-{- cpShape *shape = (cpShape *)obj;- pointQueryFuncPair *pair = (pointQueryFuncPair *)data;- - if(cpShapePointQuery(shape, *((cpVect *)point)))- pair->func(shape, pair->data);- - return 1; // return value needed for historical reasons (value is ignored)-}--static void-pointQuery(cpSpaceHash *hash, cpVect point, cpSpacePointQueryFunc func, void *data)-{- pointQueryFuncPair pair = {func, data};- cpSpaceHashPointQuery(hash, point, pointQueryHelper, &pair);-}--void-cpSpaceShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data)-{- pointQuery(space->activeShapes, point, func, data);-}--void-cpSpaceStaticShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data)-{- pointQuery(space->staticShapes, point, func, data);-}--static inline int-queryReject(cpShape *a, cpShape *b)-{- return- // BBoxes must overlap- !cpBBintersects(a->bb, b->bb)- // Don't collide shapes attached to the same body.- || a->body == b->body- // Don't collide objects in the same non-zero group- || (a->group && b->group && a->group == b->group)- // Don't collide objects that don't share at least on layer.- || !(a->layers & b->layers);-}--// Callback from the spatial hash.-// TODO: Refactor this into separate functions?-static int-queryFunc(void *p1, void *p2, void *data)-{- // Cast the generic pointers from the spatial hash back to usefull types- cpShape *a = (cpShape *)p1;- cpShape *b = (cpShape *)p2;- cpSpace *space = (cpSpace *)data;- - // Reject any of the simple cases- if(queryReject(a,b)) return 0;- - // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )- if(a->klass->type > b->klass->type){- cpShape *temp = a;- a = b;- b = temp;- }- - // Find the collision pair function for the shapes.- unsigned int ids[] = {a->collision_type, b->collision_type};- unsigned int hash = CP_HASH_PAIR(a->collision_type, b->collision_type);- cpCollPairFunc *pairFunc = (cpCollPairFunc *)cpHashSetFind(space->collFuncSet, hash, ids);- if(!pairFunc->func) return 0; // A NULL pair function means don't collide at all.- - // Narrow-phase collision detection.- cpContact *contacts = NULL;- int numContacts = cpCollideShapes(a, b, &contacts);- if(!numContacts) return 0; // Shapes are not colliding.- - // The collision pair function requires objects to be ordered by their collision types.- cpShape *pair_a = a;- cpShape *pair_b = b;- cpFloat normal_coef = 1.0f;- - // Swap them if necessary.- if(pair_a->collision_type != pairFunc->a){- cpShape *temp = pair_a;- pair_a = pair_b;- pair_b = temp;- normal_coef = -1.0f;- }- - if(pairFunc->func(pair_a, pair_b, contacts, numContacts, normal_coef, pairFunc->data)){- // The collision pair function OKed the collision. Record the contact information.- - // Get an arbiter from space->contactSet for the two shapes.- // This is where the persistant contact magic comes from.- cpShape *shape_pair[] = {a, b};- cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->contactSet, CP_HASH_PAIR(a, b), shape_pair, space);- - // Timestamp the arbiter.- arb->stamp = space->stamp;- arb->a = a; arb->b = b; // TODO: Investigate why this is still necessary?- // Inject the new contact points into the arbiter.- cpArbiterInject(arb, contacts, numContacts);- - // Add the arbiter to the list of active arbiters.- cpArrayPush(space->arbiters, arb);- - return numContacts;- } else {- // The collision pair function rejected the collision.- - free(contacts);- return 0;- }-}--// Iterator for active/static hash collisions.-static void-active2staticIter(void *ptr, void *data)-{- cpShape *shape = (cpShape *)ptr;- cpSpace *space = (cpSpace *)data;- cpSpaceHashQuery(space->staticShapes, shape, shape->bb, &queryFunc, space);-}--// Hashset reject func to throw away old arbiters.-static int-contactSetReject(void *ptr, void *data)-{- cpArbiter *arb = (cpArbiter *)ptr;- cpSpace *space = (cpSpace *)data;- - if((space->stamp - arb->stamp) > cp_contact_persistence){- cpArbiterFree(arb);- return 0;- }- - return 1;-}--void-cpSpaceStep(cpSpace *space, cpFloat dt)-{- if(!dt) return; // prevents div by zero.- cpFloat dt_inv = 1.0f/dt;-- cpArray *bodies = space->bodies;- cpArray *arbiters = space->arbiters;- cpArray *joints = space->joints;- - // Empty the arbiter list.- cpHashSetReject(space->contactSet, &contactSetReject, space);- space->arbiters->num = 0;-- // Integrate positions.- for(int i=0; i<bodies->num; i++){- cpBody *body = (cpBody *)bodies->arr[i];- body->position_func(body, dt);- }- - // Pre-cache BBoxes and shape data.- cpSpaceHashEach(space->activeShapes, &updateBBCache, NULL);- - // Collide!- cpSpaceHashEach(space->activeShapes, &active2staticIter, space);- cpSpaceHashQueryRehash(space->activeShapes, &queryFunc, space);-- // Prestep the arbiters.- for(int i=0; i<arbiters->num; i++)- cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt_inv);-- // Prestep the joints.- for(int i=0; i<joints->num; i++){- cpJoint *joint = (cpJoint *)joints->arr[i];- joint->klass->preStep(joint, dt_inv);- }-- for(int i=0; i<space->elasticIterations; i++){- for(int j=0; j<arbiters->num; j++)- cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 1.0f);- - for(int j=0; j<joints->num; j++){- cpJoint *joint = (cpJoint *)joints->arr[j];- joint->klass->applyImpulse(joint);- }- }-- // Integrate velocities.- cpFloat damping = pow(1.0f/space->damping, -dt);- for(int i=0; i<bodies->num; i++){- cpBody *body = (cpBody *)bodies->arr[i];- body->velocity_func(body, space->gravity, damping, dt);- }-- for(int i=0; i<arbiters->num; i++)- cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i]);- - // Run the impulse solver.- for(int i=0; i<space->iterations; i++){- for(int j=0; j<arbiters->num; j++)- cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 0.0f);- - for(int j=0; j<joints->num; j++){- cpJoint *joint = (cpJoint *)joints->arr[j];- joint->klass->applyImpulse(joint);- }- }--// cpFloat dvsq = cpvdot(space->gravity, space->gravity);-// dvsq *= dt*dt * space->damping*space->damping;-// for(int i=0; i<bodies->num; i++)-// cpBodyMarkLowEnergy(bodies->arr[i], dvsq, space->sleepTicks);- - // Increment the stamp.- space->stamp++;-}
− chipmunk/cpSpace.h
@@ -1,120 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -// Number of frames that contact information should persist.-extern int cp_contact_persistence;--// User collision pair function.-typedef int (*cpCollFunc)(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data);--// Structure for holding collision pair function information.-// Used internally.-typedef struct cpCollPairFunc {- unsigned int a;- unsigned int b;- cpCollFunc func;- void *data;-} cpCollPairFunc;--typedef struct cpSpace{- // *** User definable fields- - // Number of iterations to use in the impulse solver to solve contacts.- int iterations;- - // Number of iterations to use in the impulse solver to solve elastic collisions.- int elasticIterations;- - // Default gravity to supply when integrating rigid body motions.- cpVect gravity;- - // Default damping to supply when integrating rigid body motions.- cpFloat damping;- - // *** Internally Used Fields- - // Time stamp. Is incremented on every call to cpSpaceStep().- int stamp;-- // The static and active shape spatial hashes.- cpSpaceHash *staticShapes;- cpSpaceHash *activeShapes;- - // List of bodies in the system.- cpArray *bodies;- // List of active arbiters for the impulse solver.- cpArray *arbiters;- // Persistant contact set.- cpHashSet *contactSet;- - // List of joints in the system.- cpArray *joints;- - // Set of collisionpair functions.- cpHashSet *collFuncSet;- // Default collision pair function.- cpCollPairFunc defaultPairFunc;-} cpSpace;--// Basic allocation/destruction functions.-cpSpace* cpSpaceAlloc(void);-cpSpace* cpSpaceInit(cpSpace *space);-cpSpace* cpSpaceNew(void);--void cpSpaceDestroy(cpSpace *space);-void cpSpaceFree(cpSpace *space);--// Convenience function. Frees all referenced entities. (bodies, shapes and joints)-void cpSpaceFreeChildren(cpSpace *space);--// Collision pair function management functions.-void cpSpaceAddCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b,- cpCollFunc func, void *data);-void cpSpaceRemoveCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b);-void cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data);--// Add and remove entities from the system.-void cpSpaceAddShape(cpSpace *space, cpShape *shape);-void cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);-void cpSpaceAddBody(cpSpace *space, cpBody *body);-void cpSpaceAddJoint(cpSpace *space, cpJoint *joint);--void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);-void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);-void cpSpaceRemoveBody(cpSpace *space, cpBody *body);-void cpSpaceRemoveJoint(cpSpace *space, cpJoint *joint);--// Point query callback function-typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);-void cpSpaceShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data);-void cpSpaceStaticShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data);--// Iterator function for iterating the bodies in a space.-typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);-void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);--// Spatial hash management functions.-void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);-void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);-void cpSpaceRehashStatic(cpSpace *space);--// Update the space.-void cpSpaceStep(cpSpace *space, cpFloat dt);
− chipmunk/cpSpaceHash.c
@@ -1,455 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include <stdlib.h>-#include <stdio.h>-#include <math.h>-#include <assert.h>--#include "chipmunk.h"-#include "prime.h"--static cpHandle*-cpHandleAlloc(void)-{- return (cpHandle *)malloc(sizeof(cpHandle));-}--static cpHandle*-cpHandleInit(cpHandle *hand, void *obj)-{- hand->obj = obj;- hand->retain = 0;- hand->stamp = 0;- - return hand;-}--static cpHandle*-cpHandleNew(void *obj)-{- return cpHandleInit(cpHandleAlloc(), obj);-}--static inline void-cpHandleRetain(cpHandle *hand)-{- hand->retain++;-}--static inline void-cpHandleFree(cpHandle *hand)-{- free(hand);-}--static inline void-cpHandleRelease(cpHandle *hand)-{- hand->retain--;- if(hand->retain == 0)- cpHandleFree(hand);-}---cpSpaceHash*-cpSpaceHashAlloc(void)-{- return (cpSpaceHash *)calloc(1, sizeof(cpSpaceHash));-}--// Frees the old table, and allocates a new one.-static void-cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)-{- free(hash->table);- - hash->numcells = numcells;- hash->table = (cpSpaceHashBin **)calloc(numcells, sizeof(cpSpaceHashBin *));-}--// Equality function for the handleset.-static int-handleSetEql(void *obj, void *elt)-{- cpHandle *hand = (cpHandle *)elt;- return (obj == hand->obj);-}--// Transformation function for the handleset.-static void *-handleSetTrans(void *obj, void *unused)-{- cpHandle *hand = cpHandleNew(obj);- cpHandleRetain(hand);- - return hand;-}--cpSpaceHash*-cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBFunc bbfunc)-{- cpSpaceHashAllocTable(hash, next_prime(numcells));- hash->celldim = celldim;- hash->bbfunc = bbfunc;- - hash->bins = NULL;- hash->handleSet = cpHashSetNew(0, &handleSetEql, &handleSetTrans);- - hash->stamp = 1;- - return hash;-}--cpSpaceHash*-cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc)-{- return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc);-}--static inline void-clearHashCell(cpSpaceHash *hash, int index)-{- cpSpaceHashBin *bin = hash->table[index];- while(bin){- cpSpaceHashBin *next = bin->next;- - // Release the lock on the handle.- cpHandleRelease(bin->handle);- // Recycle the bin.- bin->next = hash->bins;- hash->bins = bin;- - bin = next;- }- - hash->table[index] = NULL;-}--// Clear all cells in the hashtable.-static void-clearHash(cpSpaceHash *hash)-{- for(int i=0; i<hash->numcells; i++)- clearHashCell(hash, i);-}--// Free the recycled hash bins.-static void-freeBins(cpSpaceHash *hash)-{- cpSpaceHashBin *bin = hash->bins;- while(bin){- cpSpaceHashBin *next = bin->next;- free(bin);- bin = next;- }-}--// Hashset iterator function to free the handles.-static void-handleFreeWrap(void *elt, void *unused)-{- cpHandle *hand = (cpHandle *)elt;- cpHandleFree(hand);-}--void-cpSpaceHashDestroy(cpSpaceHash *hash)-{- clearHash(hash);- freeBins(hash);- - // Free the handles.- cpHashSetEach(hash->handleSet, &handleFreeWrap, NULL);- cpHashSetFree(hash->handleSet);- - free(hash->table);-}--void-cpSpaceHashFree(cpSpaceHash *hash)-{- if(!hash) return;- cpSpaceHashDestroy(hash);- free(hash);-}--void-cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)-{- // Clear the hash to release the old handle locks.- clearHash(hash);- - hash->celldim = celldim;- cpSpaceHashAllocTable(hash, next_prime(numcells));-}--// Return true if the chain contains the handle.-static inline int-containsHandle(cpSpaceHashBin *bin, cpHandle *hand)-{- while(bin){- if(bin->handle == hand) return 1;- bin = bin->next;- }- - return 0;-}--// Get a recycled or new bin.-static inline cpSpaceHashBin *-getEmptyBin(cpSpaceHash *hash)-{- cpSpaceHashBin *bin = hash->bins;- - // Make a new one if necessary.- if(bin == NULL) return (cpSpaceHashBin *)malloc(sizeof(cpSpaceHashBin));-- hash->bins = bin->next;- return bin;-}--// The hash function itself.-static inline unsigned int-hash_func(unsigned int x, unsigned int y, unsigned int n)-{- return (x*2185031351ul ^ y*4232417593ul) % n;-}--static inline void-hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)-{- // Find the dimensions in cell coordinates.- cpFloat dim = hash->celldim;- int l = bb.l/dim;- int r = bb.r/dim;- int b = bb.b/dim;- int t = bb.t/dim;- - int n = hash->numcells;- for(int i=l; i<=r; i++){- for(int j=b; j<=t; j++){- int index = hash_func(i,j,n);- cpSpaceHashBin *bin = hash->table[index];- - // Don't add an object twice to the same cell.- if(containsHandle(bin, hand)) continue;-- cpHandleRetain(hand);- // Insert a new bin for the handle in this cell.- cpSpaceHashBin *newBin = getEmptyBin(hash);- newBin->handle = hand;- newBin->next = bin;- hash->table[index] = newBin;- }- }-}--void-cpSpaceHashInsert(cpSpaceHash *hash, void *obj, unsigned int id, cpBB bb)-{- cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, id, obj, NULL);- hashHandle(hash, hand, bb);-}--void-cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, unsigned int id)-{- cpHandle *hand = (cpHandle *)cpHashSetFind(hash->handleSet, id, obj);- hashHandle(hash, hand, hash->bbfunc(obj));-}--// Hashset iterator function for rehashing the spatial hash. (hash hash hash hash?)-static void-handleRehashHelper(void *elt, void *data)-{- cpHandle *hand = (cpHandle *)elt;- cpSpaceHash *hash = (cpSpaceHash *)data;- - hashHandle(hash, hand, hash->bbfunc(hand->obj));-}--void-cpSpaceHashRehash(cpSpaceHash *hash)-{- clearHash(hash);- - // Rehash all of the handles.- cpHashSetEach(hash->handleSet, &handleRehashHelper, hash);-}--void-cpSpaceHashRemove(cpSpaceHash *hash, void *obj, unsigned int id)-{- cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, id, obj);- - if(hand){- hand->obj = NULL;- cpHandleRelease(hand);- }-}--// Used by the cpSpaceHashEach() iterator.-typedef struct eachPair {- cpSpaceHashIterator func;- void *data;-} eachPair;--// Calls the user iterator function. (Gross I know.)-static void-eachHelper(void *elt, void *data)-{- cpHandle *hand = (cpHandle *)elt;- eachPair *pair = (eachPair *)data;- - pair->func(hand->obj, pair->data);-}--// Iterate over the objects in the spatial hash.-void-cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)-{- // Bundle the callback up to send to the hashset iterator.- eachPair pair = {func, data};- - cpHashSetEach(hash->handleSet, &eachHelper, &pair);-}--// Calls the callback function for the objects in a given chain.-static inline void-query(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashQueryFunc func, void *data)-{- for(; bin; bin = bin->next){- cpHandle *hand = bin->handle;- void *other = hand->obj;- - // Skip over certain conditions- if(- // Have we already tried this pair in this query?- hand->stamp == hash->stamp- // Is obj the same as other?- || obj == other - // Has other been removed since the last rehash?- || !other- ) continue;- - func(obj, other, data);-- // Stamp that the handle was checked already against this object.- hand->stamp = hash->stamp;- }-}--void-cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data)-{- cpFloat dim = hash->celldim;- int index = hash_func((int)(point.x/dim), (int)(point.y/dim), hash->numcells);- - query(hash, hash->table[index], &point, func, data);-- // Increment the stamp.- // Only one cell is checked, but query() requires it anyway.- hash->stamp++;-}--void-cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data)-{- // Get the dimensions in cell coordinates.- cpFloat dim = hash->celldim;- int l = bb.l/dim;- int r = bb.r/dim;- int b = bb.b/dim;- int t = bb.t/dim;- - int n = hash->numcells;- - // Iterate over the cells and query them.- for(int i=l; i<=r; i++){- for(int j=b; j<=t; j++){- int index = hash_func(i,j,n);- query(hash, hash->table[index], obj, func, data);- }- }- - // Increment the stamp.- hash->stamp++;-}--// Similar to struct eachPair above.-typedef struct queryRehashPair {- cpSpaceHash *hash;- cpSpaceHashQueryFunc func;- void *data;-} queryRehashPair;--// Hashset iterator func used with cpSpaceHashQueryRehash().-static void-handleQueryRehashHelper(void *elt, void *data)-{- cpHandle *hand = (cpHandle *)elt;- - // Unpack the user callback data.- queryRehashPair *pair = (queryRehashPair *)data;- cpSpaceHash *hash = pair->hash;- cpSpaceHashQueryFunc func = pair->func;-- cpFloat dim = hash->celldim;- int n = hash->numcells;-- void *obj = hand->obj;- cpBB bb = hash->bbfunc(obj);-- int l = bb.l/dim;- int r = bb.r/dim;- int b = bb.b/dim;- int t = bb.t/dim;-- for(int i=l; i<=r; i++){- for(int j=b; j<=t; j++){- int index = hash_func(i,j,n);- cpSpaceHashBin *bin = hash->table[index];- - if(containsHandle(bin, hand)) continue;- query(hash, bin, obj, func, pair->data);- - cpHandleRetain(hand);- cpSpaceHashBin *newBin = getEmptyBin(hash);- newBin->handle = hand;- newBin->next = bin;- hash->table[index] = newBin;- }- }- - // Increment the stamp for each object we hash.- hash->stamp++;-}--void-cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)-{- clearHash(hash);-- queryRehashPair pair = {hash, func, data};- cpHashSetEach(hash->handleSet, &handleQueryRehashHelper, &pair);-}
− chipmunk/cpSpaceHash.h
@@ -1,100 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */--// The spatial hash is Chipmunk's default (and currently only) spatial index type.-// Based on a chained hash table.--// Used internally to track objects added to the hash-typedef struct cpHandle{- // Pointer to the object- void *obj;- // Retain count- int retain;- // Query stamp. Used to make sure two objects- // aren't identified twice in the same query.- int stamp;-} cpHandle;--// Linked list element for in the chains.-typedef struct cpSpaceHashBin{- cpHandle *handle;- struct cpSpaceHashBin *next;-} cpSpaceHashBin;--// BBox callback. Called whenever the hash needs a bounding box from an object.-typedef cpBB (*cpSpaceHashBBFunc)(void *obj);--typedef struct cpSpaceHash{- // Number of cells in the table.- int numcells;- // Dimentions of the cells.- cpFloat celldim;- - // BBox callback.- cpSpaceHashBBFunc bbfunc;-- // Hashset of all the handles.- cpHashSet *handleSet;- - cpSpaceHashBin **table;- // List of recycled bins.- cpSpaceHashBin *bins;-- // Incremented on each query. See cpHandle.stamp.- int stamp;-} cpSpaceHash;--//Basic allocation/destruction functions.-cpSpaceHash *cpSpaceHashAlloc(void);-cpSpaceHash *cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);-cpSpaceHash *cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);--void cpSpaceHashDestroy(cpSpaceHash *hash);-void cpSpaceHashFree(cpSpaceHash *hash);--// Resize the hashtable. (Does not rehash! You must call cpSpaceHashRehash() if needed.)-void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);--// Add an object to the hash.-void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, unsigned int id, cpBB bb);-// Remove an object from the hash.-void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, unsigned int id);--// Iterator function-typedef void (*cpSpaceHashIterator)(void *obj, void *data);-// Iterate over the objects in the hash.-void cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data);--// Rehash the contents of the hash.-void cpSpaceHashRehash(cpSpaceHash *hash);-// Rehash only a specific object.-void cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, unsigned int id);--// Query callback.-typedef int (*cpSpaceHashQueryFunc)(void *obj1, void *obj2, void *data);-// Point query the hash. A reference to the query point is passed as obj1 to the query callback.-void cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data);-// Query the hash for a given BBox.-void cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);-// Run a query for the object, then insert it. (Optimized case)-void cpSpaceHashQueryInsert(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);-// Rehashes while querying for each object. (Optimized case) -void cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data);
− chipmunk/cpVect.c
@@ -1,63 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -#include "stdio.h"-#include "math.h"--#include "chipmunk.h"--cpFloat-cpvlength(const cpVect v)-{- return sqrtf( cpvdot(v, v) );-}--cpFloat-cpvlengthsq(const cpVect v)-{- return cpvdot(v, v);-}--cpVect-cpvnormalize(const cpVect v)-{- return cpvmult( v, 1.0f/cpvlength(v) );-}--cpVect-cpvforangle(const cpFloat a)-{- return cpv(cos(a), sin(a));-}--cpFloat-cpvtoangle(const cpVect v)-{- return atan2(v.y, v.x);-}--char*-cpvstr(const cpVect v)-{- static char str[256];- sprintf(str, "(% .3f, % .3f)", v.x, v.y);- return str;-}
− chipmunk/cpVect.h
@@ -1,106 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -typedef struct cpVect{- cpFloat x,y;-} cpVect;--static const cpVect cpvzero={0.0f,0.0f};--static inline cpVect-cpv(const cpFloat x, const cpFloat y)-{- cpVect v = {x, y};- return v;-}--static inline cpVect-cpvadd(const cpVect v1, const cpVect v2)-{- return cpv(v1.x + v2.x, v1.y + v2.y);-}--static inline cpVect-cpvneg(const cpVect v)-{- return cpv(-v.x, -v.y);-}--static inline cpVect-cpvsub(const cpVect v1, const cpVect v2)-{- return cpv(v1.x - v2.x, v1.y - v2.y);-}--static inline cpVect-cpvmult(const cpVect v, const cpFloat s)-{- return cpv(v.x*s, v.y*s);-}--static inline cpFloat-cpvdot(const cpVect v1, const cpVect v2)-{- return v1.x*v2.x + v1.y*v2.y;-}--static inline cpFloat-cpvcross(const cpVect v1, const cpVect v2)-{- return v1.x*v2.y - v1.y*v2.x;-}--static inline cpVect-cpvperp(const cpVect v)-{- return cpv(-v.y, v.x);-}--static inline cpVect-cpvrperp(const cpVect v)-{- return cpv(v.y, -v.x);-}--static inline cpVect-cpvproject(const cpVect v1, const cpVect v2)-{- return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));-}--static inline cpVect-cpvrotate(const cpVect v1, const cpVect v2)-{- return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);-}--static inline cpVect-cpvunrotate(const cpVect v1, const cpVect v2)-{- return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);-}--cpFloat cpvlength(const cpVect v);-cpFloat cpvlengthsq(const cpVect v); // no sqrt() call-cpVect cpvnormalize(const cpVect v);-cpVect cpvforangle(const cpFloat a); // convert radians to a normalized vector-cpFloat cpvtoangle(const cpVect v); // convert a vector to radians-char *cpvstr(const cpVect v); // get a string representation of a vector
− chipmunk/prime.h
@@ -1,68 +0,0 @@-/* Copyright (c) 2007 Scott Lembcke- * - * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- * - * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE- * SOFTWARE.- */- -// Used for resizing hash tables.-// Values approximately double.--static int primes[] = {- 5, //2^2 + 1- 11, //2^3 + 3- 17, //2^4 + 1- 37, //2^5 + 5- 67, //2^6 + 3- 131, //2^7 + 3- 257, //2^8 + 1- 521, //2^9 + 9- 1031, //2^10 + 7- 2053, //2^11 + 5- 4099, //2^12 + 3- 8209, //2^13 + 17- 16411, //2^14 + 27- 32771, //2^15 + 3- 65537, //2^16 + 1- 131101, //2^17 + 29- 262147, //2^18 + 3- 524309, //2^19 + 21- 1048583, //2^20 + 7- 2097169, //2^21 + 17- 4194319, //2^22 + 15- 8388617, //2^23 + 9- 16777259, //2^24 + 43- 33554467, //2^25 + 35- 67108879, //2^26 + 15- 134217757, //2^27 + 29- 268435459, //2^28 + 3- 536870923, //2^29 + 11- 1073741827, //2^30 + 3- 0,-};--static int-next_prime(int n)-{- int i = 0;- while(n > primes[i]){- i++;- assert(primes[i]); // realistically this should never happen- }- - return primes[i];-}