Portability | portable (needs FFI) |
---|---|
Stability | provisional |
Maintainer | felipe.lessa@gmail.com |
The space, where the simulation happens and the various entities interact.
- data Space
- newSpace :: IO Space
- freeSpace :: Space -> IO ()
- class Entity a where
- newtype StaticShape = Static {}
- type Iterations = CInt
- iterations :: Space -> StateVar Iterations
- type ElasticIterations = CInt
- elasticIterations :: Space -> StateVar ElasticIterations
- type Gravity = Vector
- gravity :: Space -> StateVar Gravity
- damping :: Space -> StateVar Damping
- type TimeStamp = CInt
- timeStamp :: Space -> GettableStateVar TimeStamp
- resizeStaticHash :: Space -> Distance -> CInt -> IO ()
- resizeActiveHash :: Space -> Distance -> CInt -> IO ()
- rehashStatic :: Space -> IO ()
- spaceQuery :: Space -> Position -> Layers -> Group -> (Shape -> IO ()) -> IO ()
- spaceQueryList :: Space -> Position -> Layers -> Group -> IO [Shape]
- step :: Space -> Time -> IO ()
Callbacks problem
We have a huge problem for callbacks: we *have* to call
freeHaskellFunPtr
to every Haskell function that was
passed via FFI to C code after we don't need them.
However, the ForeignPtr
that the Space
has can
portably have finalizers only in the FFI, never in the
Haskell land, so we can't run the Haskell function
freeHaskellFunPtr
from a ForeignPtr
finalizer.
There are two options:
- Use Foreign.Concurrent to add a Haskell finalizer. Under GHC this is great and adds no overhead (maybe there's even less overhead than calling a C function). However Foreign.Concurrent is not portable and works only under GHC.
- Require that users of the library (you) call a finalizer function when they plan to stop using the space. This adds some burden to the programmer and somehow defeats the purpose of the GC, however it works everywhere.
As this is a library that intends to be as portable as possible (like Chipmunk itself), of course I chose to follow the second path. This means that your code will run unchanged on every Haskell environment supporting FFI with C99, but also that you have to take care to avoid memory leaks. You've been warned! :)
Note: callbacks are implemented in Physics.Hipmunk.Callbacks module.
Creating spaces and adding entities
A space is where the simulation really occurs. You add
bodies, shapes and constraints to a space and then step
it
to update it as whole.
freeSpace :: Space -> IO ()Source
freeSpace sp
frees some memory resources that can't
be automatically deallocated in a portable way.
The space sp
then becomes invalid and should
not be used (passing sp
to any other function,
including freeSpace
, results in undefined behavior).
Type class implemented by entities that can be added to a space.
newtype StaticShape Source
A StaticShape
is a Shape
container that, when added
to a space via spaceAdd
, is added to the static
list of shapes.
A static shape is one assumed not to move. If you move
a static shape after adding it, then you need to rehashStatic
.
You should not add the same shape as active and static, nor should you add as active and try to remove as static or vice versa.
Properties
Iterations
type Iterations = CIntSource
The number of iterations to use when solving constraints. (default is 10).
Elastic iterations
type ElasticIterations = CIntSource
The number of elastic iterations to use when solving
constraints. If 0
, then old-style elastic code is used.
(default is 0).
This property is deprecated. You should no longer need to set any value other than the default.
Gravity
Damping
damping :: Space -> StateVar DampingSource
The amount of viscous damping applied to the system. (default is 1)
Time stamp
The time stamp of the simulation, increased in 1
every time step
is called.
Spatial hashes
resizes the static
hash of space resizeStaticHash
sp dim countsp
to have hash cells of size dim
and suggested minimum number of cells count
.
works the same way
but modifying the active hash of the space.
resizeActiveHash
sp dim count
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 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.
rehashStatic :: Space -> IO ()Source
Rehashes the shapes in the static spatial hash. You only need to call this if you move one of the static shapes.
Point query
Point querying uses the spatial hashes to find out in what shapes a point is contained. It is useful, for example, to know if a shape was clicked by the user.
spaceQuery :: Space -> Position -> Layers -> Group -> (Shape -> IO ()) -> IO ()Source
spaceQuery sp pos l g cb
will call cb
for every
shape that
- Contains point
pos
(in world's coordinates). - Isn't of the same group as
g
. - Shares at least one 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).
spaceQueryList :: Space -> Position -> Layers -> Group -> IO [Shape]Source
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.