packages feed

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 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];-}