-------------------------------------------------------------------------------- -- | -- Module : Graphics.Rendering.OpenGL.GLU.NURBS -- Copyright : (c) Sven Panne 2002-2009 -- License : BSD-style (see the file libraries/OpenGL/LICENSE) -- -- Maintainer : sven.panne@aedion.de -- Stability : stable -- Portability : portable -- -- This module corresponds to chapter 7 (NURBS) of the GLU specs. -- -------------------------------------------------------------------------------- module Graphics.Rendering.OpenGL.GLU.NURBS ( NURBSObj, withNURBSObj, NURBSBeginCallback, withNURBSBeginCallback, NURBSVertexCallback, withNURBSVertexCallback, NURBSNormalCallback, withNURBSNormalCallback, NURBSColorCallback, withNURBSColorCallback, NURBSEndCallback, withNURBSEndCallback, checkForNURBSError, nurbsBeginEndCurve, nurbsCurve, nurbsBeginEndSurface, nurbsSurface, TrimmingPoint, nurbsBeginEndTrim, pwlCurve, trimmingCurve, NURBSMode(..), setNURBSMode, setNURBSCulling, SamplingMethod(..), setSamplingMethod, loadSamplingMatrices, DisplayMode'(..), setDisplayMode' ) where import Control.Monad ( unless ) import Foreign.Marshal.Array ( withArray ) import Foreign.Ptr ( Ptr, nullPtr, castPtr, FunPtr, freeHaskellFunPtr ) import Foreign.Storable ( Storable(..) ) import Graphics.Rendering.OpenGL.GL.BasicTypes ( GLenum, GLint, GLfloat, Capability ) import Graphics.Rendering.OpenGL.GL.Capability ( marshalCapability ) import Graphics.Rendering.OpenGL.GL.ControlPoint import Graphics.Rendering.OpenGL.GL.CoordTrans ( Position(..), Size(..), MatrixOrder(ColumnMajor), MatrixComponent, Matrix(..) ) import Graphics.Rendering.OpenGL.GL.Exception ( bracket, bracket_ ) import Graphics.Rendering.OpenGL.GL.GLboolean ( marshalGLboolean ) import Graphics.Rendering.OpenGL.GL.PrimitiveMode ( unmarshalPrimitiveMode ) import Graphics.Rendering.OpenGL.GL.BeginEnd ( PrimitiveMode ) import Graphics.Rendering.OpenGL.GL.VertexSpec ( Vertex2, Vertex3, Normal3, Color4 ) import Graphics.Rendering.OpenGL.GLU.ErrorsInternal ( recordErrorCode, recordOutOfMemory ) -------------------------------------------------------------------------------- data NURBSCallback = Error | Begin | Vertex | Normal | Color | TextureCoord | End | BeginData | VertexData | NormalData | ColorData | TextureCoordData | EndData marshalNURBSCallback :: NURBSCallback -> GLenum marshalNURBSCallback x = case x of Error -> 100103 Begin -> 100164 Vertex -> 100165 Normal -> 100166 Color -> 100167 TextureCoord -> 100168 End -> 100169 BeginData -> 100170 VertexData -> 100171 NormalData -> 100172 ColorData -> 100173 TextureCoordData -> 100174 EndData -> 100175 -------------------------------------------------------------------------------- -- chapter 7.1: The NURBS Object -- an opaque pointer to a NURBS object newtype NURBSObj = NURBSObj (Ptr NURBSObj) isNullNURBSObj :: NURBSObj -> Bool isNullNURBSObj (NURBSObj ptr) = ptr == nullPtr withNURBSObj :: a -> (NURBSObj -> IO a) -> IO a withNURBSObj failureValue action = bracket gluNewNurbsRenderer safeDeleteNurbsRenderer (\nurbsObj -> if isNullNURBSObj nurbsObj then do recordOutOfMemory return failureValue else action nurbsObj) foreign import CALLCONV safe "gluNewNurbsRenderer" gluNewNurbsRenderer :: IO NURBSObj safeDeleteNurbsRenderer :: NURBSObj -> IO () safeDeleteNurbsRenderer nurbsObj = unless (isNullNURBSObj nurbsObj) $ gluDeleteNurbsRenderer nurbsObj foreign import CALLCONV safe "gluDeleteNurbsRenderer" gluDeleteNurbsRenderer :: NURBSObj -> IO () -------------------------------------------------------------------------------- -- chapter 7.2: Callbacks (begin) type NURBSBeginCallback = PrimitiveMode -> IO () type BeginCallback' = GLenum -> IO () withNURBSBeginCallback :: NURBSObj -> NURBSBeginCallback -> IO a -> IO a withNURBSBeginCallback nurbsObj beginCallback action = bracket (makeBeginCallback (beginCallback . unmarshalPrimitiveMode)) freeHaskellFunPtr $ \callbackPtr -> do setBeginCallback nurbsObj (marshalNURBSCallback Begin) callbackPtr action foreign import CALLCONV "wrapper" makeBeginCallback :: BeginCallback' -> IO (FunPtr BeginCallback') foreign import CALLCONV safe "gluNurbsCallback" setBeginCallback :: NURBSObj -> GLenum -> FunPtr BeginCallback' -> IO () -------------------------------------------------------------------------------- -- chapter 7.2: Callbacks (vertex) type NURBSVertexCallback = Vertex3 GLfloat -> IO () type VertexCallback' = Ptr (Vertex3 GLfloat) -> IO () withNURBSVertexCallback :: NURBSObj -> NURBSVertexCallback -> IO a -> IO a withNURBSVertexCallback nurbsObj vertexCallback action = bracket (makeVertexCallback (\p -> peek p >>= vertexCallback)) freeHaskellFunPtr $ \callbackPtr -> do setVertexCallback nurbsObj (marshalNURBSCallback Vertex) callbackPtr action foreign import CALLCONV "wrapper" makeVertexCallback :: VertexCallback' -> IO (FunPtr VertexCallback') foreign import CALLCONV safe "gluNurbsCallback" setVertexCallback :: NURBSObj -> GLenum -> FunPtr VertexCallback' -> IO () -------------------------------------------------------------------------------- -- chapter 7.2: Callbacks (normal) type NURBSNormalCallback = Normal3 GLfloat -> IO () type NormalCallback' = Ptr (Normal3 GLfloat) -> IO () withNURBSNormalCallback :: NURBSObj -> NURBSNormalCallback -> IO a -> IO a withNURBSNormalCallback nurbsObj normalCallback action = bracket (makeNormalCallback (\p -> peek p >>= normalCallback)) freeHaskellFunPtr $ \callbackPtr -> do setNormalCallback nurbsObj (marshalNURBSCallback Normal) callbackPtr action foreign import CALLCONV "wrapper" makeNormalCallback :: NormalCallback' -> IO (FunPtr NormalCallback') foreign import CALLCONV safe "gluNurbsCallback" setNormalCallback :: NURBSObj -> GLenum -> FunPtr NormalCallback' -> IO () -------------------------------------------------------------------------------- -- chapter 7.2: Callbacks (color) type NURBSColorCallback = Color4 GLfloat -> IO () type ColorCallback' = Ptr (Color4 GLfloat) -> IO () withNURBSColorCallback :: NURBSObj -> NURBSColorCallback -> IO a -> IO a withNURBSColorCallback nurbsObj colorCallback action = bracket (makeColorCallback (\p -> peek p >>= colorCallback)) freeHaskellFunPtr $ \callbackPtr -> do setColorCallback nurbsObj (marshalNURBSCallback Color) callbackPtr action foreign import CALLCONV "wrapper" makeColorCallback :: ColorCallback' -> IO (FunPtr ColorCallback') foreign import CALLCONV safe "gluNurbsCallback" setColorCallback :: NURBSObj -> GLenum -> FunPtr ColorCallback' -> IO () -------------------------------------------------------------------------------- -- chapter 7.2: Callbacks (end) type NURBSEndCallback = IO () withNURBSEndCallback :: NURBSObj -> NURBSEndCallback -> IO a -> IO a withNURBSEndCallback nurbsObj endCallback action = bracket (makeEndCallback endCallback) freeHaskellFunPtr $ \callbackPtr -> do setEndCallback nurbsObj (marshalNURBSCallback End) callbackPtr action foreign import CALLCONV "wrapper" makeEndCallback :: NURBSEndCallback -> IO (FunPtr NURBSEndCallback) foreign import CALLCONV safe "gluNurbsCallback" setEndCallback :: NURBSObj -> GLenum -> FunPtr NURBSEndCallback -> IO () -------------------------------------------------------------------------------- -- chapter 7.2: Callbacks (error) type ErrorCallback = GLenum -> IO () withErrorCallback :: NURBSObj -> ErrorCallback -> IO a -> IO a withErrorCallback nurbsObj errorCallback action = bracket (makeErrorCallback errorCallback) freeHaskellFunPtr $ \callbackPtr -> do setErrorCallback nurbsObj (marshalNURBSCallback Error) callbackPtr action foreign import CALLCONV "wrapper" makeErrorCallback :: ErrorCallback -> IO (FunPtr ErrorCallback) foreign import CALLCONV safe "gluNurbsCallback" setErrorCallback :: NURBSObj -> GLenum -> FunPtr ErrorCallback -> IO () checkForNURBSError :: NURBSObj -> IO a -> IO a checkForNURBSError nurbsObj = withErrorCallback nurbsObj recordErrorCode -------------------------------------------------------------------------------- -- chapter 7.3: NURBS Curves nurbsBeginEndCurve :: NURBSObj -> IO a -> IO a nurbsBeginEndCurve nurbsObj = bracket_ (gluBeginCurve nurbsObj) (gluEndCurve nurbsObj) foreign import CALLCONV safe "gluBeginCurve" gluBeginCurve :: NURBSObj -> IO () nurbsCurve :: ControlPoint c => NURBSObj -> GLint -> Ptr GLfloat -> GLint -> Ptr (c GLfloat) -> GLint -> IO () nurbsCurve nurbsObj knotCount knots stride control order = gluNurbsCurve nurbsObj knotCount knots stride (castPtr control) order (map1Target (pseudoPeek control)) pseudoPeek :: Ptr (c GLfloat) -> c GLfloat pseudoPeek _ = undefined foreign import CALLCONV safe "gluNurbsCurve" gluNurbsCurve :: NURBSObj -> GLint -> Ptr GLfloat -> GLint -> Ptr GLfloat -> GLint -> GLenum -> IO () foreign import CALLCONV safe "gluEndCurve" gluEndCurve :: NURBSObj -> IO () -------------------------------------------------------------------------------- -- chapter 7.4: NURBS Surfaces nurbsBeginEndSurface :: NURBSObj -> IO a -> IO a nurbsBeginEndSurface nurbsObj = bracket_ (gluBeginSurface nurbsObj) (gluEndSurface nurbsObj) foreign import CALLCONV safe "gluBeginSurface" gluBeginSurface :: NURBSObj -> IO () nurbsSurface :: ControlPoint c => NURBSObj -> GLint -> Ptr GLfloat -> GLint -> Ptr GLfloat -> GLint -> GLint -> Ptr (c GLfloat) -> GLint -> GLint -> IO () nurbsSurface nurbsObj sKnotCount sKnots tKnotCount tKnots sStride tStride control sOrder tOrder = gluNurbsSurface nurbsObj sKnotCount sKnots tKnotCount tKnots sStride tStride (castPtr control) sOrder tOrder (map2Target (pseudoPeek control)) foreign import CALLCONV safe "gluNurbsSurface" gluNurbsSurface :: NURBSObj -> GLint -> Ptr GLfloat -> GLint -> Ptr GLfloat -> GLint -> GLint -> Ptr GLfloat -> GLint -> GLint -> GLenum -> IO () foreign import CALLCONV safe "gluEndSurface" gluEndSurface :: NURBSObj -> IO () -------------------------------------------------------------------------------- -- chapter 7.5: Trimming class TrimmingPoint p where trimmingTarget :: p GLfloat -> GLenum instance TrimmingPoint Vertex2 where trimmingTarget = marshalNURBSTrim . const Map1Trim2 instance TrimmingPoint Vertex3 where trimmingTarget = marshalNURBSTrim . const Map1Trim3 data NURBSTrim = Map1Trim2 | Map1Trim3 marshalNURBSTrim :: NURBSTrim -> GLenum marshalNURBSTrim x = case x of Map1Trim2 -> 100210 Map1Trim3 -> 100211 nurbsBeginEndTrim :: NURBSObj -> IO a -> IO a nurbsBeginEndTrim nurbsObj = bracket_ (gluBeginTrim nurbsObj) (gluEndTrim nurbsObj) foreign import CALLCONV safe "gluBeginTrim" gluBeginTrim :: NURBSObj -> IO () pwlCurve :: TrimmingPoint p => NURBSObj -> GLint -> Ptr (p GLfloat) -> GLint -> IO () pwlCurve nurbsObj count points stride = gluPwlCurve nurbsObj count (castPtr points) stride (trimmingTarget (pseudoPeek points)) foreign import CALLCONV safe "gluPwlCurve" gluPwlCurve :: NURBSObj -> GLint -> Ptr GLfloat -> GLint -> GLenum -> IO () trimmingCurve :: TrimmingPoint c => NURBSObj -> GLint -> Ptr GLfloat -> GLint -> Ptr (c GLfloat) -> GLint -> IO () trimmingCurve nurbsObj knotCount knots stride control order = gluNurbsCurve nurbsObj knotCount knots stride (castPtr control) order (trimmingTarget (pseudoPeek control)) foreign import CALLCONV safe "gluEndTrim" gluEndTrim :: NURBSObj -> IO () -------------------------------------------------------------------------------- -- chapter 7.6: NURBS Properties data NURBSProperty = AutoLoadMatrix | Culling | ParametricTolerance | SamplingTolerance | DisplayMode' | SamplingMethod | UStep | VStep | NURBSMode marshalNURBSProperty :: NURBSProperty -> GLenum marshalNURBSProperty x = case x of AutoLoadMatrix -> 100200 Culling -> 100201 ParametricTolerance -> 100202 SamplingTolerance -> 100203 DisplayMode' -> 100204 SamplingMethod -> 100205 UStep -> 100206 VStep -> 100207 NURBSMode -> 100160 -------------------------------------------------------------------------------- setNURBSProperty :: NURBSObj -> NURBSProperty -> GLfloat -> IO () setNURBSProperty nurbsObj = gluNurbsProperty nurbsObj . marshalNURBSProperty foreign import CALLCONV safe "gluNurbsProperty" gluNurbsProperty :: NURBSObj -> GLenum -> GLfloat -> IO () -------------------------------------------------------------------------------- data NURBSMode = NURBSTessellator | NURBSRenderer deriving ( Eq, Ord, Show ) marshalNURBSMode :: NURBSMode -> GLfloat marshalNURBSMode x = case x of NURBSTessellator -> 100161 NURBSRenderer -> 100162 setNURBSMode :: NURBSObj -> NURBSMode -> IO () setNURBSMode nurbsObj = setNURBSProperty nurbsObj NURBSMode . marshalNURBSMode -------------------------------------------------------------------------------- setNURBSCulling :: NURBSObj -> Capability -> IO () setNURBSCulling nurbsObj = setNURBSProperty nurbsObj Culling . fromIntegral . marshalCapability -------------------------------------------------------------------------------- data SamplingMethod' = PathLength' | ParametricError' | DomainDistance' | ObjectPathLength' | ObjectParametricError' marshalSamplingMethod' :: SamplingMethod' -> GLfloat marshalSamplingMethod' x = case x of PathLength' -> 100215 ParametricError' -> 100216 DomainDistance' -> 100217 ObjectPathLength' -> 100209 ObjectParametricError' -> 100208 setSamplingMethod' :: NURBSObj -> SamplingMethod' -> IO () setSamplingMethod' nurbsObj = setNURBSProperty nurbsObj SamplingMethod . marshalSamplingMethod' -------------------------------------------------------------------------------- data SamplingMethod = PathLength GLfloat | ParametricError GLfloat | DomainDistance GLfloat GLfloat | ObjectPathLength GLfloat | ObjectParametricError GLfloat deriving ( Eq, Ord, Show ) setSamplingMethod :: NURBSObj -> SamplingMethod -> IO () setSamplingMethod nurbsObj x = case x of PathLength s -> do setNURBSProperty nurbsObj SamplingTolerance s setSamplingMethod' nurbsObj PathLength' ParametricError p -> do setNURBSProperty nurbsObj ParametricTolerance p setSamplingMethod' nurbsObj ParametricError' DomainDistance u v -> do setNURBSProperty nurbsObj UStep u setNURBSProperty nurbsObj VStep v setSamplingMethod' nurbsObj DomainDistance' ObjectPathLength s -> do setNURBSProperty nurbsObj SamplingTolerance s setSamplingMethod' nurbsObj ObjectPathLength' ObjectParametricError p -> do setNURBSProperty nurbsObj ParametricTolerance p setSamplingMethod' nurbsObj ObjectParametricError' -------------------------------------------------------------------------------- setAutoLoadMatrix :: NURBSObj -> Bool -> IO () setAutoLoadMatrix nurbsObj = setNURBSProperty nurbsObj AutoLoadMatrix . marshalGLboolean loadSamplingMatrices :: (Matrix m1, Matrix m2) => NURBSObj -> Maybe (m1 GLfloat, m2 GLfloat, (Position, Size)) -> IO () loadSamplingMatrices nurbsObj = maybe (setAutoLoadMatrix nurbsObj True) (\(mv, proj, (Position x y, Size w h)) -> do withMatrixColumnMajor mv $ \mvBuf -> withMatrixColumnMajor proj $ \projBuf -> withArray [x, y, w, h] $ \viewportBuf -> gluLoadSamplingMatrices nurbsObj mvBuf projBuf viewportBuf setAutoLoadMatrix nurbsObj False) withMatrixColumnMajor :: (Matrix m, MatrixComponent c) => m c -> (Ptr c -> IO a) -> IO a withMatrixColumnMajor mat act = withMatrix mat $ \order p -> if order == ColumnMajor then act p else do elems <- mapM (peekElemOff p) [ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 ] withArray elems act foreign import CALLCONV safe "gluLoadSamplingMatrices" gluLoadSamplingMatrices :: NURBSObj -> Ptr GLfloat -> Ptr GLfloat -> Ptr GLint -> IO () -------------------------------------------------------------------------------- data DisplayMode' = Fill' | OutlinePolygon | OutlinePatch deriving ( Eq, Ord, Show ) marshalDisplayMode' :: DisplayMode' -> GLfloat marshalDisplayMode' x = case x of Fill' -> 100012 OutlinePolygon -> 100240 OutlinePatch -> 100241 setDisplayMode' :: NURBSObj -> DisplayMode' -> IO () setDisplayMode' nurbsObj = setNURBSProperty nurbsObj DisplayMode' . marshalDisplayMode'