module RSAGL.Modeling.BakedModel (BakedSurface, bakeSurface, freeSurface, surfaceToOpenGL, tesselatedElementToOpenGL) where import Foreign import Graphics.Rendering.OpenGL.GL import RSAGL.Modeling.OpenGLPrimitives import RSAGL.Modeling.Tesselation hiding (tesselatedElementToOpenGL) import Control.Monad data BakedFragment = BakedFragment { baked_model_primitive_mode :: PrimitiveMode, baked_model_length :: GLsizei, baked_model_vertex_ptr :: Ptr (Vertex3 GLdouble), baked_model_normal_ptr :: Ptr (Normal3 GLdouble), baked_model_color_ptr :: Maybe (Ptr (Color4 GLdouble)) } data BakedSurface = BakedSurface { baked_model_action :: IO () -> IO (), baked_model_fragments :: [BakedFragment] } bakeFragment :: (OpenGLPrimitive a) => PrimitiveMode -> Bool -> [a] -> IO BakedFragment bakeFragment primitive_mode colors_on as = do let l = length as v <- newArray $ map getVertex as n <- newArray $ map getNormal as m_c <- case colors_on of False -> return Nothing True -> liftM Just $ newArray $ map getColor as return $ BakedFragment { baked_model_primitive_mode = primitive_mode, baked_model_length = fromInteger $ toInteger l, baked_model_vertex_ptr = v, baked_model_normal_ptr = n, baked_model_color_ptr = m_c } freeFragment :: BakedFragment -> IO () freeFragment baked_run = do free $ baked_model_vertex_ptr baked_run free $ baked_model_normal_ptr baked_run maybe (return ()) free $ baked_model_color_ptr baked_run fragmentToOpenGL :: BakedFragment -> IO () fragmentToOpenGL baked_fragment = do arrayPointer VertexArray $= VertexArrayDescriptor 3 Double 0 (baked_model_vertex_ptr baked_fragment) arrayPointer NormalArray $= VertexArrayDescriptor 3 Double 0 (baked_model_normal_ptr baked_fragment) flip (maybe $ return ()) (baked_model_color_ptr baked_fragment) $ \color_ptr -> arrayPointer ColorArray $= VertexArrayDescriptor 4 Double 0 color_ptr drawArrays (baked_model_primitive_mode baked_fragment) 0 (baked_model_length baked_fragment) bakeSurface :: (OpenGLPrimitive a) => (IO () -> IO ()) -> Bool -> [(PrimitiveMode,[a])] -> IO BakedSurface bakeSurface wrapperM colors_on fragment_data = do fragments <- mapM (\(primitive_mode,a) -> bakeFragment primitive_mode colors_on a) fragment_data return $ BakedSurface { baked_model_action = \actionM -> wrapperM $ do save_vertex_arrays <- get $ clientState VertexArray save_normal_arrays <- get $ clientState NormalArray save_color_arrays <- get $ clientState ColorArray clientState VertexArray $= Enabled clientState NormalArray $= Enabled clientState ColorArray $= if colors_on then Enabled else Disabled actionM clientState ColorArray $= save_color_arrays clientState NormalArray $= save_normal_arrays clientState VertexArray $= save_vertex_arrays, baked_model_fragments = fragments } freeSurface :: BakedSurface -> IO () freeSurface baked_surface = mapM_ freeFragment $ baked_model_fragments baked_surface surfaceToOpenGL :: BakedSurface -> IO () surfaceToOpenGL baked_surface = baked_model_action baked_surface $ mapM_ fragmentToOpenGL $ baked_model_fragments baked_surface tesselatedElementToOpenGL :: (OpenGLPrimitive a) => Bool -> TesselatedElement a -> IO () tesselatedElementToOpenGL colors_on tesselated_element = do fragment <- bakeSurface id colors_on $ [unmapTesselatedElement tesselated_element] surfaceToOpenGL fragment freeSurface fragment