graphics-formats-collada (empty) → 0.1.0
raw patch · 7 files changed
+691/−0 lines, 7 filesdep +OpenGLdep +basedep +bitmap-openglsetup-changed
Dependencies added: OpenGL, base, bitmap-opengl, containers, ghc-prim, hxt, stb-image, transformers
Files
- Graphics/Formats/Collada.hs +34/−0
- Graphics/Formats/Collada/Objects.hs +251/−0
- Graphics/Formats/Collada/Render.hs +227/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- graphics-formats-collada.cabal +74/−0
- sample.hs +73/−0
+ Graphics/Formats/Collada.hs view
@@ -0,0 +1,34 @@+module Graphics.Formats.Collada + ( Config(..), load, defaultConfig, pathTextureLoader )+where++import qualified Graphics.Rendering.OpenGL.GL as GL+import Graphics.Formats.Collada.Objects+import Graphics.Formats.Collada.Render+import qualified Codec.Image.STB as Image+import qualified Data.Bitmap.OpenGL as Bitmap++data Config = Config {+ textureLoader :: String -> IO GL.TextureObject+}++load :: Config -> String -> IO (IO ())+load config contents = do+ case parseCollada contents of+ Nothing -> fail "Parse error"+ Just (mainid, dict) -> compile dict (textureLoader config) mainid++defaultConfig :: Config+defaultConfig = Config {+ textureLoader = pathTextureLoader "."+}++-- | Takes a prefix and returns a texture loader that prepends the prefix to the path+-- and loads from disk.+pathTextureLoader :: String -> String -> IO GL.TextureObject+pathTextureLoader prefix path = do+ let loc = prefix ++ "/" ++ path+ e <- Image.loadImage loc+ case e of+ Left err -> fail $ "Couldn't load " ++ loc ++ ": " ++ err+ Right bmp -> Bitmap.makeSimpleBitmapTexture bmp
+ Graphics/Formats/Collada/Objects.hs view
@@ -0,0 +1,251 @@+module Graphics.Formats.Collada.Objects+ ( Dict, ID+ , Object(..), Matrix(..)+ , Accessor(..), Input(..), InputSemantic(..), Primitive(..)+ , Mesh(..), Parameter(..), Technique(..)+ , ColorOrTexture(..), Node(..), NodeRef(..), NodeInstance(..)+ , MaterialBinding(..), parseCollada+ )+where++import Prelude hiding ((.), id)+import qualified Text.XML.HXT.Arrow as X+import qualified Text.XML.HXT.Arrow.ParserInterface as X+import qualified Control.Arrow.ListArrow as LA+import qualified Graphics.Rendering.OpenGL.GL as GL+import qualified Data.Map as Map+import Data.Maybe (listToMaybe)+import Control.Category+import Control.Arrow+import Foreign.Ptr+import Foreign.Marshal.Array+import Data.List++type Dict = Map.Map ID Object+type ID = String++data Object+ = OVisualScene [NodeRef]+ | OFloatArray [GL.GLfloat]+ | OSource Accessor+ | OVertices [Input]+ | OGeometry Mesh+ | OImage FilePath+ | OParam Parameter+ | OEffect Technique+ | OMaterial ID -- instance_effect+ | ONode Node+ deriving Show++data Matrix+ = Matrix [GL.GLfloat]+ deriving Show++identityMatrix :: Matrix+identityMatrix = Matrix [ 1, 0, 0, 0+ , 0, 1, 0, 0+ , 0, 0, 1, 0+ , 0, 0, 0, 1 ]++data Accessor+ = Accessor ID Int Int Int Int -- array components count stride offset+ deriving Show++data Input+ = Input Int InputSemantic ID -- offset semantic source+ deriving Show++data InputSemantic+ = SemPosition+ | SemNormal+ | SemVertex+ | SemTexCoord+ deriving (Eq,Show)++data Primitive+ = PrimTriangles String [Input] [Int] -- material inputs indices+ deriving Show++data Mesh = Mesh [Primitive]+ deriving Show++data Parameter+ = ParamSurface2D ID+ | ParamSampler2D ID+ deriving Show++data Technique+ = TechLambert ColorOrTexture -- diffuse+ | TechConstant ColorOrTexture GL.GLfloat -- transparent transparency+ deriving Show++data ColorOrTexture+ = COTColor GL.GLfloat GL.GLfloat GL.GLfloat GL.GLfloat+ | COTTexture ID String -- source texcoord+ deriving Show++data Node+ = Node Matrix [NodeInstance]+ deriving Show++data NodeRef+ = NRNode Node+ | NRInstance ID+ deriving Show++data NodeInstance+ = NINode NodeRef+ | NIGeometry ID [MaterialBinding]+ deriving Show++data MaterialBinding+ = MaterialBinding String ID String String -- symbol target semantic input_semantic+ deriving Show++parseCollada :: String -> Maybe (ID, Dict)+parseCollada = listToMaybe . LA.runLA (mainA <<< X.parseXmlDoc <<^ (\x -> ("<stdin>", x)))++mainA :: LA.LA X.XmlTree (ID, Dict)+mainA = mainScene &&& (Map.unions .< X.multi objects) <<< X.hasName "COLLADA"++infixr 1 .<+(.<) = flip (X.>.)++refAttr :: String -> LA.LA X.XmlTree ID+refAttr name = stripHash ^<< X.getAttrValue0 name+ where+ stripHash ('#':x) = x+ stripHash x = x++objects = asum [ float_array, source, vertices, geometry, image, newparam, effect, material, node, visual_scene ]++mainScene :: LA.LA X.XmlTree ID+mainScene = refAttr "url" <<< child (X.hasName "instance_visual_scene") <<< child (X.hasName "scene")++asum = foldr1 (X.<+>)++objectWithIDAttr :: String -> String -> LA.LA X.XmlTree Object -> LA.LA X.XmlTree Dict+objectWithIDAttr attr name proc = uncurry Map.singleton ^<< (X.getAttrValue0 attr &&& proc) . X.hasName name++object :: String -> LA.LA X.XmlTree Object -> LA.LA X.XmlTree Dict+object = objectWithIDAttr "id"++float_array :: LA.LA X.XmlTree Dict+float_array = object "float_array" $ toArray ^<< X.getText . X.getChildren+ where+ toArray = OFloatArray . map read . words++accessor :: LA.LA X.XmlTree Accessor+accessor = massage ^<< (length .< child (X.hasName "param")) &&& refAttr "source" &&& X.getAttrValue0 "count" &&& X.getAttrValue "stride" &&& X.getAttrValue "offset" <<< X.hasName "accessor"+ where+ massage (len, (source, (count, (stride, offset)))) = Accessor source len (read count) (readDef len stride) (readDef 0 offset)++readDef d "" = d+readDef _ s = read s++child n = n <<< X.getChildren++source :: LA.LA X.XmlTree Dict+source = object "source" $ OSource ^<< accessor <<< X.getChildren <<< child (X.hasName "technique_common")++input :: LA.LA X.XmlTree Input+input = massage ^<< X.getAttrValue "offset" &&& X.getAttrValue0 "semantic" &&& refAttr "source" <<< X.hasName "input"+ where+ massage (offset, (semantic, source)) = Input (readDef (-1) offset) (massageSemantic semantic) source -- -1 hax!! See vertices where this is fixedup.+ massageSemantic "POSITION" = SemPosition+ massageSemantic "NORMAL" = SemNormal+ massageSemantic "VERTEX" = SemVertex+ massageSemantic "TEXCOORD" = SemTexCoord+ massageSemantic s = error $ "Unknown semantic: " ++ s++vertices :: LA.LA X.XmlTree Dict+vertices = object "vertices" $ OVertices . fixups .< child input+ where+ fixups = zipWith fixup [0..]+ fixup n (Input z sem source) | z == -1 = Input n sem source+ | otherwise = Input z sem source+++triangles :: LA.LA X.XmlTree Primitive+triangles = massage ^<< X.getAttrValue "material" &&& procBody <<< X.hasName "triangles"+ where+ procBody = (id .< child input) &&& (map read . words ^<< child X.getText <<< child (X.hasName "p"))+ massage (material, (inputs, p)) = PrimTriangles material inputs p++mesh :: LA.LA X.XmlTree Mesh+mesh = (Mesh .< child primitives) <<< X.hasName "mesh"+ where+ primitives = asum [ triangles ]++geometry :: LA.LA X.XmlTree Dict+geometry = object "geometry" $ OGeometry ^<< child mesh++image :: LA.LA X.XmlTree Dict+image = object "image" $ OImage ^<< child X.getText <<< child (X.hasName "init_from")++newparam :: LA.LA X.XmlTree Dict+newparam = objectWithIDAttr "sid" "newparam" $ OParam ^<< asum [surface, sampler2D] <<< X.getChildren+ where+ surface = ParamSurface2D ^<< child X.getText <<< child (X.hasName "init_from") <<< X.hasAttrValue "type" (== "2D") <<< X.hasName "surface"+ sampler2D = ParamSampler2D ^<< child X.getText <<< child (X.hasName "source") <<< X.hasName "sampler2D"++colorOrTexture :: LA.LA X.XmlTree ColorOrTexture+colorOrTexture = texture X.<+> color+ where+ texture = uncurry COTTexture ^<< X.getAttrValue0 "texture" &&& X.getAttrValue0 "texcoord" <<< X.hasName "texture"+ color = colorify . map read . words ^<< child X.getText <<< X.hasName "color"+ colorify [r,g,b,a] = COTColor r g b a+ colorify s = error "Malformed color"++lambert :: LA.LA X.XmlTree Technique+lambert = TechLambert ^<< child colorOrTexture <<< child (X.hasName "diffuse") <<< X.hasName "lambert"++constant :: LA.LA X.XmlTree Technique+constant = uncurry TechConstant ^<< (child colorOrTexture <<< child (X.hasName "transparent")) &&& (read ^<< child (X.getText) <<< child (X.hasName "float") <<< child (X.hasName "transparency")) <<< X.hasName "constant"++technique :: LA.LA X.XmlTree Technique+technique = asum [lambert, constant] <<< X.getChildren <<< X.hasName "technique"++effect :: LA.LA X.XmlTree Dict+effect = object "effect" $ OEffect ^<< child technique <<< child (X.hasName "profile_COMMON")++material :: LA.LA X.XmlTree Dict+material = object "material" $ OMaterial ^<< refAttr "url" <<< child (X.hasName "instance_effect")++nodeRef :: LA.LA X.XmlTree NodeRef+nodeRef = asum [inline, instance_node] + where+ inline = (arr NRInstance ||| (NRNode ^<< rawNode)) <<< switch <<< X.hasName "node"+ switch = convid ^<< X.getAttrValue "id" &&& id+ convid ("", xml) = Right xml+ convid (x, _) = Left x++instance_node :: LA.LA X.XmlTree NodeRef+instance_node = NRInstance ^<< refAttr "url" <<< X.hasName "instance_node"++nodeInstance :: LA.LA X.XmlTree NodeInstance+nodeInstance = asum [NINode ^<< nodeRef, instance_geometry]++instance_geometry :: LA.LA X.XmlTree NodeInstance+instance_geometry = uncurry NIGeometry ^<< refAttr "url" &&& bindings <<< X.hasName "instance_geometry"+ where+ bindings = id .< (child instance_material <<< child (X.hasName "technique_common") <<< child (X.hasName "bind_material"))++matrix :: LA.LA X.XmlTree Matrix+matrix = Matrix . map read . words ^<< child X.getText <<< X.hasName "matrix"++rawNode :: LA.LA X.XmlTree Node+rawNode = uncurry Node ^<< (child matrix `X.withDefault` identityMatrix) &&& (id .< child nodeInstance) <<< X.hasName "node"++node :: LA.LA X.XmlTree Dict+node = object "node" $ ONode ^<< rawNode++instance_material :: LA.LA X.XmlTree MaterialBinding+instance_material = conv ^<< myAttrs &&& bindAttrs <<< X.hasName "instance_material"+ where+ conv ((symbol, target), (semantic, input_semantic)) = MaterialBinding symbol target semantic input_semantic+ myAttrs = X.getAttrValue0 "symbol" &&& refAttr "target"+ bindAttrs = X.getAttrValue0 "semantic" &&& X.getAttrValue0 "input_semantic" <<< child (X.hasName "bind_vertex_input")++visual_scene :: LA.LA X.XmlTree Dict+visual_scene = object "visual_scene" $ OVisualScene ^<< id .< child nodeRef
+ Graphics/Formats/Collada/Render.hs view
@@ -0,0 +1,227 @@+{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, PatternGuards, RecursiveDo #-}++module Graphics.Formats.Collada.Render + ( compile )+where++import qualified Graphics.Rendering.OpenGL.GL as GL+import qualified Graphics.Formats.Collada.Objects as O+import qualified Data.Map as Map+import qualified Foreign.Marshal.Array as Array+import qualified Foreign.Storable as Storable+import Foreign.Ptr (Ptr)+import Data.Monoid (Monoid(..))+import Control.Arrow (second)+import Control.Applicative+import Control.Monad.Trans.Reader+import Control.Monad.Trans.State+import Control.Monad.Trans+import Control.Monad (when, forM_, liftM2, liftM3)+import GHC.Prim (Any)+import Unsafe.Coerce (unsafeCoerce)++newtype DrawM a = DrawM { runDrawM :: IO a }+ deriving (Functor, Applicative, Monad, MonadIO)++wrapDrawM :: (IO a -> IO a) -> (DrawM a -> DrawM a)+wrapDrawM f = DrawM . f . runDrawM++type Bindings = Map.Map String (DrawM ())++type Cache = Map.Map O.ID Any++data CompileEnv = CompileEnv {+ envDict :: O.Dict,+ envBindings :: Bindings,+ envLoader :: String -> IO GL.TextureObject+}++newtype CompileM a = CompileM { runCompileM :: ReaderT CompileEnv (StateT Cache IO) a }+ deriving (Functor, Applicative, Monad, MonadIO)++cached :: (O.Object -> CompileM a) -> (O.ID -> CompileM a)+cached f ident = CompileM $ do+ cache <- lift get+ case Map.lookup ident cache of+ Nothing -> mdo+ lift . modify . Map.insert ident . unsafeCoerce $ result+ result <- runCompileM $ f =<< findSymbol ident+ return result+ Just result -> return (unsafeCoerce result)++lookup' :: (Ord k, Show k) => k -> Map.Map k a -> a+lookup' k mp | Just x <- Map.lookup k mp = x+ | otherwise = error $ "Couldn't find object: " ++ show k++findSymbol :: O.ID -> CompileM O.Object+findSymbol sym = CompileM $ asks (lookup' sym . envDict)++findBinding :: String -> CompileM (DrawM ())+findBinding sym = CompileM $ asks (lookup' sym . envBindings)++addBindings :: Bindings -> CompileM a -> CompileM a+addBindings bindings = CompileM . local addBinding . runCompileM+ where+ addBinding env = env { envBindings = envBindings env `Map.union` bindings }++loadTexture :: String -> CompileM GL.TextureObject+loadTexture s = CompileM $ liftIO . ($ s) =<< asks envLoader++compile :: O.Dict -> (String -> IO (GL.TextureObject)) -> O.ID -> IO (IO ())+compile dict loader mainid = do+ runDrawM <$> evalStateT (runReaderT (runCompileM (compileVisualScene mainid)) initEnv) Map.empty+ where+ initEnv = CompileEnv { envDict = dict, envBindings = Map.empty, envLoader = loader }++compileArray :: O.ID -> CompileM (Ptr GL.GLfloat)+compileArray = cached go+ where+ go (O.OFloatArray xs) = liftIO $ Array.newArray xs+ go _ = error "Not an array"++floatSize = Storable.sizeOf (undefined :: GL.GLfloat)++compileAccessor :: O.Accessor -> CompileM (GL.VertexArrayDescriptor GL.GLfloat)+compileAccessor (O.Accessor arrayid components count stride offset) = do+ ptr <- compileArray arrayid+ let ptr' = Array.advancePtr ptr offset+ return $ GL.VertexArrayDescriptor (fromIntegral components) GL.Float byteStride ptr'+ where+ byteStride = fromIntegral $ Storable.sizeOf floatSize * (stride - components)+++indexDescriptor :: GL.VertexArrayDescriptor GL.GLfloat -> Int -> Int -> IO GL.GLfloat+indexDescriptor (GL.VertexArrayDescriptor components _ stride ptr) = \ix off ->+ Storable.peekByteOff ptr (step * ix + floatSize * off)+ where+ step = fromIntegral stride + floatSize * fromIntegral components++data CompiledInput = CompiledInput { ciSetupArrays :: DrawM (), ciIndex :: Int -> DrawM () }++instance Monoid CompiledInput where+ mempty = CompiledInput (return ()) (const (return ()))+ mappend a b = CompiledInput { ciSetupArrays = ciSetupArrays a >> ciSetupArrays b+ , ciIndex = \z -> ciIndex a z >> ciIndex b z + }++compileInput :: O.Input -> CompileM CompiledInput+compileInput (O.Input _ semantic source) = do+ sym <- findSymbol source+ case sym of+ O.OVertices inputs -> mconcat <$> mapM compileInput inputs+ O.OSource acc -> do+ descriptor <- compileAccessor acc+ let sem = convertSem semantic+ let setupArrays = liftIO $ do+ GL.arrayPointer sem GL.$= descriptor+ GL.clientState sem GL.$= GL.Enabled+ let ind = indexDescriptor descriptor + let index = case sem of+ GL.VertexArray -> \z -> liftIO $ GL.vertex =<< liftM3 GL.Vertex3 (ind z 0) (ind z 1) (ind z 2)+ GL.NormalArray -> \z -> liftIO $ GL.normal =<< liftM3 GL.Normal3 (ind z 0) (ind z 1) (ind z 2)+ GL.TextureCoordArray -> \z -> liftIO $ GL.texCoord =<< liftM2 GL.TexCoord2 (ind z 0) (ind z 1)+ x -> error $ "Don't know how to index a " ++ show x+ return $ CompiledInput setupArrays index+ + + x -> error $ "Input can't use " ++ show x ++ " as a source"+ where+ convertSem O.SemPosition = GL.VertexArray+ convertSem O.SemNormal = GL.NormalArray+ convertSem O.SemTexCoord = GL.TextureCoordArray+ conversion sem = error $ "Unknown semantic: " ++ show sem++compilePrimitive :: O.Primitive -> CompileM (DrawM ())+compilePrimitive (O.PrimTriangles material inputs indices) = do+ mat <- findBinding material+ case inputs of+ [inp] -> do -- fast single-input+ compiled <- compileInput inp + liftIO $ do+ let numindices = fromIntegral (length indices)+ ixarray :: Ptr GL.GLuint <- liftIO . Array.newArray $ map fromIntegral indices+ return . wrapDrawM (GL.preservingClientAttrib [GL.AllClientAttributes]) $ do+ mat+ ciSetupArrays compiled+ liftIO $ GL.drawElements GL.Triangles numindices GL.UnsignedInt ixarray+ + inps -> do -- slow multi-input (should copy to a new vertex array instead)+ compiled <- Map.fromListWith mappend <$> mapM (\inp@(O.Input i _ _) -> ((,) i) <$> compileInput inp) inps+ let (maxE,example) = Map.findMax compiled+ return . (mat >>) . wrapDrawM (GL.renderPrimitive GL.Triangles) . forM_ (zip (cycle [0..maxE]) indices) $ \(inpix,ix) -> do+ ciIndex (Map.findWithDefault mempty inpix compiled) ix+ ++compileGeometry :: O.ID -> CompileM (DrawM ())+compileGeometry = cached go+ where+ go (O.OGeometry (O.Mesh prims)) = do+ cprims <- mapM compilePrimitive prims+ return $ sequence_ cprims+ go _ = error "Not a geometry"++compileNode :: O.Node -> CompileM (DrawM ())+compileNode (O.Node (O.Matrix matrix) instances) = do+ mat :: GL.GLmatrix GL.GLfloat <- liftIO $ GL.newMatrix GL.RowMajor matrix + instances' <- mapM compileNodeInstance instances+ return . wrapDrawM GL.preservingMatrix $ liftIO (GL.multMatrix mat) >> sequence_ instances'++compileNodeInstance :: O.NodeInstance -> CompileM (DrawM ())+compileNodeInstance (O.NINode ref) = compileNodeRef ref+compileNodeInstance (O.NIGeometry geom materials) = do+ materials' <- Map.unions <$> mapM compileMaterialBinding materials+ addBindings materials' $ compileGeometry geom++compileNodeRef :: O.NodeRef -> CompileM (DrawM ())+compileNodeRef (O.NRNode node) = compileNode node+compileNodeRef (O.NRInstance nodeid) = compileNodeObject nodeid++compileNodeObject :: O.ID -> CompileM (DrawM ())+compileNodeObject = cached go+ where+ go (O.ONode node) = compileNode node+ go _ = error "Not a node"++compileVisualScene :: O.ID -> CompileM (DrawM ())+compileVisualScene = cached go+ where+ go (O.OVisualScene noderefs) = do+ sequence_ <$> mapM compileNodeRef noderefs+ go _ = error "Not a visual scene"++compileImage :: O.ID -> CompileM GL.TextureObject+compileImage = cached go+ where+ go (O.OImage path) = loadTexture path+ go _ = error "not an image"++compileEffect :: O.ID -> CompileM (DrawM ())+compileEffect = cached go+ where+ go (O.OEffect (O.TechLambert cot)) = lambert cot+ go (O.OEffect (O.TechConstant cot alpha)) = go (O.OEffect (O.TechLambert cot)) -- XXX Hax+ go (O.OMaterial ident) = compileEffect ident+ go x = error $ "Not an effect: " ++ show x+ + lambert (O.COTColor r g b a) = return . liftIO $ do+ GL.texture GL.Texture2D GL.$= GL.Disabled+ GL.colorMaterial GL.$= Just (GL.Front, GL.Diffuse)+ GL.color $ GL.Color4 r g b a+ lambert (O.COTTexture source _texcoord) = do+ texobj <- compileParameter source+ return . liftIO $ do+ GL.colorMaterial GL.$= Just (GL.Front, GL.Diffuse)+ GL.texture GL.Texture2D GL.$= GL.Enabled+ GL.textureBinding GL.Texture2D GL.$= Just texobj++compileParameter :: O.ID -> CompileM GL.TextureObject+compileParameter = cached go+ where+ go (O.OParam (O.ParamSurface2D img)) = compileImage img+ go (O.OParam (O.ParamSampler2D surf)) = compileParameter surf+ go _ = error "Not a param"++compileMaterialBinding :: O.MaterialBinding -> CompileM Bindings+compileMaterialBinding (O.MaterialBinding sym target _ _) = do+ targetE <- compileEffect target+ return $ Map.singleton sym targetE
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2010, Luke Palmer++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Luke Palmer nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ graphics-formats-collada.cabal view
@@ -0,0 +1,74 @@+-- graphics-formats-collada.cabal auto-generated by cabal init. For+-- additional options, see+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.+-- The name of the package.+Name: graphics-formats-collada++-- The package version. See the Haskell package versioning policy+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for+-- standards guiding when and how versions should be incremented.+Version: 0.1.0++-- A short (one-line) description of the package.+Synopsis: Load 3D geometry in the COLLADA format++-- A longer description of the package.+Description:+ Early in development. Should be able to load anything that Google SketchUp+ produces -- other than that, all bets are off.++-- URL for the project homepage or repository.+Homepage: http://github.com/luqui/collada++-- The license under which the package is released.+License: BSD3++-- The file containing the license text.+License-file: LICENSE++-- The package author(s).+Author: Luke Palmer++-- An email address to which users can send suggestions, bug reports,+-- and patches.+Maintainer: lrpalmer@gmail.com++-- A copyright notice.+-- Copyright: ++Category: Graphics++Build-type: Simple++-- Extra files to be distributed with the package, such as examples or+-- a README.+Extra-source-files: sample.hs++-- Constraint on the version of Cabal needed to build this package.+Cabal-version: >=1.6+++Library+ -- Modules exported by the library.+ Exposed-modules: + Graphics.Formats.Collada+ Graphics.Formats.Collada.Objects+ Graphics.Formats.Collada.Render+ + -- Packages needed in order to build this package.+ Build-depends: + base == 4.*,+ containers,+ transformers == 0.1.*,+ ghc-prim == 0.1.*,+ hxt == 8.5.*,+ OpenGL == 2.4.*, + stb-image == 0.2.*,+ bitmap-opengl == 0.0.*++ -- Modules not exported by this package.+ -- Other-modules: + + -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.+ -- Build-tools: +
+ sample.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE TypeFamilies #-}++import qualified Graphics.Formats.Collada as Collada+import qualified Graphics.UI.GLUT as GLUT+import qualified Graphics.Rendering.OpenGL.GL as GL+import qualified Graphics.Rendering.OpenGL.GLU as GLU+import System.IO+import Control.Applicative+import Data.VectorSpace+import Data.IORef++instance AdditiveGroup GL.GLdouble where+ zeroV = 0+ (^+^) = (+)+ negateV = negate++instance VectorSpace GL.GLdouble where+ type Scalar GL.GLdouble = GL.GLdouble+ (*^) = (*)++instance InnerSpace GL.GLdouble where+ (<.>) = (*)++main = do+ hSetBuffering stdout NoBuffering++ GLUT.initialDisplayMode GL.$= [GLUT.RGBAMode, GLUT.DoubleBuffered, GLUT.WithDepthBuffer]++ GLUT.getArgsAndInitialize+ GLUT.createWindow "Hello!"++ putStrLn "Loading"+ action <- Collada.load Collada.defaultConfig =<< getContents+ putStrLn "Done"++ GL.lighting GL.$= GL.Enabled+ GL.light (GL.Light 0) GL.$= GL.Enabled+ GL.position (GL.Light 0) GL.$= GL.Vertex4 0 0 0 1+ GL.depthFunc GL.$= Nothing+ GL.depthFunc GL.$= Just GL.Lequal+ GL.depthMask GL.$= GL.Enabled++ GLUT.displayCallback GLUT.$= (do+ GL.clearColor GL.$= GL.Color4 0 0 0 0+ GL.clear [GL.ColorBuffer, GL.DepthBuffer]+ GL.preservingMatrix $ do+ GL.matrixMode GL.$= GL.Projection+ GL.loadIdentity+ GLU.perspective 45 1 1 10000+ GL.matrixMode GL.$= GL.Modelview 0+ GL.loadIdentity+ GLU.lookAt (uncurry3 GL.Vertex3 eye) (uncurry3 GL.Vertex3 object) (uncurry3 GL.Vector3 up)+ GL.renderPrimitive GL.Lines $ do+ vertex (-200) 0 0+ vertex 200 0 0+ vertex 0 (-200) 0+ vertex 0 200 0+ vertex 0 0 (-200)+ vertex 0 0 200+ action+ GLUT.swapBuffers)+ GLUT.mainLoop++ where+ eye = (200, 200, 200)+ object = (0, 0, 0)+ up = normalized $ (object ^-^ eye) `cross` ((object ^-^ eye) `cross` (0,0,-1))+ cross (bx,by,bz) (cx,cy,cz) = (by*cz - cy*bz, bz*cx - bx*cz, bx*cy - by*cx)++ uncurry3 f (x,y,z) = f x y z++ vertex :: GL.GLfloat -> GL.GLfloat -> GL.GLfloat -> IO ()+ vertex x y z = GL.vertex $ GL.Vertex3 x y z