{-# LINE 1 "Physics/Hipmunk/Unsafe.hsc" #-}
-----------------------------------------------------------------------------
{-# LINE 2 "Physics/Hipmunk/Unsafe.hsc" #-}
-- |
-- Module      :  Physics/Hipmunk/Unsafe.hsc
-- Copyright   :  (c) 2008-2010 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

{-# LINE 31 "Physics/Hipmunk/Unsafe.hsc" #-}

import Physics.Hipmunk.Common
import Physics.Hipmunk.Internal
import Physics.Hipmunk.Shape

-- | @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 #-}