{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-} -- | This module provides an implementation for simple resolution -- independent drawing and rendering. You can do the same stuff with -- the resolution independent compositor as with a regular one. -- -- One important difference is that the 'translateA' function as well -- as the standard drawing functions don't work with 'ResIndependent'. -- Instead there are replacement functions for these operations. -- -- This implementation finds the biggest square that fits into the -- dimensions of the rendering surface. The top left corner of this -- sqare is @V2 0 0@, the bottom right corner is @V2 1 1@. module SDL.Compositor.ResIndependent ( -- * Wrapping and unwrapping ResIndependent , fromRelativeCompositor -- * Drawing , rectangleR , filledRectangleR , lineR -- * Composition , RelativeSize (..) ) where import Linear.V2 import SDL.Compositor class RelativeSize c where -- | Translate a composition by a given resolution independent -- vector. translateR :: V2 Float -> c a -> c a -- | This function takes a rectangular area given as resolution -- independent coordinates and an object and constructs a -- compositing node from it that spans the given area. sizedR :: V2 Float -> a -> c a newtype ResIndependent c a = ResIndependent (V2 Int -> c a) deriving (Functor,Monoid) instance Compositor (c a) => Compositor (ResIndependent c a) where overC (ResIndependent fun1) (ResIndependent fun2) = ResIndependent $ \dims -> fun1 dims `overC` fun2 dims rotateC ang (ResIndependent fun) = ResIndependent $ \dims -> rotateC ang (fun dims) flipC flipping (ResIndependent fun) = ResIndependent $ \dims -> flipC flipping (fun dims) instance (AbsoluteSize c) => RelativeSize (ResIndependent c) where translateR coords (ResIndependent fun) = ResIndependent $ \dims -> translateA (scaleToFormat dims coords) (fun dims) sizedR texDims tex = ResIndependent $ \dims -> sizedA (scaleToFormat dims texDims) tex instance Manipulator (c a) => Manipulator (ResIndependent c a) where modulateAlphaM val (ResIndependent fun) = ResIndependent $ \dims -> modulateAlphaM val (fun dims) modulateRedM val (ResIndependent fun) = ResIndependent $ \dims -> modulateRedM val (fun dims) modulateGreenM val (ResIndependent fun) = ResIndependent $ \dims -> modulateGreenM val (fun dims) modulateBlueM val (ResIndependent fun) = ResIndependent $ \dims -> modulateBlueM val (fun dims) instance Blender (c a) => Blender (ResIndependent c a) where blendMode mode (ResIndependent fun) = ResIndependent $ \dims -> blendMode mode (fun dims) scaleToFormat :: V2 Int -> V2 Float -> V2 Int scaleToFormat (V2 w h) coords = round <$> scale * coords where scale = fromIntegral (min w h) shiftToFormat :: V2 Int -> V2 Int -> V2 Int shiftToFormat (V2 w h) (V2 x y) | w == h = V2 x y | w > h = let delta = (w - h) `div` 2 in V2 (x + delta) y | otherwise = let delta = (h - w) `div` 2 in V2 x (y + delta) -- | Convert a resolution independent compositor into a compositor for -- a fixed screen size by specifying the size of the screen. fromRelativeCompositor :: (Compositor (c a), AbsoluteSize c) => V2 Int -> ResIndependent c a -> c a fromRelativeCompositor dims (ResIndependent fun) = translateA (shiftToFormat dims 0) (fun dims) rectangleR :: (Drawer (c a)) => V2 Float -> Color -> ResIndependent c a rectangleR rectDims colors = ResIndependent $ \dims -> rectangleC (scaleToFormat dims rectDims) colors filledRectangleR :: (Drawer (c a)) => V2 Float -> Color -> ResIndependent c a filledRectangleR rectDims colors = ResIndependent $ \dims -> filledRectangleC (scaleToFormat dims rectDims) colors lineR :: (Drawer (c a)) => V2 Float -> Color -> ResIndependent c a lineR lineCoords colors = ResIndependent $ \dims -> lineC (scaleToFormat dims lineCoords) colors