module Graphics.Gloss.Data.ViewPort ( ViewPort(..) , viewPortInit , applyViewPortToPicture , invertViewPort ) where import Graphics.Gloss.Data.Picture import qualified Graphics.Gloss.Data.Point.Arithmetic as Pt -- | The 'ViewPort' represents the global transformation applied to the displayed picture. -- When the user pans, zooms, or rotates the display then this changes the 'ViewPort'. data ViewPort = ViewPort { -- | Global translation. viewPortTranslate :: !(Float, Float) -- | Global rotation (in degrees). , viewPortRotate :: !Float -- | Global scaling (of both x and y coordinates). , viewPortScale :: !Float } -- | The initial state of the viewport. viewPortInit :: ViewPort viewPortInit = ViewPort { viewPortTranslate = (0, 0) , viewPortRotate = 0 , viewPortScale = 1 } -- | Translates, rotates, and scales an image according to the 'ViewPort'. applyViewPortToPicture :: ViewPort -> Picture -> Picture applyViewPortToPicture ViewPort { viewPortScale = vscale , viewPortTranslate = (transX, transY) , viewPortRotate = vrotate } = Scale vscale vscale . Rotate vrotate . Translate transX transY -- | Takes a point using screen coordinates, and uses the `ViewPort` to convert -- it to Picture coordinates. This is the inverse of `applyViewPortToPicture` -- for points. invertViewPort :: ViewPort -> Point -> Point invertViewPort ViewPort { viewPortScale = vscale , viewPortTranslate = vtrans , viewPortRotate = vrotate } pos = rotateV (degToRad vrotate) (mulSV (1 / vscale) pos) Pt.- vtrans -- | Convert degrees to radians degToRad :: Float -> Float degToRad d = d * pi / 180 {-# INLINE degToRad #-} -- | Multiply a vector by a scalar. mulSV :: Float -> Vector -> Vector mulSV s (x, y) = (s * x, s * y) {-# INLINE mulSV #-} -- | Rotate a vector by an angle (in radians). +ve angle is counter-clockwise. rotateV :: Float -> Vector -> Vector rotateV r (x, y) = ( x * cos r - y * sin r , x * sin r + y * cos r) {-# INLINE rotateV #-}