{-# LANGUAGE DataKinds, FlexibleContexts, ConstraintKinds, TypeOperators, TypeFamilies #-} {-| Simplified 3D graphics system. -} module FWGL.Graphics.D3 ( -- * Elements Element, cube, -- ** Geometry Geometry, Geometry3, geom, mkGeometry3, -- * Textures module FWGL.Graphics.Color, Texture, textureURL, textureFile, C.colorTex, mkTexture, -- * Transformations V3(..), pos, rotX, rotY, rotZ, rotAA, scale, scaleV, transform, -- * Layers Layer, -- ** Element layers elements, view, -- ** Object layers layer, layerPrg, program, -- ** Sublayers C.subLayer, -- * Custom 3D objects Object, object, object1, (C.~~), -- ** Globals C.global, C.globalTexture, C.globalTexSize, viewObject, DefaultUniforms3D, Texture2(..), Transform3(..), View3(..), -- * 3D matrices V4(..), M4(..), mat4, mul4, -- ** View matrices perspectiveMat4, cameraMat4, -- ** Transformation matrices idMat4, transMat4, rotXMat4, rotYMat4, rotZMat4, rotAAMat4, scaleMat4 ) where import Control.Applicative import FWGL.Backend hiding (Texture, Program) import FWGL.Geometry import qualified FWGL.Graphics.Custom as C import FWGL.Graphics.Color import FWGL.Graphics.Draw import FWGL.Graphics.Shapes import FWGL.Graphics.Types import FWGL.Internal.TList import FWGL.Shader.Default3D (Texture2, Transform3, View3) import FWGL.Shader.Program hiding (program) import FWGL.Graphics.Texture import FWGL.Vector -- | A 3D object with a 'Texture' and a transformation. data Element = Element Texture (Draw M4) (Geometry Geometry3) -- | A cube with a specified 'Texture'. cube :: GLES => Texture -> Element cube t = Element t (return idMat4) cubeGeometry -- | An element with a specified 'Geometry' and 'Texture'. geom :: Texture -> Geometry Geometry3 -> Element geom t = Element t $ return idMat4 -- | Create a graphical 'Object' from a list of 'Element's and a view matrix. object :: BackendIO => M4 -> [Element] -> Object DefaultUniforms3D Geometry3 object m = viewObject m . foldl acc ObjectEmpty where acc o e = o C.~~ object1 e -- | Create a graphical 'Object' from a single 'Element'. This lets you set your -- own globals individually. If the shader uses the view matrix 'View3' (e.g. -- the default 3D shader), you have to set it with 'viewObject'. object1 :: BackendIO => Element -> Object '[Transform3, Texture2] Geometry3 object1 (Element t m g) = C.globalDraw (undefined :: Transform3) m $ C.globalTexture (undefined :: Texture2) t $ C.static g -- | Create a standard 'Layer' from a list of 'Element's. elements :: BackendIO => [Element] -> Layer elements = layer . object idMat4 -- | Create a 'Layer' from a view matrix and a list of 'Element's. view :: BackendIO => M4 -> [Element] -> Layer view m = layer . object m -- | Set the value of the view matrix of a 3D 'Object'. viewObject :: BackendIO => M4 -> Object gs Geometry3 -> Object (View3 ': gs) Geometry3 viewObject = C.global (undefined :: View3) -- | Create a 'Layer' from a 3D 'Object', using the default shader. layer :: BackendIO => Object DefaultUniforms3D Geometry3 -> Layer layer = layerPrg defaultProgram3D -- | Create a 'Layer' from a 3D 'Object', using a custom shader. layerPrg :: (BackendIO, Subset og pg) => Program pg Geometry3 -> Object og Geometry3 -> Layer layerPrg = C.layer -- | Translate an 'Element'. pos :: V3 -> Element -> Element pos v = transform $ transMat4 v -- | Rotate an 'Element' around the X axis. rotX :: Float -> Element -> Element rotX a = transform $ rotXMat4 a -- | Rotate an 'Element' around the X axis. rotY :: Float -> Element -> Element rotY a = transform $ rotYMat4 a -- | Rotate an 'Element' around the X axis. rotZ :: Float -> Element -> Element rotZ a = transform $ rotZMat4 a -- | Rotate an 'Element' around an axis and an angle. rotAA :: V3 -> Float -> Element -> Element rotAA ax ag = transform $ rotAAMat4 ax ag -- | Scale an 'Element'. scale :: Float -> Element -> Element scale f = transform $ scaleMat4 (V3 f f f) -- | Scale an 'Element' in three dimensions. scaleV :: V3 -> Element -> Element scaleV v = transform $ scaleMat4 v -- | Transform an 'Element'. transform :: M4 -> Element -> Element transform m' (Element t m g) = Element t (mul4 <$> m <*> pure m') g